1 /*
2  * Copyright (c) 2017 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/internal/syscall_handler.h>
9 #include <zephyr/ztest.h>
10 #include <kernel_internal.h>
11 
12 #define SEM_ARRAY_SIZE	16
13 
14 /* Show that extern declarations don't interfere with detecting kernel
15  * objects, this was at one point a problem.
16  */
17 extern struct k_sem sem1;
18 
19 static struct k_sem semarray[SEM_ARRAY_SIZE];
20 static struct k_sem *dyn_sem[SEM_ARRAY_SIZE];
21 
22 static struct k_mutex *test_dyn_mutex;
23 
24 K_SEM_DEFINE(sem1, 0, 1);
25 static struct k_sem sem2;
26 static char bad_sem[sizeof(struct k_sem)];
27 static struct k_sem sem3;
28 
test_object(struct k_sem * sem,int retval)29 static int test_object(struct k_sem *sem, int retval)
30 {
31 	int ret;
32 
33 	if (retval) {
34 		/* Expected to fail; bypass k_object_validation_check() so we don't
35 		 * fill the logs with spam
36 		 */
37 		ret = k_object_validate(k_object_find(sem), K_OBJ_SEM, 0);
38 	} else {
39 		ret = k_object_validation_check(k_object_find(sem), sem,
40 					    K_OBJ_SEM, 0);
41 	}
42 
43 	if (ret != retval) {
44 		TC_PRINT("FAIL check of %p is not %d, got %d instead\n", sem,
45 			 retval, ret);
46 		return 1;
47 	}
48 	return 0;
49 }
50 
object_permission_checks(struct k_sem * sem,bool skip_init)51 void object_permission_checks(struct k_sem *sem, bool skip_init)
52 {
53 	/* Should fail because we don't have perms on this object */
54 	zassert_false(test_object(sem, -EPERM),
55 		      "object should not have had permission granted");
56 
57 	k_object_access_grant(sem, k_current_get());
58 
59 	if (!skip_init) {
60 		/* Should fail, not initialized and we have no permissions */
61 		zassert_false(test_object(sem, -EINVAL),
62 			      "object should not have been initialized");
63 		k_sem_init(sem, 0, 1);
64 	}
65 
66 	/* This should succeed now */
67 	zassert_false(test_object(sem, 0),
68 		      "object should have had sufficient permissions");
69 }
70 
71 /**
72  * @brief Test to verify object permission
73  *
74  * @details
75  * - The kernel must be able to associate kernel object memory addresses
76  *   with whether the calling thread has access to that object, the object is
77  *   of the expected type, and the object is of the expected init state.
78  * - Test support freeing kernel objects allocated at runtime manually.
79  *
80  * @ingroup kernel_memprotect_tests
81  *
82  * @see k_object_alloc(), k_object_access_grant()
83  */
ZTEST(object_validation,test_generic_object)84 ZTEST(object_validation, test_generic_object)
85 {
86 	struct k_sem stack_sem;
87 
88 	/* None of these should be even in the table */
89 	zassert_false(test_object(&stack_sem, -EBADF));
90 	zassert_false(test_object((struct k_sem *)&bad_sem, -EBADF));
91 	zassert_false(test_object((struct k_sem *)0xFFFFFFFF, -EBADF));
92 	object_permission_checks(&sem3, false);
93 	object_permission_checks(&sem1, true);
94 	object_permission_checks(&sem2, false);
95 
96 	for (int i = 0; i < SEM_ARRAY_SIZE; i++) {
97 		object_permission_checks(&semarray[i], false);
98 		dyn_sem[i] = k_object_alloc(K_OBJ_SEM);
99 		zassert_not_null(dyn_sem[i], "couldn't allocate semaphore");
100 		/* Give an extra reference to another thread so the object
101 		 * doesn't disappear if we revoke our own
102 		 */
103 		k_object_access_grant(dyn_sem[i], &z_main_thread);
104 	}
105 
106 	/* dynamic object table well-populated with semaphores at this point */
107 	for (int i = 0; i < SEM_ARRAY_SIZE; i++) {
108 		/* Should have permission granted but be uninitialized */
109 		zassert_false(test_object(dyn_sem[i], -EINVAL));
110 		k_object_access_revoke(dyn_sem[i], k_current_get());
111 		object_permission_checks(dyn_sem[i], false);
112 		k_object_free(dyn_sem[i]);
113 		zassert_false(test_object(dyn_sem[i], -EBADF));
114 	}
115 }
116 
117 /**
118  * @brief Test requestor thread will implicitly be assigned permission on the
119  * dynamically allocated object
120  *
121  * @details
122  * - Create kernel object semaphore, dynamically allocate it from the calling
123  *   thread's resource pool.
124  * - Check that object's address is in bounds of that memory pool.
125  * - Then check the requestor thread will implicitly be assigned permission on
126  *   the allocated object by using semaphore API k_sem_init()
127  *
128  * @ingroup kernel_memprotect_tests
129  *
130  * @see k_object_alloc()
131  */
ZTEST(object_validation,test_kobj_assign_perms_on_alloc_obj)132 ZTEST(object_validation, test_kobj_assign_perms_on_alloc_obj)
133 {
134 	static struct k_sem *test_dyn_sem;
135 	struct k_thread *thread = _current;
136 
137 	uintptr_t start_addr, end_addr;
138 	size_t size_heap = K_HEAP_MEM_POOL_SIZE;
139 
140 	/* dynamically allocate kernel object semaphore */
141 	test_dyn_sem = k_object_alloc(K_OBJ_SEM);
142 	zassert_not_null(test_dyn_sem, "Cannot allocate sem k_object");
143 
144 	start_addr = *((uintptr_t *)(void *)thread->resource_pool);
145 	end_addr = start_addr + size_heap;
146 
147 	/* check semaphore initialized within thread's mem pool address space */
148 	zassert_true(((uintptr_t)test_dyn_sem > start_addr) &&
149 				 ((uintptr_t)test_dyn_sem < end_addr),
150 				 "semaphore object not in bound of thread's memory pool");
151 
152 	/* try to init that object, thread should have permissions implicitly */
153 	k_sem_init(test_dyn_sem, 1, 1);
154 }
155 
156 /**
157  * @brief Test dynamically allocated kernel object release memory
158  *
159  * @details Dynamically allocated kernel objects whose access is controlled by
160  * the permission system will use object permission as a reference count.
161  * If no threads have access to an object, the object's memory released.
162  *
163  * @ingroup kernel_memprotect_tests
164  *
165  * @see k_object_alloc()
166  */
ZTEST(object_validation,test_no_ref_dyn_kobj_release_mem)167 ZTEST(object_validation, test_no_ref_dyn_kobj_release_mem)
168 {
169 	int ret;
170 
171 	/* dynamically allocate kernel object mutex */
172 	test_dyn_mutex = k_object_alloc(K_OBJ_MUTEX);
173 	zassert_not_null(test_dyn_mutex,
174 					 "Can not allocate dynamic kernel object");
175 
176 	struct k_thread *thread = _current;
177 
178 	/* revoke access from the current thread */
179 	k_object_access_revoke(test_dyn_mutex, thread);
180 
181 	/* check object was released, when no threads have access to it */
182 	ret = k_object_validate(k_object_find(test_dyn_mutex), K_OBJ_MUTEX, 0);
183 	zassert_true(ret == -EBADF, "Dynamic kernel object not released");
184 }
185 
object_validation_setup(void)186 void *object_validation_setup(void)
187 {
188 	k_thread_system_pool_assign(k_current_get());
189 
190 	return NULL;
191 }
192 
193 ZTEST_SUITE(object_validation, NULL, object_validation_setup, NULL, NULL, NULL);
194