• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }