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