1 /**
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <dlfcn.h>
17 #include <stdbool.h>
18 #include <stdint.h>
19 #include <stdio.h>
20 #include <sys/wait.h>
21 #include "functionalext.h"
22
23 #define LIB_PATH "/data/tests/libc-test/src/libldso_cfi_test_lib.so"
24
25 struct dso {
26 char *mock;
27 unsigned char *map;
28 size_t map_len;
29 };
30
31 extern int init_cfi_shadow(struct dso *dso_list, struct dso *ldso);
32 extern int map_dso_to_cfi_shadow(struct dso *dso);
33 extern void unmap_dso_from_cfi_shadow(struct dso *dso);
34 extern void __cfi_slowpath(uint64_t CallSiteTypeId, void *Ptr);
35 extern void __cfi_slowpath_diag(uint64_t CallSiteTypeId, void *Ptr, void *DiagData);
36
37 typedef void(*TEST_FUN)(void);
38 typedef size_t (*GET_COUNT)();
39 typedef uint64_t (*GET_TP_ID)();
40 typedef void* (*GET_LAST_ADDR)();
41 typedef void* (*GET_LAST_DIAG)();
42 typedef void* (*GET_GL_ADDR)();
43 typedef void (*CFI_CHECK)();
44 typedef char* (*BUF_CHECK)();
45
46 GET_COUNT get_count = NULL;
47 GET_TP_ID get_type_id = NULL;
48 GET_LAST_ADDR get_address = NULL;
49 GET_LAST_DIAG get_diag = NULL;
50 GET_GL_ADDR get_global_address = NULL;
51 CFI_CHECK cfi_check = NULL;
52 BUF_CHECK buf_check = NULL;
53
test_funcnull54 static void test_func() {}
55
56 /**
57 * @tc.name : cfi_init_test_0001
58 * @tc.desc : If no dso while initializing the CFI shadow, do nothing and return true.
59 * @tc.level : Level 1
60 */
cfi_init_test_0001(void)61 void cfi_init_test_0001(void)
62 {
63 printf("["__FILE__"][Line: %d][%s]: entry\n", __LINE__, __func__);
64 EXPECT_EQ("cfi_init_test_0001", init_cfi_shadow(NULL, NULL), 0);
65 }
66
67 /**
68 * @tc.name : cfi_init_test_0002
69 * @tc.desc : If dso is NULL while mapping to the CFI shadow, do nothing and return true.
70 * @tc.level : Level 2
71 */
cfi_init_test_0002(void)72 void cfi_init_test_0002(void)
73 {
74 printf("["__FILE__"][Line: %d][%s]: entry\n", __LINE__, __func__);
75 EXPECT_EQ("cfi_init_test_0002", map_dso_to_cfi_shadow(NULL), 0);
76 }
77
78 /**
79 * @tc.name : cfi_init_test_0003
80 * @tc.desc : If dso is NULL while unmapping from the CFI shadow, do nothing.
81 * @tc.level : Level 2
82 */
cfi_init_test_0003(void)83 void cfi_init_test_0003(void)
84 {
85 printf("["__FILE__"][Line: %d][%s]: entry\n", __LINE__, __func__);
86 unmap_dso_from_cfi_shadow(NULL);
87 }
88
89 /**
90 * @tc.name : cfi_slowpath_function_test_0002
91 * @tc.desc : Loading a dso that contains __cfi_check() symbol, call the __cfi_slowpath() function with
92 * address inside the DSO, the __cfi_check() function is called.
93 * @tc.level : Level 1
94 */
cfi_slowpath_function_test_0002(void)95 void cfi_slowpath_function_test_0002(void)
96 {
97 printf("["__FILE__"][Line: %d][%s]: entry\n", __LINE__, __func__);
98 uint64_t expected_call_site_type_id = 20;
99 void* handle = dlopen(LIB_PATH, RTLD_LAZY);
100 EXPECT_PTRNE("cfi_slowpath_function_test_0002", handle, NULL);
101
102 *(void **)(&get_count) = dlsym(handle, "get_count");
103 *(void **)(&get_type_id) = dlsym(handle, "get_type_id");
104 *(void **)(&get_address) = dlsym(handle, "get_address");
105 *(void **)(&get_diag) = dlsym(handle, "get_diag");
106 *(void **)(&get_global_address) = dlsym(handle, "get_global_address");
107
108 size_t count = (*get_count)();
109
110 __cfi_slowpath(expected_call_site_type_id, (*get_global_address)());
111 EXPECT_EQ("cfi_slowpath_function_test_0002", expected_call_site_type_id, (*get_type_id)());
112 EXPECT_EQ("cfi_slowpath_function_test_0002", (*get_global_address)(), (*get_address)());
113 EXPECT_EQ("cfi_slowpath_function_test_0002", NULL, (*get_diag)());
114 EXPECT_EQ("cfi_slowpath_function_test_0002", ++count, (*get_count)());
115
116 dlclose(handle);
117 printf("["__FILE__"][Line: %d][%s]: end\n", __LINE__, __func__);
118 }
119
120 /**
121 * @tc.name : cfi_slowpath_function_test_0003
122 * @tc.desc : Loading a dso that contains __cfi_check() symbol, call the __cfi_slowpath() function with
123 * address belongs to other dso that does not enable Cross-DSO, the __cfi_check() function is
124 * not called.
125 * @tc.level : Level 1
126 */
cfi_slowpath_function_test_0003(void)127 void cfi_slowpath_function_test_0003(void)
128 {
129 printf("["__FILE__"][Line: %d][%s]: entry\n", __LINE__, __func__);
130 uint64_t expected_call_site_type_id = 30;
131 uint64_t unexpected_call_site_type_id = 40;
132 void* handle = dlopen(LIB_PATH, RTLD_LAZY);
133 EXPECT_PTRNE("cfi_slowpath_function_test_0003", handle, NULL);
134
135 *(void **)(&get_count) = dlsym(handle, "get_count");
136 *(void **)(&get_type_id) = dlsym(handle, "get_type_id");
137 *(void **)(&get_address) = dlsym(handle, "get_address");
138 *(void **)(&get_diag) = dlsym(handle, "get_diag");
139 *(void **)(&get_global_address) = dlsym(handle, "get_global_address");
140
141 __cfi_slowpath(expected_call_site_type_id, (*get_global_address)());
142 size_t count = (*get_count)();
143 __cfi_slowpath(unexpected_call_site_type_id, (void*)(&test_func));
144 EXPECT_EQ("cfi_slowpath_function_test_0003", expected_call_site_type_id, (*get_type_id)());
145 EXPECT_EQ("cfi_slowpath_function_test_0003", (*get_global_address)(), (*get_address)());
146 EXPECT_EQ("cfi_slowpath_function_test_0003", NULL, (*get_diag)());
147 EXPECT_EQ("cfi_slowpath_function_test_0003", count, (*get_count)());
148
149 dlclose(handle);
150 printf("["__FILE__"][Line: %d][%s]: end\n", __LINE__, __func__);
151 }
152
153 /**
154 * @tc.name : cfi_slowpath_function_test_0004
155 * @tc.desc : Calling __cfi_slowpath() with target_addr = NULL
156 * @tc.level : Level 2
157 */
cfi_slowpath_function_test_0004(void)158 void cfi_slowpath_function_test_0004(void)
159 {
160 printf("["__FILE__"][Line: %d][%s]: entry\n", __LINE__, __func__);
161 uint64_t call_site_type_id = 30;
162 void* handle = dlopen(LIB_PATH, RTLD_LAZY);
163 EXPECT_PTRNE("cfi_slowpath_function_test_0004", handle, NULL);
164
165 *(void **)(&get_count) = dlsym(handle, "get_count");
166
167 size_t count = (*get_count)();
168 __cfi_slowpath(call_site_type_id, NULL);
169 EXPECT_EQ("cfi_slowpath_function_test_0004", count, (*get_count)());
170
171 dlclose(handle);
172 printf("["__FILE__"][Line: %d][%s]: end\n", __LINE__, __func__);
173 }
174
175 /**
176 * @tc.name : cfi_slowpath_function_test_0005
177 * @tc.desc : Loading a dso that contains __cfi_check() symbol, call the __cfi_slowpath() function with
178 * invalid address, coredump happened.
179 * @tc.level : Level 2
180 */
cfi_slowpath_function_test_0005(void)181 void cfi_slowpath_function_test_0005(void)
182 {
183 printf("["__FILE__"][Line: %d][%s]: entry\n", __LINE__, __func__);
184 uint64_t call_site_type_id = 30;
185 void* handle = dlopen(LIB_PATH, RTLD_LAZY);
186 EXPECT_PTRNE("cfi_slowpath_function_test_0005", handle, NULL);
187
188 *(void **)(&get_count) = dlsym(handle, "get_count");
189 *(void **)(&get_type_id) = dlsym(handle, "get_type_id");
190 *(void **)(&get_address) = dlsym(handle, "get_address");
191 *(void **)(&get_diag) = dlsym(handle, "get_diag");
192 *(void **)(&get_global_address) = dlsym(handle, "get_global_address");
193
194 size_t count = (*get_count)();
195 int status;
196 pid_t pid;
197 pid = fork();
198 if (pid > 0) {
199 printf("["__FILE__"][Line: %d][%s]: parent process pid = %d\n", __LINE__, __func__, getppid());
200 wait(&status);
201 } else if (pid == 0) {
202 printf("["__FILE__"][Line: %d][%s]: child pid = %d\n", __LINE__, __func__, pid);
203 __cfi_slowpath(call_site_type_id, (void*)&count);
204 } else {
205 printf("["__FILE__"][Line: %d][%s]: fork failed!\n", __LINE__, __func__);
206 }
207 dlclose(handle);
208 printf("["__FILE__"][Line: %d][%s]: end\n", __LINE__, __func__);
209 }
210
211 /**
212 * @tc.name : cfi_slowpath_function_test_0006
213 * @tc.desc : Loading a dso which size is larger than 1 LIBRARY_ALIGNMENT(256KB), call the __cfi_slowpath()
214 * function with address in different LIBRARY_ALIGNMENT range and make sure __cfi_check() is called.
215 * @tc.level : Level 1
216 */
cfi_slowpath_function_test_0006(void)217 void cfi_slowpath_function_test_0006(void)
218 {
219 printf("["__FILE__"][Line: %d][%s]: entry\n", __LINE__, __func__);
220 uint64_t call_site_type_id = 50;
221 void* handle = dlopen(LIB_PATH, RTLD_LAZY);
222 EXPECT_PTRNE("cfi_slowpath_function_test_0006", handle, NULL);
223
224 *(void **)(&get_count) = dlsym(handle, "get_count");
225 *(void **)(&buf_check) = dlsym(handle, "buf");
226
227 size_t count = (*get_count)();
228 const size_t bss_size = 1024 * 1024;
229
230 for (size_t i = 0; i < bss_size; ++i) {
231 __cfi_slowpath(call_site_type_id, (char*)buf_check + i);
232 EXPECT_EQ("cfi_slowpath_function_test_0006", ++count, (*get_count)());
233 }
234
235 dlclose(handle);
236 printf("["__FILE__"][Line: %d][%s]: end\n", __LINE__, __func__);
237 }
238
239 /**
240 * @tc.name : cfi_slowpath_function_test_0007
241 * @tc.desc : Loading a dso 2 times
242 * @tc.level : Level 1
243 */
cfi_slowpath_function_test_0007(void)244 void cfi_slowpath_function_test_0007(void)
245 {
246 printf("["__FILE__"][Line: %d][%s]: entry\n", __LINE__, __func__);
247 uint64_t call_site_type_id1 = 10;
248 uint64_t call_site_type_id2 = 20;
249 void* handle = dlopen(LIB_PATH, RTLD_LAZY);
250 EXPECT_PTRNE("cfi_slowpath_function_test_0007", handle, NULL);
251
252 *(void **)(&get_count) = dlsym(handle, "get_count");
253 *(void **)(&get_global_address) = dlsym(handle, "get_global_address");
254 __cfi_slowpath(call_site_type_id1, (*get_global_address)());
255
256 void* handle2 = dlopen(LIB_PATH, RTLD_LAZY);
257 EXPECT_PTREQ("cfi_slowpath_function_test_0007", handle, handle2);
258 *(void **)(&get_count) = dlsym(handle2, "get_count");
259 *(void **)(&get_type_id) = dlsym(handle2, "get_type_id");
260 *(void **)(&get_address) = dlsym(handle2, "get_address");
261 *(void **)(&get_diag) = dlsym(handle2, "get_diag");
262 *(void **)(&get_global_address) = dlsym(handle2, "get_global_address");
263
264 size_t count = (*get_count)();
265 __cfi_slowpath(call_site_type_id2, (*get_global_address)());
266 EXPECT_EQ("cfi_slowpath_function_test_0007", call_site_type_id2, (*get_type_id)());
267 EXPECT_EQ("cfi_slowpath_function_test_0007", (*get_global_address)(), (*get_address)());
268 EXPECT_EQ("cfi_slowpath_function_test_0007", ++count, (*get_count)());
269
270 dlclose(handle);
271 dlclose(handle2);
272 printf("["__FILE__"][Line: %d][%s]: end\n", __LINE__, __func__);
273 }
274
275 /**
276 * @tc.name : cfi_slowpath_function_test_0008
277 * @tc.desc : Calling dso's function after unloading the dso.
278 * @tc.level : Level 1
279 */
cfi_slowpath_function_test_0008(void)280 void cfi_slowpath_function_test_0008(void)
281 {
282 printf("["__FILE__"][Line: %d][%s]: entry\n", __LINE__, __func__);
283 uint64_t call_site_type_id = 30;
284 void* handle = dlopen(LIB_PATH, RTLD_LAZY);
285 EXPECT_PTRNE("cfi_slowpath_function_test_0008", handle, NULL);
286 *(void **)(&get_global_address) = dlsym(handle, "get_global_address");
287 dlclose(handle);
288
289 int status;
290 pid_t pid;
291 pid = fork();
292 if (pid > 0) {
293 printf("["__FILE__"][Line: %d][%s]: parent process pid = %d\n", __LINE__, __func__, getppid());
294 wait(&status);
295 } else if (pid == 0) {
296 printf("["__FILE__"][Line: %d][%s]: child pid = %d\n", __LINE__, __func__, pid);
297 __cfi_slowpath(call_site_type_id, (*get_global_address)());
298 } else {
299 printf("["__FILE__"][Line: %d][%s]: fork failed!\n", __LINE__, __func__);
300 }
301 printf("["__FILE__"][Line: %d][%s]: end\n", __LINE__, __func__);
302 }
303
304 /**
305 * @tc.name : cfi_slowpath_diag_function_test_0001
306 * @tc.desc : Loading a dso that contains __cfi_check() symbol, call the __cfi_slowpath_diag() function with
307 * address inside the DSO, the __cfi_check() function is called.
308 * @tc.level : Level 1
309 */
cfi_slowpath_diag_function_test_0001(void)310 void cfi_slowpath_diag_function_test_0001(void)
311 {
312 printf("["__FILE__"][Line: %d][%s]: entry\n", __LINE__, __func__);
313 uint64_t call_site_type_id = 10;
314 uint64_t diag_info = 0;
315 void* handle = dlopen(LIB_PATH, RTLD_LAZY);
316 EXPECT_PTRNE("cfi_slowpath_diag_function_test_0001", handle, NULL);
317
318 *(void **)(&get_count) = dlsym(handle, "get_count");
319 *(void **)(&get_type_id) = dlsym(handle, "get_type_id");
320 *(void **)(&get_diag) = dlsym(handle, "get_diag");
321 *(void **)(&get_global_address) = dlsym(handle, "get_global_address");
322
323 size_t count = (*get_count)();
324
325 __cfi_slowpath_diag(call_site_type_id, NULL, &diag_info);
326 EXPECT_EQ("cfi_slowpath_diag_function_test_0001", count, (*get_count)());
327
328 __cfi_slowpath_diag(call_site_type_id, (*get_global_address)(), &diag_info);
329 EXPECT_EQ("cfi_slowpath_diag_function_test_0001", ++count, (*get_count)());
330 EXPECT_EQ("cfi_slowpath_diag_function_test_0001", call_site_type_id, (*get_type_id)());
331 EXPECT_EQ("cfi_slowpath_diag_function_test_0001", (*get_diag)(), &diag_info);
332
333 dlclose(handle);
334 printf("["__FILE__"][Line: %d][%s]: end\n", __LINE__, __func__);
335 }
336
337 /**
338 * @tc.name : cfi_unmap_dso_from_cfi_shadow_001
339 * @tc.desc : If dso map is NULL while unmapping from the CFI shadow, do nothing.
340 * @tc.level : Level 2
341 */
cfi_unmap_dso_from_cfi_shadow_001(void)342 void cfi_unmap_dso_from_cfi_shadow_001(void)
343 {
344 printf("["__FILE__"][Line: %d][%s]: entry\n", __LINE__, __func__);
345 struct dso test_dso = {};
346 test_dso.map = 0;
347 test_dso.map_len = 1;
348 unmap_dso_from_cfi_shadow(&test_dso);
349 printf("["__FILE__"][Line: %d][%s]: end\n", __LINE__, __func__);
350 }
351
352 /**
353 * @tc.name : cfi_unmap_dso_from_cfi_shadow_002
354 * @tc.desc : If dso map_len is NULL while unmapping from the CFI shadow, do nothing.
355 * @tc.level : Level 2
356 */
cfi_unmap_dso_from_cfi_shadow_002(void)357 void cfi_unmap_dso_from_cfi_shadow_002(void)
358 {
359 printf("["__FILE__"][Line: %d][%s]: entry\n", __LINE__, __func__);
360 struct dso test_dso = {};
361 unsigned char a = 'S';
362 test_dso.map = &a;
363 test_dso.map_len = 0;
364 unmap_dso_from_cfi_shadow(&test_dso);
365 printf("["__FILE__"][Line: %d][%s]: end\n", __LINE__, __func__);
366 }
367
368 TEST_FUN G_Fun_Array[] = {
369 cfi_init_test_0001,
370 cfi_init_test_0002,
371 cfi_init_test_0003,
372 cfi_slowpath_function_test_0002,
373 cfi_slowpath_function_test_0003,
374 cfi_slowpath_function_test_0004,
375 cfi_slowpath_function_test_0005,
376 cfi_slowpath_function_test_0006,
377 cfi_slowpath_function_test_0007,
378 cfi_slowpath_function_test_0008,
379 cfi_slowpath_diag_function_test_0001,
380 cfi_unmap_dso_from_cfi_shadow_001,
381 cfi_unmap_dso_from_cfi_shadow_002,
382 };
383
main(void)384 int main(void)
385 {
386 printf("["__FILE__"][Line: %d][%s]: entry\n", __LINE__, __func__);
387 int num = sizeof(G_Fun_Array) / sizeof(TEST_FUN);
388 for (int pos = 0; pos < num; ++pos) {
389 G_Fun_Array[pos]();
390 }
391 printf("["__FILE__"][Line: %d][%s]: end\n", __LINE__, __func__);
392 return 0;
393 }
394