1 /*
2 * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
3 * Copyright (c) 2022 Cypress Semiconductor Corporation (an Infineon
4 * company) or an affiliate of Cypress Semiconductor Corporation. All rights
5 * reserved.
6 *
7 * SPDX-License-Identifier: BSD-3-Clause
8 */
9
10 #include <stdbool.h>
11 #include <stddef.h>
12 #include <stdint.h>
13
14 #include "internal_status_code.h"
15 #include "region.h"
16 #include "region_defs.h"
17 #include "tfm_hal_multi_core.h"
18 #include "tfm_multi_core.h"
19 #include "tfm_arch.h"
20 #include "utilities.h"
21
22 #ifndef TFM_ISOLATION_LEVEL
23 #error TFM_ISOLATION_LEVEL is not defined!
24 #endif
25
tfm_get_mem_region_security_attr(const void * p,size_t s,struct security_attr_info_t * p_attr)26 void tfm_get_mem_region_security_attr(const void *p, size_t s,
27 struct security_attr_info_t *p_attr)
28 {
29 p_attr->is_valid = true;
30
31 if (check_address_range(p, s, NS_DATA_START,
32 NS_DATA_LIMIT) == SPM_SUCCESS) {
33 p_attr->is_secure = false;
34 return;
35 }
36
37 if (check_address_range(p, s, NS_CODE_START,
38 NS_CODE_LIMIT) == SPM_SUCCESS) {
39 p_attr->is_secure = false;
40 return;
41 }
42
43 if (check_address_range(p, s, S_DATA_START, S_DATA_LIMIT) == SPM_SUCCESS) {
44 p_attr->is_secure = true;
45 return;
46 }
47
48 if (check_address_range(p, s, S_CODE_START, S_CODE_LIMIT) == SPM_SUCCESS) {
49 p_attr->is_secure = true;
50 return;
51 }
52
53 p_attr->is_valid = false;
54 }
55
56 #if TFM_ISOLATION_LEVEL == 2
57 REGION_DECLARE(Image$$, TFM_UNPRIV_CODE_START, $$RO$$Base);
58 REGION_DECLARE(Image$$, TFM_UNPRIV_CODE_END, $$RO$$Limit);
59 #ifdef CONFIG_TFM_PARTITION_META
60 REGION_DECLARE(Image$$, TFM_SP_META_PTR, $$ZI$$Base);
61 REGION_DECLARE(Image$$, TFM_SP_META_PTR, $$ZI$$Limit);
62 #endif /* CONFIG_TFM_PARTITION_META */
63 REGION_DECLARE(Image$$, TFM_APP_CODE_START, $$Base);
64 REGION_DECLARE(Image$$, TFM_APP_CODE_END, $$Base);
65 REGION_DECLARE(Image$$, TFM_APP_RW_STACK_START, $$Base);
66 REGION_DECLARE(Image$$, TFM_APP_RW_STACK_END, $$Base);
67 #endif
68
tfm_get_secure_mem_region_attr(const void * p,size_t s,struct mem_attr_info_t * p_attr)69 void tfm_get_secure_mem_region_attr(const void *p, size_t s,
70 struct mem_attr_info_t *p_attr)
71 {
72 #if TFM_ISOLATION_LEVEL == 1
73 p_attr->is_mpu_enabled = false;
74 p_attr->is_valid = true;
75
76 if (check_address_range(p, s, S_DATA_START, S_DATA_LIMIT) == SPM_SUCCESS) {
77 p_attr->is_priv_rd_allow = true;
78 p_attr->is_priv_wr_allow = true;
79 p_attr->is_unpriv_rd_allow = true;
80 p_attr->is_unpriv_wr_allow = true;
81 p_attr->is_xn = true;
82 return;
83 }
84
85 if (check_address_range(p, s, S_CODE_START, S_CODE_LIMIT) == SPM_SUCCESS) {
86 p_attr->is_priv_rd_allow = true;
87 p_attr->is_priv_wr_allow = false;
88 p_attr->is_unpriv_rd_allow = true;
89 p_attr->is_unpriv_wr_allow = false;
90 p_attr->is_xn = false;
91 return;
92 }
93
94 p_attr->is_valid = false;
95 #elif TFM_ISOLATION_LEVEL == 2
96 uintptr_t base, limit;
97
98 p_attr->is_mpu_enabled = false;
99 p_attr->is_valid = true;
100
101 /* TFM Core unprivileged code region */
102 base = (uintptr_t)®ION_NAME(Image$$, TFM_UNPRIV_CODE_START, $$RO$$Base);
103 limit = (uintptr_t)®ION_NAME(Image$$, TFM_UNPRIV_CODE_END, $$RO$$Limit) - 1;
104 if (check_address_range(p, s, base, limit) == SPM_SUCCESS) {
105 p_attr->is_priv_rd_allow = true;
106 p_attr->is_priv_wr_allow = false;
107 p_attr->is_unpriv_rd_allow = true;
108 p_attr->is_unpriv_wr_allow = false;
109 p_attr->is_xn = false;
110 return;
111 }
112
113 #ifdef CONFIG_TFM_PARTITION_META
114 /* TFM partition metadata pointer region */
115 base = (uintptr_t)®ION_NAME(Image$$, TFM_SP_META_PTR, $$ZI$$Base);
116 limit = (uintptr_t)®ION_NAME(Image$$, TFM_SP_META_PTR, $$ZI$$Limit) - 1;
117 if (check_address_range(p, s, base, limit) == SPM_SUCCESS) {
118 p_attr->is_priv_rd_allow = true;
119 p_attr->is_priv_wr_allow = true;
120 p_attr->is_unpriv_rd_allow = true;
121 p_attr->is_unpriv_wr_allow = true;
122 p_attr->is_xn = true;
123 return;
124 }
125 #endif
126
127 /* APP RoT partition RO region */
128 base = (uintptr_t)®ION_NAME(Image$$, TFM_APP_CODE_START, $$Base);
129 limit = (uintptr_t)®ION_NAME(Image$$, TFM_APP_CODE_END, $$Base) - 1;
130 if (check_address_range(p, s, base, limit) == SPM_SUCCESS) {
131 p_attr->is_priv_rd_allow = true;
132 p_attr->is_priv_wr_allow = false;
133 p_attr->is_unpriv_rd_allow = true;
134 p_attr->is_unpriv_wr_allow = false;
135 p_attr->is_xn = false;
136 return;
137 }
138
139 /* RW, ZI and stack as one region */
140 base = (uintptr_t)®ION_NAME(Image$$, TFM_APP_RW_STACK_START, $$Base);
141 limit = (uintptr_t)®ION_NAME(Image$$, TFM_APP_RW_STACK_END, $$Base) - 1;
142 if (check_address_range(p, s, base, limit) == SPM_SUCCESS) {
143 p_attr->is_priv_rd_allow = true;
144 p_attr->is_priv_wr_allow = true;
145 p_attr->is_unpriv_rd_allow = true;
146 p_attr->is_unpriv_wr_allow = true;
147 p_attr->is_xn = true;
148 return;
149 }
150
151 /*
152 * Treat the remaining parts in secure data section and secure code section
153 * as privileged regions
154 */
155 base = (uintptr_t)S_DATA_START;
156 limit = (uintptr_t)S_DATA_LIMIT;
157 if (check_address_range(p, s, base, limit) == SPM_SUCCESS) {
158 p_attr->is_priv_rd_allow = true;
159 p_attr->is_priv_wr_allow = true;
160 p_attr->is_unpriv_rd_allow = false;
161 p_attr->is_unpriv_wr_allow = false;
162 p_attr->is_xn = true;
163 return;
164 }
165
166 base = (uintptr_t)S_CODE_START;
167 limit = (uintptr_t)S_CODE_LIMIT;
168 if (check_address_range(p, s, base, limit) == SPM_SUCCESS) {
169 p_attr->is_priv_rd_allow = true;
170 p_attr->is_priv_wr_allow = false;
171 p_attr->is_unpriv_rd_allow = false;
172 p_attr->is_unpriv_wr_allow = false;
173 p_attr->is_xn = false;
174 return;
175 }
176
177 p_attr->is_valid = false;
178 #else
179 #error "Cannot support current TF-M isolation level"
180 #endif
181 }
182
tfm_get_ns_mem_region_attr(const void * p,size_t s,struct mem_attr_info_t * p_attr)183 void tfm_get_ns_mem_region_attr(const void *p, size_t s,
184 struct mem_attr_info_t *p_attr)
185 {
186 p_attr->is_mpu_enabled = false;
187 p_attr->is_valid = true;
188
189 if (check_address_range(p, s, NS_DATA_START,
190 NS_DATA_LIMIT) == SPM_SUCCESS) {
191 p_attr->is_priv_rd_allow = true;
192 p_attr->is_priv_wr_allow = true;
193 p_attr->is_unpriv_rd_allow = true;
194 p_attr->is_unpriv_wr_allow = true;
195 p_attr->is_xn = true;
196 return;
197 }
198
199 if (check_address_range(p, s, NS_CODE_START,
200 NS_CODE_LIMIT) == SPM_SUCCESS) {
201 p_attr->is_priv_rd_allow = true;
202 p_attr->is_priv_wr_allow = false;
203 p_attr->is_unpriv_rd_allow = true;
204 p_attr->is_unpriv_wr_allow = false;
205 p_attr->is_xn = false;
206 return;
207 }
208
209 p_attr->is_valid = false;
210 }
211
security_attr_init(struct security_attr_info_t * p_attr)212 static void security_attr_init(struct security_attr_info_t *p_attr)
213 {
214 /* No check if p_attr is valid */
215
216 /*
217 * The initial values may be not a valid combination.
218 * The value in each filed just guarantees the least access permission in
219 * case that the field is incorrectly set later.
220 */
221 p_attr->is_valid = false;
222 p_attr->is_secure = true;
223 }
224
mem_attr_init(struct mem_attr_info_t * p_attr)225 static void mem_attr_init(struct mem_attr_info_t *p_attr)
226 {
227 /* No check if p_attr is valid */
228
229 /*
230 * The initial values may be not a valid combination.
231 * The value in each filed just guarantees the least access permission in
232 * case that the field is incorrectly set later.
233 */
234 p_attr->is_mpu_enabled = false;
235 p_attr->is_valid = false;
236 p_attr->is_xn = true;
237 p_attr->is_priv_rd_allow = false;
238 p_attr->is_priv_wr_allow = false;
239 p_attr->is_unpriv_rd_allow = false;
240 p_attr->is_unpriv_wr_allow = false;
241 }
242
243 /**
244 * \brief Check whether the access permission matches the security settings of
245 * the target memory region
246 *
247 * \param[in] attr The security_attr_info_t containing security settings of
248 * memory region
249 * \param[in] flags The flags indicating the access permissions.
250 *
251 * \return SPM_SUCCESS if the check passes,
252 * SPM_ERROR_GENERIC otherwise.
253 */
security_attr_check(struct security_attr_info_t attr,uint8_t flags)254 static int32_t security_attr_check(struct security_attr_info_t attr, uint8_t flags)
255 {
256 bool secure_access;
257
258 if (!attr.is_valid) {
259 return SPM_ERROR_GENERIC;
260 }
261
262 secure_access = flags & MEM_CHECK_NONSECURE ? false : true;
263 /*
264 * Non-secure access should not access secure memory region.
265 * Secure service should not directly access non-secure memory region.
266 */
267 if (secure_access ^ attr.is_secure) {
268 return SPM_ERROR_GENERIC;
269 }
270
271 return SPM_SUCCESS;
272 }
273
274 /**
275 * \brief Check whether the access permission matches the target non-secure
276 * memory region access attributes.
277 *
278 * \param[in] attr The mem_attr_info_t containing attributes of memory region
279 * \param[in] flags The flags indicating the access permissions.
280 *
281 * \return SPM_SUCCESS if the check passes,
282 * SPM_ERROR_GENERIC otherwise.
283 */
ns_mem_attr_check(struct mem_attr_info_t attr,uint8_t flags)284 static int32_t ns_mem_attr_check(struct mem_attr_info_t attr, uint8_t flags)
285 {
286 /*
287 * Non-secure privileged/unprivileged check is skipped.
288 * Non-secure software should implement the check if it enforces the
289 * isolation between privileged and unprivileged regions.
290 */
291
292 if ((flags & MEM_CHECK_MPU_READWRITE) &&
293 (attr.is_priv_rd_allow || attr.is_unpriv_rd_allow) &&
294 (attr.is_priv_wr_allow || attr.is_unpriv_wr_allow)) {
295 return SPM_SUCCESS;
296 }
297
298 if ((flags & MEM_CHECK_MPU_READ) &&
299 (attr.is_priv_rd_allow || attr.is_unpriv_rd_allow)) {
300 return SPM_SUCCESS;
301 }
302
303 return SPM_ERROR_GENERIC;
304 }
305
306 /**
307 * \brief Check whether the access permission matches the target secure memory
308 * region access attributes.
309 *
310 * \param[in] attr The mem_attr_info_t containing attributes of memory region
311 * \param[in] flags The flags indicating the access permissions.
312 *
313 * \return SPM_SUCCESS if the check passes,
314 * SPM_ERROR_GENERIC otherwise.
315 */
secure_mem_attr_check(struct mem_attr_info_t attr,uint8_t flags)316 static int32_t secure_mem_attr_check(struct mem_attr_info_t attr, uint8_t flags)
317 {
318 #if TFM_ISOLATION_LEVEL == 1
319 /* Privileged/unprivileged is ignored in TFM_ISOLATION_LEVEL == 1 */
320
321 if ((flags & MEM_CHECK_MPU_READWRITE) &&
322 (attr.is_priv_rd_allow || attr.is_unpriv_rd_allow) &&
323 (attr.is_priv_wr_allow || attr.is_unpriv_wr_allow)) {
324 return SPM_SUCCESS;
325 }
326
327 if ((flags & MEM_CHECK_MPU_READ) &&
328 (attr.is_priv_rd_allow || attr.is_unpriv_rd_allow)) {
329 return SPM_SUCCESS;
330 }
331
332 return SPM_ERROR_GENERIC;
333 #else
334 if (flags & MEM_CHECK_MPU_UNPRIV) {
335 if ((flags & MEM_CHECK_MPU_READWRITE) && attr.is_unpriv_rd_allow &&
336 attr.is_unpriv_wr_allow) {
337 return SPM_SUCCESS;
338 }
339
340 if ((flags & MEM_CHECK_MPU_READ) && attr.is_unpriv_rd_allow) {
341 return SPM_SUCCESS;
342 }
343 } else {
344 if ((flags & MEM_CHECK_MPU_READWRITE) && attr.is_priv_rd_allow &&
345 attr.is_priv_wr_allow) {
346 return SPM_SUCCESS;
347 }
348
349 if ((flags & MEM_CHECK_MPU_READ) && attr.is_priv_rd_allow) {
350 return SPM_SUCCESS;
351 }
352 }
353
354 return SPM_ERROR_GENERIC;
355 #endif
356 }
357
358 /**
359 * \brief Check whether the access permission matches the memory attributes of
360 * the target memory region
361 *
362 * \param[in] attr The mem_attr_info_t containing memory region attributes
363 * \param[in] flags The flags indicating the access permissions.
364 *
365 * \return SPM_SUCCESS if the check passes,
366 * SPM_ERROR_GENERIC otherwise.
367 */
mem_attr_check(struct mem_attr_info_t attr,uint8_t flags)368 static int32_t mem_attr_check(struct mem_attr_info_t attr, uint8_t flags)
369 {
370 if (!attr.is_valid) {
371 return SPM_ERROR_GENERIC;
372 }
373
374 if (flags & MEM_CHECK_NONSECURE) {
375 return ns_mem_attr_check(attr, flags);
376 }
377
378 return secure_mem_attr_check(attr, flags);
379 }
380
tfm_has_access_to_region(const void * p,size_t s,uint32_t flags)381 int32_t tfm_has_access_to_region(const void *p, size_t s, uint32_t flags)
382 {
383 struct security_attr_info_t security_attr;
384 struct mem_attr_info_t mem_attr;
385
386 /* If size is zero, this indicates an empty buffer and base is ignored */
387 if (s == 0) {
388 return SPM_SUCCESS;
389 }
390
391 if (!p) {
392 return SPM_ERROR_GENERIC;
393 }
394
395 if ((uintptr_t)p > (UINTPTR_MAX - s)) {
396 return SPM_ERROR_GENERIC;
397 }
398
399 /* Abort if current check doesn't run in PSA RoT */
400 if (!tfm_arch_is_priv()) {
401 tfm_core_panic();
402 }
403
404 security_attr_init(&security_attr);
405
406 /* Retrieve security attributes of target memory region */
407 tfm_hal_get_mem_security_attr(p, s, &security_attr);
408
409 if (security_attr_check(security_attr, flags) != SPM_SUCCESS) {
410 return SPM_ERROR_GENERIC;
411 }
412
413 mem_attr_init(&mem_attr);
414
415 if (security_attr.is_secure) {
416 /* Retrieve access attributes of secure memory region */
417 tfm_hal_get_secure_access_attr(p, s, &mem_attr);
418
419 #if TFM_ISOLATION_LEVEL != 1
420 /* Secure MPU must be enabled in Isolation Level 2 and 3 */
421 if (!mem_attr.is_mpu_enabled) {
422 tfm_core_panic();
423 }
424 #endif
425 } else {
426 /* Retrieve access attributes of non-secure memory region. */
427 tfm_hal_get_ns_access_attr(p, s, &mem_attr);
428 }
429
430 return mem_attr_check(mem_attr, flags);
431 }
432
check_address_range(const void * p,size_t s,uintptr_t region_start,uintptr_t region_limit)433 int32_t check_address_range(const void *p, size_t s,
434 uintptr_t region_start,
435 uintptr_t region_limit)
436 {
437 int32_t range_in_region;
438
439 /* Check for overflow in the range parameters */
440 if ((uintptr_t)p > UINTPTR_MAX - s) {
441 return SPM_ERROR_GENERIC;
442 }
443
444 /* We trust the region parameters, and don't check for overflow */
445
446 /* Calculate the result */
447 range_in_region = ((uintptr_t)p >= region_start) &&
448 ((uintptr_t)((char *) p + s - 1) <= region_limit);
449 if (range_in_region) {
450 return SPM_SUCCESS;
451 } else {
452 return SPM_ERROR_GENERIC;
453 }
454 }
455