1 #include <dlfcn.h>
2 #include <gtest/gtest.h>
3 #include <stdint.h>
4 #include <stdlib.h>
5
6 #include "libs/ldso_gtest_util.h"
7
8 #define LIB_PATH "/data/tmp/libcgtest/libs/libldso_cfi_lib.so"
9 #define TYPE_ID_1 1
10 #define TYPE_ID_2 2
11 #define TYPE_ID_3 3
12 #define TYPE_ID_4 4
13 #define TYPE_ID_5 5
14
15 using namespace std;
16 using namespace testing::ext;
17 class LdsoCfiTest : public testing::Test {
SetUp()18 void SetUp() override {}
TearDown()19 void TearDown() override {}
20 };
21
22 struct dso {
23 char* mock;
24 unsigned char* map;
25 size_t len;
26 };
27
28 extern "C" int init_cfi_shadow(struct dso* dso_list, struct dso* ldso);
29 extern "C" int map_dso_to_cfi_shadow(struct dso* dso);
30 extern "C" void unmap_dso_from_cfi_shadow(struct dso* dso);
31 extern "C" void __cfi_slowpath(uint64_t CallSiteTypeId, void* Ptr);
32 extern "C" void __cfi_slowpath_diag(uint64_t CallSiteTypeId, void* Ptr, void* DiagData);
33
34 typedef void (*FuncTypeRetVoid)();
35 typedef void* (*FuncTypeRetVoidPtr)();
36 typedef char* (*FuncTypeRetCharPtr)();
37 typedef size_t (*FuncTypeRetSize)();
38 typedef uint64_t (*FuncTypeRetUint64)();
39
TestFunc()40 static void TestFunc() {}
41
ExitBySig(int status)42 static bool ExitBySig(int status)
43 {
44 return WIFSIGNALED(status) &&
45 (WTERMSIG(status) == SIGTRAP || WTERMSIG(status) == SIGILL || WTERMSIG(status) == SIGSEGV);
46 }
47
48 /**
49 * @tc.name: __cfi_slowpath_001
50 * @tc.desc: Load a so twice and verify it can be mapped to cfi shadow successfully.
51 * @tc.type: FUNC
52 */
53 HWTEST_F(LdsoCfiTest, __cfi_slowpath_001, TestSize.Level1)
54 {
55 uint64_t callSiteTypeId1 = TYPE_ID_1;
56 uint64_t callSiteTypeId2 = TYPE_ID_2;
57 void* handle = dlopen(LIB_PATH, RTLD_NOW);
58 ASSERT_NE(handle, nullptr);
59
60 FuncTypeRetVoidPtr globalAddress = reinterpret_cast<FuncTypeRetVoidPtr>(dlsym(handle, "GetGlobalAddress"));
61 ASSERT_NE(globalAddress, nullptr);
62 __cfi_slowpath(callSiteTypeId1, (*globalAddress)());
63
64 void* handle2 = dlopen(LIB_PATH, RTLD_NOW);
65 ASSERT_EQ(handle, handle2);
66 FuncTypeRetSize getCount = reinterpret_cast<FuncTypeRetSize>(dlsym(handle2, "GetCount"));
67 ASSERT_NE(getCount, nullptr);
68 FuncTypeRetUint64 getTypeId = reinterpret_cast<FuncTypeRetUint64>(dlsym(handle2, "GetTypeId"));
69 ASSERT_NE(getTypeId, nullptr);
70 FuncTypeRetVoidPtr getAddress = reinterpret_cast<FuncTypeRetVoidPtr>(dlsym(handle2, "GetAddress"));
71 ASSERT_NE(getAddress, nullptr);
72 globalAddress = reinterpret_cast<FuncTypeRetVoidPtr>(dlsym(handle2, "GetGlobalAddress"));
73 ASSERT_NE(globalAddress, nullptr);
74
75 size_t count = (*getCount)();
76 __cfi_slowpath(callSiteTypeId2, (*globalAddress)());
77 EXPECT_EQ(callSiteTypeId2, (*getTypeId)());
78 EXPECT_EQ((*globalAddress)(), (*getAddress)());
79 EXPECT_EQ(++count, (*getCount)());
80
81 dlclose(handle);
82 dlclose(handle2);
83 }
84
85 /**
86 * @tc.name: __cfi_slowpath_002
87 * @tc.desc: Loading a so that contains __cfi_check() symbol, call the __cfi_slowpath() function with address inside
88 * the DSO, the __cfi_check() function is called.
89 * @tc.type: FUNC
90 */
91 HWTEST_F(LdsoCfiTest, __cfi_slowpath_002, TestSize.Level1)
92 {
93 uint64_t expectedCallSiteTypeId = TYPE_ID_2;
94 void* handle = dlopen(LIB_PATH, RTLD_NOW);
95 ASSERT_NE(handle, nullptr);
96
97 FuncTypeRetSize getCount = reinterpret_cast<FuncTypeRetSize>(dlsym(handle, "GetCount"));
98 ASSERT_NE(getCount, nullptr);
99 FuncTypeRetUint64 getTypeId = reinterpret_cast<FuncTypeRetUint64>(dlsym(handle, "GetTypeId"));
100 ASSERT_NE(getTypeId, nullptr);
101 FuncTypeRetVoidPtr getAddress = reinterpret_cast<FuncTypeRetVoidPtr>(dlsym(handle, "GetAddress"));
102 ASSERT_NE(getAddress, nullptr);
103 FuncTypeRetVoidPtr getDiag = reinterpret_cast<FuncTypeRetVoidPtr>(dlsym(handle, "GetDiag"));
104 ASSERT_NE(getDiag, nullptr);
105 FuncTypeRetVoidPtr globalAddress = reinterpret_cast<FuncTypeRetVoidPtr>(dlsym(handle, "GetGlobalAddress"));
106 ASSERT_NE(globalAddress, nullptr);
107
108 size_t count = (*getCount)();
109
110 __cfi_slowpath(expectedCallSiteTypeId, (*globalAddress)());
111 EXPECT_EQ(expectedCallSiteTypeId, (*getTypeId)());
112 EXPECT_EQ((*globalAddress)(), (*getAddress)());
113 EXPECT_EQ(nullptr, (*getDiag)());
114 EXPECT_EQ(++count, (*getCount)());
115
116 dlclose(handle);
117 }
118
119 /**
120 * @tc.name: __cfi_slowpath_003
121 * @tc.desc: load a so that contains the __cfi_check() symbol and call the __cfi_slowpath() function whose address
122 * belongs to another so that is not Cross so enabled and the cfi_check function will not called.
123 * @tc.type: FUNC
124 */
125 HWTEST_F(LdsoCfiTest, __cfi_slowpath_003, TestSize.Level1)
126 {
127 uint64_t expectedCallSiteTypeId = TYPE_ID_3;
128 uint64_t unexpectedCallSiteTypeId = TYPE_ID_4;
129 void* handle = dlopen(LIB_PATH, RTLD_NOW);
130 ASSERT_NE(handle, nullptr);
131
132 FuncTypeRetSize getCount = reinterpret_cast<FuncTypeRetSize>(dlsym(handle, "GetCount"));
133 ASSERT_NE(getCount, nullptr);
134 FuncTypeRetVoidPtr globalAddress = reinterpret_cast<FuncTypeRetVoidPtr>(dlsym(handle, "GetGlobalAddress"));
135 ASSERT_NE(globalAddress, nullptr);
136
137 __cfi_slowpath(expectedCallSiteTypeId, (*globalAddress)());
138 size_t count = (*getCount)();
139 __cfi_slowpath(unexpectedCallSiteTypeId, reinterpret_cast<void*>(&TestFunc));
140
141 EXPECT_EQ(count, (*getCount)());
142 dlclose(handle);
143 }
144
145 /**
146 * @tc.name: __cfi_slowpath_004
147 * @tc.desc: Call __cfi_slowpath() with nullptr addr and verify the cfi_check function will not called.
148 * @tc.type: FUNC
149 */
150 HWTEST_F(LdsoCfiTest, __cfi_slowpath_004, TestSize.Level1)
151 {
152 uint64_t callSiteTypeId = TYPE_ID_3;
153 void* handle = dlopen(LIB_PATH, RTLD_NOW);
154 ASSERT_NE(handle, nullptr);
155
156 FuncTypeRetSize getCount = reinterpret_cast<FuncTypeRetSize>(dlsym(handle, "GetCount"));
157 ASSERT_NE(getCount, nullptr);
158
159 size_t count = (*getCount)();
160 __cfi_slowpath(callSiteTypeId, nullptr);
161 EXPECT_EQ(count, (*getCount)());
162
163 dlclose(handle);
164 }
165
166 /**
167 * @tc.name: __cfi_slowpath_005
168 * @tc.desc: passing a invalid address to the slowpath() function expect Call__ Cfi_ Coredump occurs.
169 * @tc.type: FUNC
170 */
171 HWTEST_F(LdsoCfiTest, __cfi_slowpath_005, TestSize.Level1)
172 {
173 uint64_t callSiteTypeId = TYPE_ID_3;
174 void* handle = dlopen(LIB_PATH, RTLD_NOW);
175 ASSERT_NE(handle, nullptr);
176
177 FuncTypeRetSize getCount = reinterpret_cast<FuncTypeRetSize>(dlsym(handle, "GetCount"));
178 ASSERT_NE(getCount, nullptr);
179
180 size_t count = (*getCount)();
181 EXPECT_EXIT(__cfi_slowpath(callSiteTypeId, static_cast<void*>(&count)), ExitBySig, "");
182
183 dlclose(handle);
184 }
185
186 /**
187 * @tc.name: __cfi_slowpath_006
188 * @tc.desc: close handle then call the cfi_slowpath and the cfi_slowpath will be killed by signal.
189 * @tc.type: FUNC
190 */
191 HWTEST_F(LdsoCfiTest, __cfi_slowpath_006, TestSize.Level1)
192 {
193 uint64_t callSiteTypeId = TYPE_ID_3;
194 void* handle = dlopen(LIB_PATH, RTLD_NOW);
195 ASSERT_NE(handle, nullptr);
196 FuncTypeRetVoidPtr globalAddress = reinterpret_cast<FuncTypeRetVoidPtr>(dlsym(handle, "GetGlobalAddress"));
197 ASSERT_NE(globalAddress, nullptr);
198 dlclose(handle);
199
200 EXPECT_EXIT(__cfi_slowpath(callSiteTypeId, (*globalAddress)()), ExitBySig, "");
201 }
202
203 /**
204 * @tc.name: __cfi_slowpath_007
205 * @tc.desc: Load a so greater than 1 LIBRARY_ALIGNMENT, call the __cfi_slowpath() function in a different
206 * LIBRARY_ALIGNMENT range, and verify that __cfi_check() is called.
207 * @tc.type: FUNC
208 */
209 HWTEST_F(LdsoCfiTest, __cfi_slowpath_007, TestSize.Level1)
210 {
211 uint64_t callSiteTypeId = TYPE_ID_5;
212 void* handle = dlopen(LIB_PATH, RTLD_NOW);
213 ASSERT_NE(handle, nullptr);
214
215 FuncTypeRetSize getCount = reinterpret_cast<FuncTypeRetSize>(dlsym(handle, "GetCount"));
216 ASSERT_NE(getCount, nullptr);
217 FuncTypeRetCharPtr bufCheck = reinterpret_cast<FuncTypeRetCharPtr>(dlsym(handle, "g_buf"));
218 ASSERT_NE(bufCheck, nullptr);
219
220 size_t count = (*getCount)();
221 const size_t size = SIZE_1024_SQUARE;
222
223 for (size_t i = 0; i < size; ++i) {
224 __cfi_slowpath(callSiteTypeId, reinterpret_cast<char*>(bufCheck) + i);
225 EXPECT_EQ(++count, (*getCount)());
226 }
227
228 dlclose(handle);
229 }
230
231 /**
232 * @tc.name: __cfi_slowpath_diag_function_test_001
233 * @tc.desc: Loading with The so file of the __cfi_check() symbol calls the internal address of the so file__
234 * cfi_slowpath_ The diag() function__cfi_the check() function is called.
235 * @tc.type: FUNC
236 */
237 HWTEST_F(LdsoCfiTest, __cfi_slowpath_diag_function_test_001, TestSize.Level1)
238 {
239 uint64_t callSiteTypeId = TYPE_ID_1;
240 uint64_t diagInfo = 0;
241 void* handle = dlopen(LIB_PATH, RTLD_NOW);
242 ASSERT_NE(handle, nullptr);
243
244 FuncTypeRetSize getCount = reinterpret_cast<FuncTypeRetSize>(dlsym(handle, "GetCount"));
245 ASSERT_NE(getCount, nullptr);
246 FuncTypeRetUint64 getTypeId = reinterpret_cast<FuncTypeRetUint64>(dlsym(handle, "GetTypeId"));
247 ASSERT_NE(getTypeId, nullptr);
248 FuncTypeRetVoidPtr getDiag = reinterpret_cast<FuncTypeRetVoidPtr>(dlsym(handle, "GetDiag"));
249 ASSERT_NE(getDiag, nullptr);
250 FuncTypeRetVoidPtr globalAddress = reinterpret_cast<FuncTypeRetVoidPtr>(dlsym(handle, "GetGlobalAddress"));
251 ASSERT_NE(globalAddress, nullptr);
252
253 size_t count = (*getCount)();
254 __cfi_slowpath_diag(callSiteTypeId, nullptr, &diagInfo);
255 EXPECT_EQ(count, (*getCount)());
256
257 __cfi_slowpath_diag(callSiteTypeId, (*globalAddress)(), &diagInfo);
258 EXPECT_EQ(++count, (*getCount)());
259 EXPECT_EQ(callSiteTypeId, (*getTypeId)());
260 EXPECT_EQ((*getDiag)(), &diagInfo);
261
262 dlclose(handle);
263 }
264
265 /**
266 * @tc.name: map_dso_to_cfi_shadow_001
267 * @tc.desc: If so is nullptr while mapping to the CFI shadow, do nothing and return true.
268 * @tc.type: FUNC
269 */
270 HWTEST_F(LdsoCfiTest, map_dso_to_cfi_shadow_001, TestSize.Level1)
271 {
272 EXPECT_EQ(map_dso_to_cfi_shadow(nullptr), 0);
273 }
274
275 /**
276 * @tc.name: cfi_init_test_001
277 * @tc.desc: check all args is null when initializing the CFI shadow. do nothing and return true.
278 * @tc.type: FUNC
279 */
280 HWTEST_F(LdsoCfiTest, cfi_init_test_001, TestSize.Level1)
281 {
282 EXPECT_EQ(init_cfi_shadow(nullptr, nullptr), 0);
283 }
284
285 /**
286 * @tc.name: unmap_dso_to_cfi_shadow_001
287 * @tc.desc: If so is nullptr while unmapping from the CFI shadow the program can be run success.
288 * @tc.type: FUNC
289 */
290 HWTEST_F(LdsoCfiTest, unmap_dso_to_cfi_shadow_001, TestSize.Level1)
291 {
292 unmap_dso_from_cfi_shadow(nullptr);
293 SUCCEED();
294 }
295