TF-M Reference Manual  1.2.0
TrustedFirmware-M
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
tfm_multi_core_mem_check.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <stdbool.h>
8 
9 #include "tfm_spm_hal.h"
10 #include "region_defs.h"
11 #include "spm_ipc.h"
12 #include "tfm_hal_isolation.h"
13 #include "tfm_multi_core.h"
14 #include "tfm_secure_api.h"
15 #include "utilities.h"
16 #include "region.h"
17 
18 #ifndef TFM_LVL
19 #error TFM_LVL is not defined!
20 #endif
21 
22 /* Follow CMSE flag definitions */
23 #define MEM_CHECK_MPU_READWRITE (1 << 0x0)
24 #define MEM_CHECK_AU_NONSECURE (1 << 0x1)
25 #define MEM_CHECK_MPU_UNPRIV (1 << 0x2)
26 #define MEM_CHECK_MPU_READ (1 << 0x3)
27 #define MEM_CHECK_MPU_NONSECURE (1 << 0x4)
28 #define MEM_CHECK_NONSECURE (MEM_CHECK_AU_NONSECURE | \
29  MEM_CHECK_MPU_NONSECURE)
30 
44 static enum tfm_status_e check_address_range(const void *p, size_t s,
45  uintptr_t region_start,
46  uintptr_t region_limit)
47 {
48  int32_t range_in_region;
49 
50  /* Check for overflow in the range parameters */
51  if ((uintptr_t)p > UINTPTR_MAX - s) {
52  return TFM_ERROR_GENERIC;
53  }
54 
55  /* We trust the region parameters, and don't check for overflow */
56 
57  /* Calculate the result */
58  range_in_region = ((uintptr_t)p >= region_start) &&
59  ((uintptr_t)((char *) p + s - 1) <= region_limit);
60  if (range_in_region) {
61  return TFM_SUCCESS;
62  } else {
63  return TFM_ERROR_GENERIC;
64  }
65 }
66 
67 void tfm_get_mem_region_security_attr(const void *p, size_t s,
68  struct security_attr_info_t *p_attr)
69 {
70  p_attr->is_valid = true;
71 
72  if (check_address_range(p, s, NS_DATA_START,
73  NS_DATA_LIMIT) == TFM_SUCCESS) {
74  p_attr->is_secure = false;
75  return;
76  }
77 
78  if (check_address_range(p, s, NS_CODE_START,
79  NS_CODE_LIMIT) == TFM_SUCCESS) {
80  p_attr->is_secure = false;
81  return;
82  }
83 
84  if (check_address_range(p, s, S_DATA_START, S_DATA_LIMIT) == TFM_SUCCESS) {
85  p_attr->is_secure = true;
86  return;
87  }
88 
89  if (check_address_range(p, s, S_CODE_START, S_CODE_LIMIT) == TFM_SUCCESS) {
90  p_attr->is_secure = true;
91  return;
92  }
93 
94  p_attr->is_valid = false;
95 }
96 
97 #if TFM_LVL == 2
98 REGION_DECLARE(Image$$, TFM_UNPRIV_CODE, $$RO$$Base);
99 REGION_DECLARE(Image$$, TFM_UNPRIV_CODE, $$RO$$Limit);
100 REGION_DECLARE(Image$$, TFM_UNPRIV_DATA, $$RW$$Base);
101 REGION_DECLARE(Image$$, TFM_UNPRIV_DATA, $$ZI$$Limit);
102 REGION_DECLARE(Image$$, TFM_APP_CODE_START, $$Base);
103 REGION_DECLARE(Image$$, TFM_APP_CODE_END, $$Base);
104 REGION_DECLARE(Image$$, TFM_APP_RW_STACK_START, $$Base);
105 REGION_DECLARE(Image$$, TFM_APP_RW_STACK_END, $$Base);
106 #endif
107 
108 void tfm_get_secure_mem_region_attr(const void *p, size_t s,
109  struct mem_attr_info_t *p_attr)
110 {
111 #if TFM_LVL == 1
112  p_attr->is_mpu_enabled = false;
113  p_attr->is_valid = true;
114 
115  if (check_address_range(p, s, S_DATA_START, S_DATA_LIMIT) == TFM_SUCCESS) {
116  p_attr->is_priv_rd_allow = true;
117  p_attr->is_priv_wr_allow = true;
118  p_attr->is_unpriv_rd_allow = true;
119  p_attr->is_unpriv_wr_allow = true;
120  p_attr->is_xn = true;
121  return;
122  }
123 
124  if (check_address_range(p, s, S_CODE_START, S_CODE_LIMIT) == TFM_SUCCESS) {
125  p_attr->is_priv_rd_allow = true;
126  p_attr->is_priv_wr_allow = false;
127  p_attr->is_unpriv_rd_allow = true;
128  p_attr->is_unpriv_wr_allow = false;
129  p_attr->is_xn = false;
130  return;
131  }
132 
133  p_attr->is_valid = false;
134 #elif TFM_LVL == 2
135  uintptr_t base, limit;
136 
137  p_attr->is_mpu_enabled = false;
138  p_attr->is_valid = true;
139 
140  /* TFM Core unprivileged code region */
141  base = (uintptr_t)&REGION_NAME(Image$$, TFM_UNPRIV_CODE, $$RO$$Base);
142  limit = (uintptr_t)&REGION_NAME(Image$$, TFM_UNPRIV_CODE, $$RO$$Limit) - 1;
143  if (check_address_range(p, s, base, limit) == TFM_SUCCESS) {
144  p_attr->is_priv_rd_allow = true;
145  p_attr->is_priv_wr_allow = false;
146  p_attr->is_unpriv_rd_allow = true;
147  p_attr->is_unpriv_wr_allow = false;
148  p_attr->is_xn = false;
149  return;
150  }
151 
152  /* TFM Core unprivileged data region */
153  base = (uintptr_t)&REGION_NAME(Image$$, TFM_UNPRIV_DATA, $$RW$$Base);
154  limit = (uintptr_t)&REGION_NAME(Image$$, TFM_UNPRIV_DATA, $$ZI$$Limit) - 1;
155  if (check_address_range(p, s, base, limit) == TFM_SUCCESS) {
156  p_attr->is_priv_rd_allow = true;
157  p_attr->is_priv_wr_allow = true;
158  p_attr->is_unpriv_rd_allow = true;
159  p_attr->is_unpriv_wr_allow = true;
160  p_attr->is_xn = true;
161  return;
162  }
163 
164  /* APP RoT partition RO region */
165  base = (uintptr_t)&REGION_NAME(Image$$, TFM_APP_CODE_START, $$Base);
166  limit = (uintptr_t)&REGION_NAME(Image$$, TFM_APP_CODE_END, $$Base) - 1;
167  if (check_address_range(p, s, base, limit) == TFM_SUCCESS) {
168  p_attr->is_priv_rd_allow = true;
169  p_attr->is_priv_wr_allow = false;
170  p_attr->is_unpriv_rd_allow = true;
171  p_attr->is_unpriv_wr_allow = false;
172  p_attr->is_xn = false;
173  return;
174  }
175 
176  /* RW, ZI and stack as one region */
177  base = (uintptr_t)&REGION_NAME(Image$$, TFM_APP_RW_STACK_START, $$Base);
178  limit = (uintptr_t)&REGION_NAME(Image$$, TFM_APP_RW_STACK_END, $$Base) - 1;
179  if (check_address_range(p, s, base, limit) == TFM_SUCCESS) {
180  p_attr->is_priv_rd_allow = true;
181  p_attr->is_priv_wr_allow = true;
182  p_attr->is_unpriv_rd_allow = true;
183  p_attr->is_unpriv_wr_allow = true;
184  p_attr->is_xn = true;
185  return;
186  }
187 
188  /*
189  * Treat the remaining parts in secure data section and secure code section
190  * as privileged regions
191  */
192  base = (uintptr_t)S_DATA_START;
193  limit = (uintptr_t)S_DATA_LIMIT;
194  if (check_address_range(p, s, base, limit) == TFM_SUCCESS) {
195  p_attr->is_priv_rd_allow = true;
196  p_attr->is_priv_wr_allow = true;
197  p_attr->is_unpriv_rd_allow = false;
198  p_attr->is_unpriv_wr_allow = false;
199  p_attr->is_xn = true;
200  return;
201  }
202 
203  base = (uintptr_t)S_CODE_START;
204  limit = (uintptr_t)S_CODE_LIMIT;
205  if (check_address_range(p, s, base, limit) == TFM_SUCCESS) {
206  p_attr->is_priv_rd_allow = true;
207  p_attr->is_priv_wr_allow = false;
208  p_attr->is_unpriv_rd_allow = false;
209  p_attr->is_unpriv_wr_allow = false;
210  p_attr->is_xn = false;
211  return;
212  }
213 
214  p_attr->is_valid = false;
215 #else
216 #error "Cannot support current TF-M isolation level"
217 #endif
218 }
219 
220 void tfm_get_ns_mem_region_attr(const void *p, size_t s,
221  struct mem_attr_info_t *p_attr)
222 {
223  p_attr->is_mpu_enabled = false;
224  p_attr->is_valid = true;
225 
226  if (check_address_range(p, s, NS_DATA_START,
227  NS_DATA_LIMIT) == TFM_SUCCESS) {
228  p_attr->is_priv_rd_allow = true;
229  p_attr->is_priv_wr_allow = true;
230  p_attr->is_unpriv_rd_allow = true;
231  p_attr->is_unpriv_wr_allow = true;
232  p_attr->is_xn = true;
233  return;
234  }
235 
236  if (check_address_range(p, s, NS_CODE_START,
237  NS_CODE_LIMIT) == TFM_SUCCESS) {
238  p_attr->is_priv_rd_allow = true;
239  p_attr->is_priv_wr_allow = false;
240  p_attr->is_unpriv_rd_allow = true;
241  p_attr->is_unpriv_wr_allow = false;
242  p_attr->is_xn = false;
243  return;
244  }
245 
246  p_attr->is_valid = false;
247 }
248 
249 static void security_attr_init(struct security_attr_info_t *p_attr)
250 {
251  /* No check if p_attr is valid */
252 
253  /*
254  * The initial values may be not a valid combination.
255  * The value in each filed just guarantees the least access permission in
256  * case that the field is incorrectly set later.
257  */
258  p_attr->is_valid = false;
259  p_attr->is_secure = true;
260 }
261 
262 static void mem_attr_init(struct mem_attr_info_t *p_attr)
263 {
264  /* No check if p_attr is valid */
265 
266  /*
267  * The initial values may be not a valid combination.
268  * The value in each filed just guarantees the least access permission in
269  * case that the field is incorrectly set later.
270  */
271  p_attr->is_mpu_enabled = false;
272  p_attr->is_valid = false;
273  p_attr->is_xn = true;
274  p_attr->is_priv_rd_allow = false;
275  p_attr->is_priv_wr_allow = false;
276  p_attr->is_unpriv_rd_allow = false;
277  p_attr->is_unpriv_wr_allow = false;
278 }
279 
291 static enum tfm_status_e security_attr_check(struct security_attr_info_t attr,
292  uint8_t flags)
293 {
294  bool secure_access;
295 
296  if (!attr.is_valid) {
297  return TFM_ERROR_GENERIC;
298  }
299 
300  secure_access = flags & MEM_CHECK_NONSECURE ? false : true;
301  /*
302  * Non-secure access should not access secure memory region.
303  * Secure service should not directly access non-secure memory region.
304  */
305  if (secure_access ^ attr.is_secure) {
306  return TFM_ERROR_GENERIC;
307  }
308 
309  return TFM_SUCCESS;
310 }
311 
322 static enum tfm_status_e ns_mem_attr_check(struct mem_attr_info_t attr,
323  uint8_t flags)
324 {
325  /*
326  * Non-secure privileged/unprivileged check is skipped.
327  * Non-secure software should implement the check if it enforces the
328  * isolation between privileged and unprivileged regions.
329  */
330 
331  if ((flags & MEM_CHECK_MPU_READWRITE) &&
332  (attr.is_priv_rd_allow || attr.is_unpriv_rd_allow) &&
333  (attr.is_priv_wr_allow || attr.is_unpriv_wr_allow)) {
334  return TFM_SUCCESS;
335  }
336 
337  if ((flags & MEM_CHECK_MPU_READ) &&
338  (attr.is_priv_rd_allow || attr.is_unpriv_rd_allow)) {
339  return TFM_SUCCESS;
340  }
341 
342  return TFM_ERROR_GENERIC;
343 }
344 
355 static enum tfm_status_e secure_mem_attr_check(struct mem_attr_info_t attr,
356  uint8_t flags)
357 {
358 #if TFM_LVL == 1
359  /* Privileged/unprivileged is ignored in TFM_LVL == 1 */
360 
361  if ((flags & MEM_CHECK_MPU_READWRITE) &&
362  (attr.is_priv_rd_allow || attr.is_unpriv_rd_allow) &&
363  (attr.is_priv_wr_allow || attr.is_unpriv_wr_allow)) {
364  return TFM_SUCCESS;
365  }
366 
367  if ((flags & MEM_CHECK_MPU_READ) &&
368  (attr.is_priv_rd_allow || attr.is_unpriv_rd_allow)) {
369  return TFM_SUCCESS;
370  }
371 
372  return TFM_ERROR_GENERIC;
373 #else
374  if (flags & MEM_CHECK_MPU_UNPRIV) {
375  if ((flags & MEM_CHECK_MPU_READWRITE) && attr.is_unpriv_rd_allow &&
376  attr.is_unpriv_wr_allow) {
377  return TFM_SUCCESS;
378  }
379 
380  if ((flags & MEM_CHECK_MPU_READ) && attr.is_unpriv_rd_allow) {
381  return TFM_SUCCESS;
382  }
383  } else {
384  if ((flags & MEM_CHECK_MPU_READWRITE) && attr.is_priv_rd_allow &&
385  attr.is_priv_wr_allow) {
386  return TFM_SUCCESS;
387  }
388 
389  if ((flags & MEM_CHECK_MPU_READ) && attr.is_priv_rd_allow) {
390  return TFM_SUCCESS;
391  }
392  }
393 
394  return TFM_ERROR_GENERIC;
395 #endif
396 }
397 
408 static enum tfm_status_e mem_attr_check(struct mem_attr_info_t attr,
409  uint8_t flags)
410 {
411  if (!attr.is_valid) {
412  return TFM_ERROR_GENERIC;
413  }
414 
415  if (flags & MEM_CHECK_NONSECURE) {
416  return ns_mem_attr_check(attr, flags);
417  }
418 
419  return secure_mem_attr_check(attr, flags);
420 }
421 
422 int32_t tfm_has_access_to_region(const void *p, size_t s, uint32_t attr)
423 {
424  struct security_attr_info_t security_attr;
425  struct mem_attr_info_t mem_attr;
426  uint8_t flags = 0;
427 
428  if (!p) {
429  return (int32_t)TFM_ERROR_GENERIC;
430  }
431 
432  if ((uintptr_t)p > (UINTPTR_MAX - s)) {
433  return (int32_t)TFM_ERROR_GENERIC;
434  }
435 
436  /* Abort if not in Handler mode */
437  if (!__get_IPSR()) {
438  tfm_core_panic();
439  }
440 
441  if (attr & TFM_HAL_ACCESS_UNPRIVILEGED) {
442  flags |= MEM_CHECK_MPU_UNPRIV;
443  }
444 
445  if (attr & TFM_HAL_ACCESS_NS) {
446  flags |= MEM_CHECK_NONSECURE;
447  }
448 
449  if ((attr & TFM_HAL_ACCESS_WRITABLE) && (attr & TFM_HAL_ACCESS_READABLE)) {
450  flags |= MEM_CHECK_MPU_READWRITE;
451  } else if (attr & TFM_HAL_ACCESS_READABLE) {
452  flags |= MEM_CHECK_MPU_READ;
453  } else {
454  return TFM_HAL_ERROR_INVALID_INPUT;
455  }
456 
457  security_attr_init(&security_attr);
458 
459  /* Retrieve security attributes of target memory region */
460  tfm_spm_hal_get_mem_security_attr(p, s, &security_attr);
461 
462  if (security_attr_check(security_attr, flags) != TFM_SUCCESS) {
463  return (int32_t)TFM_ERROR_GENERIC;
464  }
465 
466  mem_attr_init(&mem_attr);
467 
468  if (security_attr.is_secure) {
469  /* Retrieve access attributes of secure memory region */
470  tfm_spm_hal_get_secure_access_attr(p, s, &mem_attr);
471 
472 #if TFM_LVL != 1
473  /* Secure MPU must be enabled in Isolation Level 2 and 3 */
474  if (!mem_attr.is_mpu_enabled) {
475  tfm_core_panic();
476  }
477 #endif
478  } else {
479  /* Retrieve access attributes of non-secure memory region. */
480  tfm_spm_hal_get_ns_access_attr(p, s, &mem_attr);
481  }
482 
483  return (int32_t)mem_attr_check(mem_attr, flags);
484 }
tfm_status_e
Definition: tfm_api.h:45
void tfm_get_secure_mem_region_attr(const void *p, size_t s, struct mem_attr_info_t *p_attr)
Retrieve general secure memory protection configuration information of the target memory region accor...
void tfm_get_mem_region_security_attr(const void *p, size_t s, struct security_attr_info_t *p_attr)
Retrieve general security isolation configuration information of the target memory region according t...
#define MEM_CHECK_NONSECURE
int32_t tfm_has_access_to_region(const void *p, size_t s, uint32_t attr)
Check whether a memory access is allowed to access to a memory range.
REGION_DECLARE(Image $$, ARM_LIB_STACK_MSP,$$ZI $$Base)
void tfm_core_panic(void)
Definition: utilities.c:11
void tfm_get_ns_mem_region_attr(const void *p, size_t s, struct mem_attr_info_t *p_attr)
Retrieve general non-secure memory protection configuration information of the target memory region a...
#define MEM_CHECK_MPU_UNPRIV
#define MEM_CHECK_MPU_READWRITE
#define MEM_CHECK_MPU_READ