1 /*
2 * Copyright (c) 2022 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 <stdio.h>
17 #include <string.h>
18 #include <signal.h>
19 #include <sys/wait.h>
20 #include <sigchain.h>
21 #include "fortify_test.h"
22 #include "test.h"
23
24 #define EXPECT_EQ(a, b) \
25 do { \
26 if ((a) != (b)) \
27 t_error("failed!\n"); \
28 } while (0)
29
30 #define EXPECT_STREQ(a, b) \
31 do { \
32 size_t minlen = strlen(a) >= strlen(b) ? strlen(b) : strlen(a); \
33 if (strncmp(a, b, minlen) != 0) \
34 t_error("failed\n"); \
35 } while (0)
36
37 #define EXPECT_TRUE(c) \
38 do { \
39 if (!(c)) \
40 t_error("failed!\n"); \
41 } while (0)
42
43 /**
44 * @tc.name : fread
45 * @tc.desc : normal use
46 * @tc.level : Level 0
47 */
stdio_dynamic_chk_001(void)48 static void stdio_dynamic_chk_001(void)
49 {
50 char hello_world[] = "hello world!";
51 FILE *fp = fmemopen(hello_world, sizeof(hello_world), "r");
52 EXPECT_TRUE(fp);
53
54 const int bufferSize = 14;
55 char buf[bufferSize]; // > sizeof(hello_world)
56 EXPECT_EQ(1u, fread(buf, sizeof(hello_world), 1, fp));
57 EXPECT_STREQ(hello_world, buf);
58
59 fclose(fp);
60 return;
61 }
62
63 /**
64 * @tc.name : fread
65 * @tc.desc : normal use
66 * @tc.level : Level 0
67 */
stdio_dynamic_chk_002(void)68 static void stdio_dynamic_chk_002(void)
69 {
70 FILE *fp = fopen("/dev/zero", "r");
71 EXPECT_TRUE(fp);
72
73 setvbuf(fp, NULL, _IONBF, 0);
74
75 const int bufferSize = 65*1024;
76 char buf[bufferSize];
77 memset(buf, 0xff, sizeof(buf));
78
79 size_t read_size = 64*1024;
80 size_t count_size = 1024;
81 for (size_t i = 0; i < count_size; ++i) {
82 EXPECT_EQ(1u, fread(buf, read_size, 1, fp));
83 }
84
85 // The first 64*1024 should be assigned
86 for (size_t i = 0; i < read_size; ++i) {
87 EXPECT_EQ('\0', buf[i]);
88 }
89
90 // What's left is its original data
91 for (size_t i = read_size; i < bufferSize; ++i) {
92 EXPECT_EQ('\xff', buf[i]);
93 }
94 return;
95 }
96
97 /**
98 * @tc.name : fread
99 * @tc.desc : Exceed the buffer range and reach dynamic monitoring conditions
100 * @tc.level : Level 2
101 */
stdio_dynamic_chk_003(void)102 static void stdio_dynamic_chk_003(void)
103 {
104 struct sigaction sigabrt = {
105 .sa_handler = SignalHandler,
106 };
107 sigaction(SIGABRT, &sigabrt, NULL);
108
109 const int bufferSize = 1;
110 char buf[bufferSize];
111 size_t ct = atoi("2");
112 FILE* fp = fopen("/dev/null", "r");
113
114 int status;
115 int pid = fork();
116 switch (pid) {
117 case -1:
118 t_error("fork failed: %d\n", __LINE__);
119 break;
120 case 0:
121 fread(buf, 1, ct, fp);
122 exit(0);
123 default:
124 waitpid(pid, &status, WUNTRACED);
125 TEST(WIFEXITED(status) == 0);
126 TEST(WIFSTOPPED(status) == 1);
127 TEST(WSTOPSIG(status) == SIGSTOP);
128 kill(pid, SIGCONT);
129 break;
130 }
131 fclose(fp);
132 return;
133 }
134
135 /**
136 * @tc.name : fwrite
137 * @tc.desc : Exceed the buffer range and reach dynamic monitoring conditions
138 * @tc.level : Level 2
139 */
stdio_dynamic_chk_004(void)140 static void stdio_dynamic_chk_004(void)
141 {
142 struct sigaction sigabrt = {
143 .sa_handler = SignalHandler,
144 };
145 sigaction(SIGABRT, &sigabrt, NULL);
146
147 size_t ct = atoi("2");
148 FILE* fp = fopen("/dev/null", "w");
149
150 const int bufferSize = 1;
151 char buf[bufferSize];
152
153 int status;
154 int pid = fork();
155 switch (pid) {
156 case -1:
157 t_error("fork failed: %d\n", __LINE__);
158 break;
159 case 0:
160 fwrite(buf, 1, ct, fp);
161 exit(0);
162 default:
163 waitpid(pid, &status, WUNTRACED);
164 TEST(WIFEXITED(status) == 0);
165 TEST(WIFSTOPPED(status) == 1);
166 TEST(WSTOPSIG(status) == SIGSTOP);
167 kill(pid, SIGCONT);
168 break;
169 }
170 fclose(fp);
171 return;
172 }
173
174 /**
175 * @tc.name : fgets
176 * @tc.desc : Normal function
177 * @tc.level : Level 0
178 */
stdio_dynamic_chk_005(void)179 static void stdio_dynamic_chk_005(void)
180 {
181 char hello_world[] = "hello world!";
182 FILE *fp = fmemopen(hello_world, sizeof(hello_world), "r");
183 EXPECT_TRUE(fp);
184
185 const int bufferSize = 16;
186 char buf[bufferSize];
187 char *get = fgets(buf, sizeof(buf), fp);
188 EXPECT_TRUE(get != NULL);
189 EXPECT_TRUE(strcmp(hello_world, get) == 0);
190 fclose(fp);
191 return;
192 }
193
194 /**
195 * @tc.name : fgets
196 * @tc.desc : Get newline and end position as normal
197 * @tc.level : Level 0
198 */
stdio_dynamic_chk_006(void)199 static void stdio_dynamic_chk_006(void)
200 {
201 char hello_world[] = "hello world!\nhello boy!\0";
202 FILE *fp = fmemopen(hello_world, sizeof(hello_world), "r");
203 EXPECT_TRUE(fp);
204
205 const int bufferSize = 16;
206 char buf[bufferSize];
207 char *get1 = fgets(buf, sizeof("hello"), fp);
208 EXPECT_TRUE(get1 != NULL);
209 EXPECT_TRUE(strcmp("hello", get1) == 0);
210
211 memset(buf,0x00,sizeof(buf));
212 char *get2 = fgets(buf, sizeof(buf), fp);
213 EXPECT_TRUE(get2 != NULL);
214
215 memset(buf,0x00,sizeof(buf));
216 char *get3 = fgets(buf, sizeof(buf), fp);
217 EXPECT_TRUE(get3 != NULL);
218 EXPECT_TRUE(strcmp("hello boy!", get3) == 0);
219 fclose(fp);
220 return;
221 }
222
223 /**
224 * @tc.name : fgets
225 * @tc.desc : The size of reads is greater than the capacity of buf
226 * @tc.level : Level 2
227 */
stdio_dynamic_chk_007(void)228 static void stdio_dynamic_chk_007(void)
229 {
230 struct sigaction sigabrt = {
231 .sa_handler = SignalHandler,
232 };
233 sigaction(SIGABRT, &sigabrt, NULL);
234
235 char hello_world[] = "hello world!";
236 FILE *fp = fmemopen(hello_world, sizeof(hello_world), "r");
237
238 const int bufferSize = 16;
239 char buf[bufferSize];
240 size_t n = atoi("18");
241 int status;
242 int pid = fork();
243 switch (pid) {
244 case -1:
245 t_error("fork failed: %d\n", __LINE__);
246 break;
247 case 0:
248 fgets(buf, n, fp);
249 exit(0);
250 default:
251 waitpid(pid, &status, WUNTRACED);
252 TEST(WIFEXITED(status) == 0);
253 TEST(WIFSTOPPED(status) == 1);
254 TEST(WSTOPSIG(status) == SIGSTOP);
255 kill(pid, SIGCONT);
256 break;
257 }
258 fclose(fp);
259 return;
260 }
261
262 /**
263 * @tc.name : sprintf
264 * @tc.desc : Normal call test
265 * @tc.level : Level 0
266 */
stdio_dynamic_chk_008(void)267 static void stdio_dynamic_chk_008(void)
268 {
269 char buf[] = "world";
270 sprintf(buf, "hello");
271 EXPECT_TRUE(strcmp(buf, "hello") == 0);
272 return;
273 }
274
275 /**
276 * @tc.name : sprintf
277 * @tc.desc : Normal call test
278 * @tc.level : Level 0
279 */
stdio_dynamic_chk_009(void)280 static void stdio_dynamic_chk_009(void)
281 {
282 const int bufferSize = 20;
283 char buf[bufferSize];
284 sprintf(buf, "hello : %s", "world!");
285
286 char value[] = "hello : world!";
287 EXPECT_TRUE(strcmp(buf, value) == 0);
288 return;
289 }
290
291
292 /**
293 * @tc.name : sprintf
294 * @tc.desc : sprintf beyond capacity
295 * @tc.level : Level 2
296 */
stdio_dynamic_chk_010(void)297 static void stdio_dynamic_chk_010(void)
298 {
299 const int bufferSize = 6;
300 char buf[bufferSize];
301
302 struct sigaction sigabrt = {
303 .sa_handler = SignalHandler,
304 };
305 sigaction(SIGABRT, &sigabrt, NULL);
306
307 int status;
308 int pid = fork();
309 switch (pid) {
310 case -1:
311 t_error("fork failed: %d\n", __LINE__);
312 break;
313 case 0:
314 sprintf(buf, "hello : %s", "world!");
315 exit(0);
316 default:
317 waitpid(pid, &status, WUNTRACED);
318 TEST(WIFEXITED(status) == 0);
319 TEST(WIFSTOPPED(status) == 1);
320 TEST(WSTOPSIG(status) == SIGSTOP);
321 kill(pid, SIGCONT);
322 break;
323 }
324 return;
325 }
326
327 /**
328 * @tc.name : snprintf
329 * @tc.desc : snprintf beyond capacity
330 * @tc.level : Level 2
331 */
332
stdio_dynamic_chk_011(void)333 static void stdio_dynamic_chk_011(void)
334 {
335 const int bufferSize = 6;
336 char buf[bufferSize];
337
338 struct sigaction sigabrt = {
339 .sa_handler = SignalHandler,
340 };
341 sigaction(SIGABRT, &sigabrt, NULL);
342
343 int printSize = 10;
344 int status;
345 int pid = fork();
346 switch (pid) {
347 case -1:
348 t_error("fork failed: %d\n", __LINE__);
349 break;
350 case 0: // 10 > sizeof buf
351 snprintf(buf, printSize, "hello : %s", "world!");
352 exit(0);
353 default:
354 waitpid(pid, &status, WUNTRACED);
355 TEST(WIFEXITED(status) == 0);
356 TEST(WIFSTOPPED(status) == 1);
357 TEST(WSTOPSIG(status) == SIGSTOP);
358 kill(pid, SIGCONT);
359 break;
360 }
361 return;
362 }
363
364
vsnprintf_test(const char * format,...)365 static int vsnprintf_test(const char* format, ...)
366 {
367 const int bufferSize = 6;
368 char buf[bufferSize];
369 int printSize = 10;
370 va_list va;
371 va_start(va, format);
372 int result = vsnprintf(buf, printSize, format, va);
373 va_end(va);
374 return result;
375 }
376
vsprintf_test(const char * format,...)377 static int vsprintf_test(const char* format, ...)
378 {
379 const int bufferSize = 6;
380 char buf[bufferSize];
381 va_list va;
382 va_start(va, format);
383 int result = vsprintf(buf, format, va);
384 va_end(va);
385 return result;
386 }
387
388 /**
389 * @tc.name : vsnprintf
390 * @tc.desc : vsnprintf beyond capacity
391 * @tc.level : Level 2
392 */
stdio_dynamic_chk_012(void)393 static void stdio_dynamic_chk_012(void)
394 {
395 struct sigaction sigabrt = {
396 .sa_handler = SignalHandler,
397 };
398 sigaction(SIGABRT, &sigabrt, NULL);
399
400 int status;
401 int pid = fork();
402 switch (pid) {
403 case -1:
404 t_error("fork failed: %d\n", __LINE__);
405 break;
406 case 0:
407 vsnprintf_test("hello : %s", "world!");
408 exit(0);
409 default:
410 waitpid(pid, &status, WUNTRACED);
411 TEST(WIFEXITED(status) == 0);
412 TEST(WIFSTOPPED(status) == 1);
413 TEST(WSTOPSIG(status) == SIGSTOP);
414 kill(pid, SIGCONT);
415 break;
416 }
417 return;
418 }
419
420 /**
421 * @tc.name : vsprsintf
422 * @tc.desc : vsprintf beyond capacity
423 * @tc.level : Level 2
424 */
stdio_dynamic_chk_013(void)425 static void stdio_dynamic_chk_013(void)
426 {
427 struct sigaction sigabrt = {
428 .sa_handler = SignalHandler,
429 };
430 sigaction(SIGABRT, &sigabrt, NULL);
431
432 int status;
433 int pid = fork();
434 switch (pid) {
435 case -1:
436 t_error("fork failed: %d\n", __LINE__);
437 break;
438 case 0:
439 vsprintf_test("%s", "0123456789");
440 exit(0);
441 default:
442 waitpid(pid, &status, WUNTRACED);
443 TEST(WIFEXITED(status) == 0);
444 TEST(WIFSTOPPED(status) == 1);
445 TEST(WSTOPSIG(status) == SIGSTOP);
446 kill(pid, SIGCONT);
447 break;
448 }
449 return;
450 }
451
main()452 int main()
453 {
454 remove_all_special_handler(SIGABRT);
455 stdio_dynamic_chk_001();
456 stdio_dynamic_chk_002();
457 stdio_dynamic_chk_003();
458 stdio_dynamic_chk_004();
459 stdio_dynamic_chk_005();
460 stdio_dynamic_chk_006();
461 stdio_dynamic_chk_007();
462 stdio_dynamic_chk_008();
463 stdio_dynamic_chk_009();
464 stdio_dynamic_chk_010();
465 stdio_dynamic_chk_011();
466 stdio_dynamic_chk_012();
467 stdio_dynamic_chk_013();
468
469 return t_status;
470 }