1 /*
2 * Copyright (c) 2017, 2020 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "mem_protect.h"
8 #include <zephyr/internal/syscall_handler.h>
9 #include <zephyr/sys/libc-hooks.h> /* for z_libc_partition */
10
11 /* function prototypes */
dummy_start(struct k_timer * timer)12 static inline void dummy_start(struct k_timer *timer)
13 {
14 ARG_UNUSED(timer);
15 }
dummy_end(struct k_timer * timer)16 static inline void dummy_end(struct k_timer *timer)
17 {
18 ARG_UNUSED(timer);
19 }
20
21 /* Kernel objects */
22 K_THREAD_STACK_DEFINE(test_1_stack, INHERIT_STACK_SIZE);
23 K_THREAD_STACK_DEFINE(parent_thr_stack, STACK_SIZE);
24 K_THREAD_STACK_DEFINE(child_thr_stack, STACK_SIZE);
25 K_HEAP_DEFINE(heap_mem, BLK_SIZE_MAX * BLK_NUM_MAX);
26 K_SEM_DEFINE(inherit_sem, SEMAPHORE_INIT_COUNT, SEMAPHORE_MAX_COUNT);
27 K_SEM_DEFINE(sync_sem, SEM_INIT_VAL, SEM_MAX_VAL);
28 K_MUTEX_DEFINE(inherit_mutex);
29 K_TIMER_DEFINE(inherit_timer, dummy_start, dummy_end);
30 K_MSGQ_DEFINE(inherit_msgq, MSG_Q_SIZE, MSG_Q_MAX_NUM_MSGS, MSG_Q_ALIGN);
31 struct k_thread test_1_tid, parent_thr, child_thr;
32 k_tid_t parent_tid;
33
34 uint8_t MEM_DOMAIN_ALIGNMENT inherit_buf[MEM_REGION_ALLOC]; /* for mem domain */
35
36 K_MEM_PARTITION_DEFINE(inherit_memory_partition,
37 inherit_buf,
38 sizeof(inherit_buf),
39 K_MEM_PARTITION_P_RW_U_RW);
40
41 struct k_mem_partition *inherit_memory_partition_array[] = {
42 #if Z_LIBC_PARTITION_EXISTS
43 &z_libc_partition,
44 #endif
45 &inherit_memory_partition,
46 &ztest_mem_partition
47 };
48
49 struct k_mem_domain inherit_mem_domain;
50
51 /* generic function to do check the access permissions. */
access_test(void)52 static void access_test(void)
53 {
54 uint32_t msg_q_data = 0xA5A5;
55
56 /* check for all accesses */
57 k_sem_give(&inherit_sem);
58 k_mutex_lock(&inherit_mutex, K_FOREVER);
59 (void) k_timer_status_get(&inherit_timer);
60 k_msgq_put(&inherit_msgq, (void *)&msg_q_data, K_NO_WAIT);
61 k_mutex_unlock(&inherit_mutex);
62 inherit_buf[MEM_REGION_ALLOC-1] = 0xA5;
63 }
64
test_thread_1_for_user(void * p1,void * p2,void * p3)65 static void test_thread_1_for_user(void *p1, void *p2, void *p3)
66 {
67 /* check that child thread inherited permissions */
68 access_test();
69
70 set_fault_valid(true);
71
72 /* Check that child thread can't access parent thread object*/
73 /* Kernel fault in that place will happen */
74 k_thread_priority_get(parent_tid);
75 }
76
test_thread_1_for_SU(void * p1,void * p2,void * p3)77 static void test_thread_1_for_SU(void *p1, void *p2, void *p3)
78 {
79 set_fault_valid(false);
80
81 access_test();
82
83 /* Check if user mode inherit is working if control is passed from SU */
84 k_thread_user_mode_enter(test_thread_1_for_user, NULL, NULL, NULL);
85 }
86
87 /**
88 * @brief Test object permission inheritance except of the parent thread object
89 *
90 * @details
91 * - To the parent current thread grant permissions on kernel objects.
92 * - Create a child thread and check that it inherited permissions on that
93 * kernel objects.
94 * - Then check child thread can't access to the parent thread object using API
95 * command k_thread_priority_get()
96 * - At the same moment that test verifies that child thread was granted
97 * permission on a kernel objects. That means child user thread caller
98 * already has permission on the thread objects being granted.
99
100 * @ingroup kernel_memprotect_tests
101 *
102 * @see k_mem_domain_init(), k_mem_domain_add_thread(),
103 * k_thread_access_grant()
104 */
ZTEST(mem_protect,test_permission_inheritance)105 ZTEST(mem_protect, test_permission_inheritance)
106 {
107 parent_tid = k_current_get();
108 k_mem_domain_add_thread(&inherit_mem_domain, parent_tid);
109
110 k_thread_access_grant(parent_tid,
111 &inherit_sem,
112 &inherit_mutex,
113 &inherit_timer,
114 &inherit_msgq, &test_1_stack);
115
116 k_thread_create(&test_1_tid,
117 test_1_stack,
118 INHERIT_STACK_SIZE,
119 test_thread_1_for_SU,
120 NULL, NULL, NULL,
121 0, K_INHERIT_PERMS, K_NO_WAIT);
122
123 k_thread_join(&test_1_tid, K_FOREVER);
124 }
125
z_impl_ret_resource_pool_ptr(void)126 struct k_heap *z_impl_ret_resource_pool_ptr(void)
127 {
128 return arch_current_thread()->resource_pool;
129 }
130
z_vrfy_ret_resource_pool_ptr(void)131 static inline struct k_heap *z_vrfy_ret_resource_pool_ptr(void)
132 {
133 return z_impl_ret_resource_pool_ptr();
134 }
135 #include <zephyr/syscalls/ret_resource_pool_ptr_mrsh.c>
136 struct k_heap *child_heap_mem_ptr;
137 struct k_heap *parent_heap_mem_ptr;
138
child_handler(void * p1,void * p2,void * p3)139 void child_handler(void *p1, void *p2, void *p3)
140 {
141 child_heap_mem_ptr = ret_resource_pool_ptr();
142 k_sem_give(&sync_sem);
143 }
144
parent_handler(void * p1,void * p2,void * p3)145 void parent_handler(void *p1, void *p2, void *p3)
146 {
147 parent_heap_mem_ptr = ret_resource_pool_ptr();
148 k_thread_create(&child_thr, child_thr_stack,
149 K_THREAD_STACK_SIZEOF(child_thr_stack),
150 child_handler,
151 NULL, NULL, NULL,
152 PRIORITY, 0, K_NO_WAIT);
153
154 k_thread_join(&child_thr, K_FOREVER);
155 }
156
157 /**
158 * @brief Test child thread inherits parent's thread resource pool
159 *
160 * @details
161 * - Create a memory heap heap_mem for the parent thread.
162 * - Then special system call ret_resource_pool_ptr() returns pointer
163 * to the resource pool of the current thread.
164 * - Call it in the parent_handler() and in the child_handler()
165 * - Then in the main test function test_inherit_resource_pool()
166 * compare returned addresses
167 * - If the addresses are the same, it means that child thread inherited
168 * resource pool of the parent's thread -test passed.
169 *
170 * @ingroup kernel_memprotect_tests
171 *
172 * @see k_thread_heap_assign()
173 */
ZTEST(mem_protect,test_inherit_resource_pool)174 ZTEST(mem_protect, test_inherit_resource_pool)
175 {
176 k_sem_reset(&sync_sem);
177 k_thread_create(&parent_thr, parent_thr_stack,
178 K_THREAD_STACK_SIZEOF(parent_thr_stack),
179 parent_handler,
180 NULL, NULL, NULL,
181 PRIORITY, 0, K_FOREVER);
182 k_thread_heap_assign(&parent_thr, &heap_mem);
183 k_thread_start(&parent_thr);
184 k_sem_take(&sync_sem, K_FOREVER);
185 zassert_true(parent_heap_mem_ptr == child_heap_mem_ptr,
186 "Resource pool of the parent thread not inherited,"
187 " by child thread");
188
189 k_thread_join(&parent_thr, K_FOREVER);
190 }
191
mem_protect_inhert_setup(void)192 void mem_protect_inhert_setup(void)
193 {
194 int ret;
195
196 ret = k_mem_domain_init(&inherit_mem_domain,
197 ARRAY_SIZE(inherit_memory_partition_array),
198 inherit_memory_partition_array);
199 if (ret != 0) {
200 ztest_test_fail();
201 }
202 }
203
204
205 K_HEAP_DEFINE(test_mem_heap, TEST_HEAP_SIZE);
206
mem_protect_setup(void)207 void *mem_protect_setup(void)
208 {
209 k_thread_priority_set(k_current_get(), -1);
210
211 k_thread_heap_assign(k_current_get(), &test_mem_heap);
212
213 mem_protect_inhert_setup();
214
215 return NULL;
216 }
217
218 ZTEST_SUITE(mem_protect, NULL, mem_protect_setup,
219 NULL, NULL, NULL);
220