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 */
48static 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 */
68static 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 */
102static 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 */
140static 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 */
179static 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 */
199static 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 */
228static 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 */
267static 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 */
280static 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 */
297static 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
333static 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
365static 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
377static 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 */
393static 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 */
425static 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
452int 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}