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 <securec.h>
17 #include <string>
18 #include <stdio.h>
19 #include <unistd.h>
20 #include <dirent.h>
21 #include "napi/native_api.h"
22
23 constexpr int MAX_BUFFER_SIZE = 128;
24 const int NUMFIVE = 5;
25 const int NUMTEN = 10;
26 const int NUMELEVEN = 11;
27 const int NUMTWELVE = 12;
28 const int NUMNEGATIVEONE = -1;
29
FindDirAndCheck(DIR * dir,char * fileResult,int pid)30 static int FindDirAndCheck(DIR *dir, char *fileResult, int pid)
31 {
32 struct dirent *ptr;
33 char file[MAX_BUFFER_SIZE];
34 int filenameres = snprintf_s(file, sizeof(file), sizeof(file) - 1, "%s.%d", "asanXtsLog", pid);
35 if (filenameres < 0) {
36 return -1;
37 }
38 while((ptr = readdir(dir)) != NULL) {
39 if (strstr(ptr->d_name, file) != NULL) {
40 int findRes = snprintf_s(fileResult, MAX_BUFFER_SIZE, MAX_BUFFER_SIZE - 1, "%s/%s",
41 "/data/storage/el2/log/", ptr->d_name);
42 if (findRes < 0) {
43 return -1;
44 }
45 return 1;
46 }
47 }
48 return -1;
49 }
50
GetBuffer(int pid)51 static std::string GetBuffer(int pid)
52 {
53 std::string buffer;
54 char file[MAX_BUFFER_SIZE];
55 DIR *logdir = opendir("/data/storage/el2/log/");
56 int findRes = FindDirAndCheck(logdir, file, pid);
57 if (findRes < 0) {
58 return buffer;
59 }
60 FILE *fp = fopen(file, "r+");
61 if (!fp) {
62 return buffer;
63 }
64 if (fseek(fp, 0, SEEK_END) == -1) {
65 return buffer;
66 }
67 int size = ftell(fp);
68 if (size <= 0) {
69 ftruncate(fileno(fp), 0);
70 rewind(fp);
71 fclose(fp);
72 return buffer;
73 }
74 buffer.resize(size);
75 if (fseek(fp, 0, SEEK_SET) == -1) {
76 ftruncate(fileno(fp), 0);
77 rewind(fp);
78 fclose(fp);
79 return buffer;
80 }
81 int rsize = fread(&buffer[0], 1, size, fp);
82 if (rsize == 0) {
83 ftruncate(fileno(fp), 0);
84 rewind(fp);
85 fclose(fp);
86 return buffer;
87 }
88 ftruncate(fileno(fp), 0);
89 rewind(fp);
90 fclose(fp);
91 remove(file);
92 return buffer;
93 }
94
CheckAsanLog(const std::string & errType,const std::string & buffer)95 static bool CheckAsanLog(const std::string& errType, const std::string& buffer)
96 {
97 if (buffer.empty()) {
98 return false;
99 }
100 bool checkEventTypeFail = buffer.find(errType.c_str()) == std::string::npos;
101 if (checkEventTypeFail) {
102 return false;
103 }
104 return true;
105 }
106
StackBufferOverflow(napi_env env,napi_callback_info info)107 __attribute__((optnone)) static napi_value StackBufferOverflow(napi_env env, napi_callback_info info)
108 {
109 int a[NUMTEN];
110 a[NUMELEVEN] = 1;
111 std::string bufferLog = GetBuffer(getpid());
112 bool findAsanLog = CheckAsanLog("AddressSanitizer: stack-buffer-overflow", bufferLog) &&
113 CheckAsanLog("WRITE of size 4", bufferLog) &&
114 CheckAsanLog("thread T0", bufferLog) &&
115 CheckAsanLog("'a' (line 108)", bufferLog) &&
116 CheckAsanLog("[f2]", bufferLog);
117 int checkRes = findAsanLog ? 1 : 0;
118 napi_value result = nullptr;
119 napi_create_int32(env, checkRes, &result);
120 return result;
121 }
122
StackBufferUnderflow(napi_env env,napi_callback_info info)123 __attribute__((optnone)) static napi_value StackBufferUnderflow(napi_env env, napi_callback_info info)
124 {
125 int a[NUMTEN];
126 a[NUMNEGATIVEONE] = 1;
127 std::string bufferLog = GetBuffer(getpid());
128 bool findAsanLog = CheckAsanLog("AddressSanitizer: stack-buffer-underflow", bufferLog) &&
129 CheckAsanLog("WRITE of size 4", bufferLog) &&
130 CheckAsanLog("thread T0", bufferLog) &&
131 CheckAsanLog("'a' (line 124)", bufferLog) &&
132 CheckAsanLog("[f1]", bufferLog);
133 int checkRes = findAsanLog ? 1 : 0;
134 napi_value result = nullptr;
135 napi_create_int32(env, findAsanLog, &result);
136 return result;
137 }
138
HeapBufferOverflow(napi_env env,napi_callback_info info)139 __attribute__((optnone)) static napi_value HeapBufferOverflow(napi_env env, napi_callback_info info)
140 {
141 char *buffer = (char *)malloc(NUMTEN);
142 if (buffer != nullptr) {
143 *(buffer + NUMTWELVE) = 'n';
144 }
145 free(buffer);
146 std::string bufferLog = GetBuffer(getpid());
147 bool findAsanLog = CheckAsanLog("AddressSanitizer: heap-buffer-overflow", bufferLog) &&
148 CheckAsanLog("WRITE of size 1", bufferLog) &&
149 CheckAsanLog("thread T0", bufferLog) &&
150 CheckAsanLog("[02]", bufferLog);
151 int checkRes = findAsanLog ? 1 : 0;
152 napi_value result = nullptr;
153 napi_create_int32(env, findAsanLog, &result);
154 return result;
155 }
156
HeapBufferUnderflow(napi_env env,napi_callback_info info)157 __attribute__((optnone)) static napi_value HeapBufferUnderflow(napi_env env, napi_callback_info info)
158 {
159 char *x = (char*)malloc(NUMTEN * sizeof(char));
160 memset_s(x, NUMTEN * sizeof(char), 0, NUMTEN * sizeof(char));
161 int res = x[NUMNEGATIVEONE];
162 free(x);
163 std::string bufferLog = GetBuffer(getpid());
164 bool findAsanLog = CheckAsanLog("AddressSanitizer: heap-buffer-overflow", bufferLog) &&
165 CheckAsanLog("READ of size 1", bufferLog) &&
166 CheckAsanLog("thread T0", bufferLog) &&
167 CheckAsanLog("[fa]", bufferLog);
168 int checkRes = findAsanLog ? 1 : 0;
169 napi_value result = nullptr;
170 napi_create_int32(env, findAsanLog, &result);
171 return result;
172 }
173
HeapUseAfterFree(napi_env env,napi_callback_info info)174 __attribute__((optnone)) static napi_value HeapUseAfterFree(napi_env env, napi_callback_info info)
175 {
176 char *x = (char*)malloc(NUMTEN * sizeof(char));
177 free(x);
178 char tmp = x[5];
179 std::string bufferLog = GetBuffer(getpid());
180 bool findAsanLog = CheckAsanLog("AddressSanitizer: heap-use-after-free", bufferLog) &&
181 CheckAsanLog("READ of size 1", bufferLog) &&
182 CheckAsanLog("thread T0", bufferLog) &&
183 CheckAsanLog("[fd]", bufferLog);
184 int checkRes = findAsanLog ? 1 : 0;
185 napi_value result = nullptr;
186 napi_create_int32(env, findAsanLog, &result);
187 return result;
188 }
189
190 volatile int *g_p = nullptr;
StackUseAfterScope(napi_env env,napi_callback_info info)191 __attribute__((optnone)) static napi_value StackUseAfterScope(napi_env env, napi_callback_info info)
192 {
193 {
194 int x = 0;
195 g_p = &x;
196 }
197 *g_p = NUMFIVE;
198 std::string bufferLog = GetBuffer(getpid());
199 bool findAsanLog = CheckAsanLog("AddressSanitizer: stack-use-after-scope", bufferLog) &&
200 CheckAsanLog("WRITE of size 4", bufferLog) &&
201 CheckAsanLog("thread T0", bufferLog) &&
202 CheckAsanLog("'x' (line 193)", bufferLog) &&
203 CheckAsanLog("[f8]", bufferLog);
204 int checkRes = findAsanLog ? 1 : 0;
205 napi_value result = nullptr;
206 napi_create_int32(env, findAsanLog, &result);
207 return result;
208 }
209
Fun()210 __attribute__((optnone)) int* Fun()
211 {
212 int a = 3;
213 return &a;
214 }
215
StackUseAfterReturn(napi_env env,napi_callback_info info)216 __attribute__((optnone)) static napi_value StackUseAfterReturn(napi_env env, napi_callback_info info)
217 {
218 g_p = Fun();
219 int c = *g_p;
220 std::string bufferLog = GetBuffer(getpid());
221 bool findAsanLog = CheckAsanLog("AddressSanitizer: stack-use-after-return", bufferLog) &&
222 CheckAsanLog("READ of size 4", bufferLog) &&
223 CheckAsanLog("thread T0", bufferLog) &&
224 CheckAsanLog("'a' (line 211)", bufferLog) &&
225 CheckAsanLog("[f5]", bufferLog);
226 int checkRes = findAsanLog ? 1 : 0;
227 napi_value result = nullptr;
228 napi_create_int32(env, findAsanLog, &result);
229 return result;
230 }
231
DoubleFree(napi_env env,napi_callback_info info)232 __attribute__((optnone)) static napi_value DoubleFree(napi_env env, napi_callback_info info)
233 {
234 char *x = (char*)malloc(NUMTEN * sizeof(char));
235 memset_s(x, NUMTEN * sizeof(char), 0, NUMTEN * sizeof(char));
236 int res = x[1];
237 free(x);
238 free(x);
239 std::string bufferLog = GetBuffer(getpid());
240 bool findAsanLog = CheckAsanLog("AddressSanitizer: attempting double-free", bufferLog) &&
241 CheckAsanLog("in thread T0", bufferLog);
242 int checkRes = findAsanLog ? 1 : 0;
243 napi_value result = nullptr;
244 napi_create_int32(env, findAsanLog, &result);
245 return result;
246 }
247
WildFree(napi_env env,napi_callback_info info)248 __attribute__((optnone)) static napi_value WildFree(napi_env env, napi_callback_info info)
249 {
250 char *x = (char*)malloc(NUMTEN * sizeof(char));
251 memset_s(x, NUMTEN * sizeof(char), 0, NUMTEN * sizeof(char));
252 int res = x[NUMTEN];
253 free(x + NUMFIVE);
254 std::string bufferLog = GetBuffer(getpid());
255 bool findAsanLog = CheckAsanLog("AddressSanitizer: attempting free on address which was not malloc()", bufferLog) &&
256 CheckAsanLog("allocated by thread T0", bufferLog);
257 int checkRes = findAsanLog ? 1 : 0;
258 napi_value result = nullptr;
259 napi_create_int32(env, findAsanLog, &result);
260 return result;
261 }
262
263 EXTERN_C_START
Init(napi_env env,napi_value exports)264 static napi_value Init(napi_env env, napi_value exports)
265 {
266 napi_property_descriptor desc[] = {
267 { "stackBufferOverflow", nullptr, StackBufferOverflow, nullptr, nullptr, nullptr, napi_default, nullptr },
268 { "stackBufferUnderflow", nullptr, StackBufferUnderflow, nullptr, nullptr, nullptr, napi_default, nullptr },
269 { "heapBufferOverflow", nullptr, HeapBufferOverflow, nullptr, nullptr, nullptr, napi_default, nullptr },
270 { "heapBufferUnderflow", nullptr, HeapBufferUnderflow, nullptr, nullptr, nullptr, napi_default, nullptr },
271 { "heapUseAfterFree", nullptr, HeapUseAfterFree, nullptr, nullptr, nullptr, napi_default, nullptr },
272 { "stackUseAfterScope", nullptr, StackUseAfterScope, nullptr, nullptr, nullptr, napi_default, nullptr },
273 { "stackUseAfterReturn", nullptr, StackUseAfterReturn, nullptr, nullptr, nullptr, napi_default, nullptr },
274 { "doubleFree", nullptr, DoubleFree, nullptr, nullptr, nullptr, napi_default, nullptr },
275 { "wildFree", nullptr, WildFree, nullptr, nullptr, nullptr, napi_default, nullptr }
276 };
277 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
278 return exports;
279 }
280 EXTERN_C_END
281
282 static napi_module demoModule = {
283 .nm_version = 1,
284 .nm_flags = 0,
285 .nm_filename = nullptr,
286 .nm_register_func = Init,
287 .nm_modname = "entry",
288 .nm_priv = ((void*)0),
289 .reserved = { 0 },
290 };
291
RegisterEntryModule(void)292 extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
293 {
294 napi_module_register(&demoModule);
295 }
296