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