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