1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2024-2025. All rights reserved.
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 <iostream>
17 #include <securec.h>
18 #include <string>
19 #include <sys/wait.h>
20 #include <unistd.h>
21 #include "napi/native_api.h"
22
23 constexpr int MAX_BUFFER_SIZE = 128;
24 constexpr const char *HWASAN_LOG_FILE_PATH = "/data/storage/el2/log/hwasanXtsLog.appspawn";
25 const int NUMBERTEN = 10;
26 const int NUMBERELEVEN = 11;
27 const int NUMBERTWELVE = 12;
28
GetBuffer(int pid)29 static std::string GetBuffer(int pid)
30 {
31 std::string buffer;
32 char file[MAX_BUFFER_SIZE];
33 int filePathRes = snprintf_s(file, sizeof(file), sizeof(file) - 1, "%s.%d", HWASAN_LOG_FILE_PATH, pid);
34 if (filePathRes < 0) {
35 return buffer;
36 }
37 FILE *fp = fopen(file, "r+");
38 if (!fp) {
39 return buffer;
40 }
41 if (fseek(fp, 0, SEEK_END) == -1) {
42 return buffer;
43 }
44 int size = ftell(fp);
45 if (size <= 0) {
46 ftruncate(fileno(fp), 0);
47 rewind(fp);
48 fclose(fp);
49 return buffer;
50 }
51 buffer.resize(size);
52 if (fseek(fp, 0, SEEK_SET) == -1) {
53 ftruncate(fileno(fp), 0);
54 rewind(fp);
55 fclose(fp);
56 return buffer;
57 }
58 int rsize = fread(&buffer[0], 1, size, fp);
59 if (rsize == 0) {
60 ftruncate(fileno(fp), 0);
61 rewind(fp);
62 fclose(fp);
63 return buffer;
64 }
65 ftruncate(fileno(fp), 0);
66 rewind(fp);
67 fclose(fp);
68 return buffer;
69 }
70
CheckHWAsanLog(const std::string & errType,const std::string & buffer)71 static bool CheckHWAsanLog(const std::string& errType, const std::string& buffer)
72 {
73 if (buffer.empty()) {
74 return false;
75 }
76 bool checkEventTypeFail = buffer.find(errType.c_str()) == std::string::npos;
77 if (checkEventTypeFail) {
78 return false;
79 }
80 return true;
81 }
82
StackBufferOverflow(napi_env env,napi_callback_info info)83 __attribute__((optnone)) static napi_value StackBufferOverflow(napi_env env, napi_callback_info info)
84 {
85 int status;
86 int pid = fork();
87 int checkRes = 0;
88 if (pid == -1) {
89 napi_value result = nullptr;
90 napi_create_int32(env, checkRes, &result);
91 } else if (pid == 0) {
92 int a[NUMBERTEN];
93 a[NUMBERELEVEN] = 1;
94 } else {
95 wait(&status);
96 }
97 std::string bufferLog = GetBuffer(pid);
98 bool findHWAsanLog = CheckHWAsanLog("HWAddressSanitizer: tag-mismatch", bufferLog) &&
99 CheckHWAsanLog("WRITE of size 4", bufferLog) &&
100 CheckHWAsanLog("stack of thread", bufferLog) &&
101 CheckHWAsanLog("[08]", bufferLog);
102 checkRes = findHWAsanLog ? 1 : 0;
103 napi_value result = nullptr;
104 napi_create_int32(env, checkRes, &result);
105 return result;
106 }
107
StackBufferUnderflow(napi_env env,napi_callback_info info)108 __attribute__((optnone)) static napi_value StackBufferUnderflow(napi_env env, napi_callback_info info)
109 {
110 int status;
111 int pid = fork();
112 int checkRes = 0;
113 if (pid == -1) {
114 napi_value result = nullptr;
115 napi_create_int32(env, checkRes, &result);
116 } else if (pid == 0) {
117 int a[10];
118 a[-1] = 1;
119 } else {
120 wait(&status);
121 }
122 std::string bufferLog = GetBuffer(pid);
123 bool findHWAsanLog = CheckHWAsanLog("HWAddressSanitizer: tag-mismatch", bufferLog) &&
124 CheckHWAsanLog("WRITE of size 4", bufferLog) &&
125 CheckHWAsanLog("stack of thread", bufferLog) &&
126 CheckHWAsanLog("[08]", bufferLog);
127 checkRes = findHWAsanLog ? 1 : 0;
128 napi_value result = nullptr;
129 napi_create_int32(env, checkRes, &result);
130 return result;
131 }
132
HeapBufferOverflow(napi_env env,napi_callback_info info)133 __attribute__((optnone)) static napi_value HeapBufferOverflow(napi_env env, napi_callback_info info)
134 {
135 int status;
136 int pid = fork();
137 int checkRes = 0;
138 if (pid == -1) {
139 napi_value result = nullptr;
140 napi_create_int32(env, checkRes, &result);
141 } else if (pid == 0) {
142 char *buffer = (char *)malloc(NUMBERTEN);
143 *(buffer + NUMBERTWELVE) = 'n';
144 free(buffer);
145 } else {
146 wait(&status);
147 }
148 std::string bufferLog = GetBuffer(pid);
149 bool findHWAsanLog = CheckHWAsanLog("HWAddressSanitizer: tag-mismatch", bufferLog) &&
150 CheckHWAsanLog("WRITE of size 1", bufferLog) &&
151 CheckHWAsanLog("heap-buffer-overflow", bufferLog) &&
152 CheckHWAsanLog("[0a]", bufferLog);
153 checkRes = findHWAsanLog ? 1 : 0;
154 napi_value result = nullptr;
155 napi_create_int32(env, checkRes, &result);
156 return result;
157 }
158
HeapBufferUnderflow(napi_env env,napi_callback_info info)159 __attribute__((optnone)) static napi_value HeapBufferUnderflow(napi_env env, napi_callback_info info)
160 {
161 int status;
162 int pid = fork();
163 int checkRes = 0;
164 if (pid == -1) {
165 napi_value result = nullptr;
166 napi_create_int32(env, checkRes, &result);
167 } else if (pid == 0) {
168 char *x = (char*)malloc(NUMBERTEN * sizeof(char));
169 memset_s(x, NUMBERTEN * sizeof(char), 0, NUMBERTEN * sizeof(char));
170 int res = x[-1];
171 free(x);
172 } else {
173 wait(&status);
174 }
175 std::string bufferLog = GetBuffer(pid);
176 bool findHWAsanLog = CheckHWAsanLog("HWAddressSanitizer: tag-mismatch", bufferLog) &&
177 CheckHWAsanLog("READ of size 1", bufferLog) &&
178 CheckHWAsanLog("heap-buffer-overflow", bufferLog);
179 checkRes = findHWAsanLog ? 1 : 0;
180 napi_value result = nullptr;
181 napi_create_int32(env, checkRes, &result);
182 return result;
183 }
184
HeapUseAfterFree(napi_env env,napi_callback_info info)185 __attribute__((optnone)) static napi_value HeapUseAfterFree(napi_env env, napi_callback_info info)
186 {
187 int status;
188 int pid = fork();
189 int checkRes = 0;
190 if (pid == -1) {
191 napi_value result = nullptr;
192 napi_create_int32(env, checkRes, &result);
193 } else if (pid == 0) {
194 char *x = (char*)malloc(10 * sizeof(char));
195 free(x);
196 char tmp = x[5];
197 } else {
198 wait(&status);
199 }
200 std::string bufferLog = GetBuffer(pid);
201 bool findHWAsanLog = CheckHWAsanLog("HWAddressSanitizer: tag-mismatch", bufferLog) &&
202 CheckHWAsanLog("use-after-free", bufferLog) &&
203 CheckHWAsanLog("READ of size 1", bufferLog) &&
204 CheckHWAsanLog("freed by thread", bufferLog);
205 checkRes = findHWAsanLog ? 1 : 0;
206 napi_value result = nullptr;
207 napi_create_int32(env, checkRes, &result);
208 return result;
209 }
210
GetLocalPointer()211 __attribute__((optnone)) int* GetLocalPointer()
212 {
213 int num = 10;
214 return #
215 }
216
StackUseAfterScope(napi_env env,napi_callback_info info)217 __attribute__((optnone)) static napi_value StackUseAfterScope(napi_env env, napi_callback_info info)
218 {
219 int status;
220 int pid = fork();
221 int checkRes = 0;
222 if (pid == -1) {
223 napi_value result = nullptr;
224 napi_create_int32(env, checkRes, &result);
225 } else if (pid == 0) {
226 int* ptr = GetLocalPointer();
227 std::cout << *ptr << std::endl;
228 } else {
229 wait(&status);
230 }
231 std::string bufferLog = GetBuffer(pid);
232 bool findHWAsanLog = CheckHWAsanLog("HWAddressSanitizer: tag-mismatch", bufferLog) &&
233 CheckHWAsanLog("stack of thread", bufferLog) &&
234 CheckHWAsanLog("READ of size 4", bufferLog) &&
235 CheckHWAsanLog("[00]", bufferLog);
236 checkRes = findHWAsanLog ? 1 : 0;
237 napi_value result = nullptr;
238 napi_create_int32(env, checkRes, &result);
239 return result;
240 }
241
Fun()242 __attribute__((optnone)) int* Fun()
243 {
244 int a = 3;
245 return &a;
246 }
StackUseAfterReturn(napi_env env,napi_callback_info info)247 __attribute__((optnone)) static napi_value StackUseAfterReturn(napi_env env, napi_callback_info info)
248 {
249 int status;
250 int pid = fork();
251 int checkRes = 0;
252 if (pid == -1) {
253 napi_value result = nullptr;
254 napi_create_int32(env, checkRes, &result);
255 } else if (pid == 0) {
256 int* p = Fun();
257 int c = *p;
258 } else {
259 wait(&status);
260 }
261 std::string bufferLog = GetBuffer(pid);
262 bool findHWAsanLog = CheckHWAsanLog("HWAddressSanitizer: tag-mismatch", bufferLog) &&
263 CheckHWAsanLog("stack of thread", bufferLog) &&
264 CheckHWAsanLog("READ of size 4", bufferLog) &&
265 CheckHWAsanLog("[00]", bufferLog);
266 checkRes = findHWAsanLog ? 1 : 0;
267 napi_value result = nullptr;
268 napi_create_int32(env, checkRes, &result);
269 return result;
270 }
271
DoubleFree(napi_env env,napi_callback_info info)272 __attribute__((optnone)) static napi_value DoubleFree(napi_env env, napi_callback_info info)
273 {
274 char *x = (char*)malloc(NUMBERTEN * sizeof(char));
275 memset_s(x, NUMBERTEN * sizeof(char), 0, NUMBERTEN * sizeof(char));
276 free(x);
277 free(x);
278 std::string bufferLog = GetBuffer(getpid());
279 bool findHWAsanLog = CheckHWAsanLog("HWAddressSanitizer: invalid-free", bufferLog) &&
280 CheckHWAsanLog("use-after-free", bufferLog) &&
281 CheckHWAsanLog("freed by thread", bufferLog);
282 int checkRes = findHWAsanLog ? 1 : 0;
283 napi_value result = nullptr;
284 napi_create_int32(env, checkRes, &result);
285 return result;
286 }
287
WildFree(napi_env env,napi_callback_info info)288 __attribute__((optnone)) static napi_value WildFree(napi_env env, napi_callback_info info)
289 {
290 int* ptr = new int(1);
291 delete ptr;
292 delete ptr;
293 std::string bufferLog = GetBuffer(getpid());
294 bool findHWAsanLog = CheckHWAsanLog("HWAddressSanitizer: invalid-free", bufferLog) &&
295 CheckHWAsanLog("use-after-free", bufferLog) &&
296 CheckHWAsanLog("freed by thread", bufferLog);
297 int checkRes = findHWAsanLog ? 1 : 0;
298 napi_value result = nullptr;
299 napi_create_int32(env, checkRes, &result);
300 return result;
301 }
302
303 EXTERN_C_START
Init(napi_env env,napi_value exports)304 static napi_value Init(napi_env env, napi_value exports)
305 {
306 napi_property_descriptor desc[] = {
307 { "stackBufferOverflow", nullptr, StackBufferOverflow, nullptr, nullptr, nullptr, napi_default, nullptr },
308 { "stackBufferUnderflow", nullptr, StackBufferUnderflow, nullptr, nullptr, nullptr, napi_default, nullptr },
309 { "heapBufferOverflow", nullptr, HeapBufferOverflow, nullptr, nullptr, nullptr, napi_default, nullptr },
310 { "heapBufferUnderflow", nullptr, HeapBufferUnderflow, nullptr, nullptr, nullptr, napi_default, nullptr },
311 { "heapUseAfterFree", nullptr, HeapUseAfterFree, nullptr, nullptr, nullptr, napi_default, nullptr },
312 { "stackUseAfterScope", nullptr, StackUseAfterScope, nullptr, nullptr, nullptr, napi_default, nullptr },
313 { "stackUseAfterReturn", nullptr, StackUseAfterReturn, nullptr, nullptr, nullptr, napi_default, nullptr },
314 { "doubleFree", nullptr, DoubleFree, nullptr, nullptr, nullptr, napi_default, nullptr },
315 { "wildFree", nullptr, WildFree, nullptr, nullptr, nullptr, napi_default, nullptr }
316 };
317 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
318 return exports;
319 }
320 EXTERN_C_END
321
322 static napi_module demoModule = {
323 .nm_version = 1,
324 .nm_flags = 0,
325 .nm_filename = nullptr,
326 .nm_register_func = Init,
327 .nm_modname = "entry",
328 .nm_priv = ((void*)0),
329 .reserved = { 0 },
330 };
331
RegisterEntryModule(void)332 extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
333 {
334 napi_module_register(&demoModule);
335 }
336