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)&REGION_NAME(Image$$, TFM_UNPRIV_CODE_START, $$RO$$Base);
103     limit = (uintptr_t)&REGION_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)&REGION_NAME(Image$$, TFM_SP_META_PTR, $$ZI$$Base);
116     limit = (uintptr_t)&REGION_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)&REGION_NAME(Image$$, TFM_APP_CODE_START, $$Base);
129     limit = (uintptr_t)&REGION_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)&REGION_NAME(Image$$, TFM_APP_RW_STACK_START, $$Base);
141     limit = (uintptr_t)&REGION_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