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