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)&REGION_NAME(Image$$, TFM_UNPRIV_CODE, $$RO$$Base);
111     limit = (uintptr_t)&REGION_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)&REGION_NAME(Image$$, TFM_SP_META_PTR, $$ZI$$Base);
124     limit = (uintptr_t)&REGION_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)&REGION_NAME(Image$$, TFM_APP_CODE_START, $$Base);
137     limit = (uintptr_t)&REGION_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)&REGION_NAME(Image$$, TFM_APP_RW_STACK_START, $$Base);
149     limit = (uintptr_t)&REGION_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