1/*
2 * Copyright (C) 2024 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 <stdlib.h>
18#include <signal.h>
19#include <pthread.h>
20#include <fcntl.h>
21#include <stdint.h>
22#include <string.h>
23#include <sys/wait.h>
24#include <unistd.h>
25#include <musl_log.h>
26#include <stdio_impl.h>
27
28#include <unordered_map>
29
30#include "functionalext.h"
31
32#define DEV_NULL_PATH "/dev/null"
33
34void signal_handler_abort(int signum)
35{
36    kill(getpid(), SIGSTOP);
37}
38
39void signal_handler_abort1(int signum)
40{
41    exit(signum);
42}
43
44void fdsan_test_get_tag_value()
45{
46    int fd = open(DEV_NULL_PATH, O_RDONLY);
47    uint64_t tag = fdsan_get_owner_tag(fd);
48    EXPECT_EQ("fdsan_test_get_tag_value", strcmp(fdsan_get_tag_type(tag), "native object of unknown type"), 0);
49    EXPECT_EQ("fdsan_test_get_tag_value", fdsan_get_tag_value(tag), 0);
50    EXPECT_EQ("fdsan_test_get_tag_value", close(fd), 0);
51}
52
53void fdsan_test_overflow()
54{
55    std::unordered_map<int, uint64_t> fds;
56    for (int i = 0; i < 4096; ++i) {
57        int fd = open(DEV_NULL_PATH, O_RDONLY);
58        auto tag = 0xdead00000000ULL | i;
59        fdsan_exchange_owner_tag(fd, 0, tag);
60        fds[fd] = tag;
61    }
62
63    for (auto [fd, tag] : fds) {
64        EXPECT_EQ("fdsan_test_overflow", fdsan_close_with_tag(fd, tag), 0);
65    }
66}
67
68void fdsan_test_vfork()
69{
70    int fd = open(DEV_NULL_PATH, O_RDONLY);
71
72    pid_t rc = vfork();
73    EXPECT_NE("fdsan_test_vfork", -1, rc);
74
75    if (rc == 0) {
76        close(fd);
77        _exit(0);
78    }
79
80    int status;
81    pid_t wait_result = waitpid(rc, &status, 0);
82    EXPECT_EQ("fdsan_test_vfork", wait_result, rc);
83    EXPECT_TRUE("fdsan_test_vfork", WIFEXITED(status));
84    EXPECT_EQ("fdsan_test_vfork", 0, WEXITSTATUS(status));
85}
86
87void fdsan_test_fatal_level()
88{
89    struct sigaction sigabrt = {
90        .sa_handler = signal_handler_abort,
91    };
92    sigaction(SIGABRT, &sigabrt, nullptr);
93
94    int status;
95    int pid = fork();
96    switch (pid) {
97        case -1: {
98            t_error("fork failed: %d\n", __LINE__);
99            break;
100        }
101        case 0: {
102            fdsan_set_error_level(FDSAN_ERROR_LEVEL_FATAL);
103            int fd = open(DEV_NULL_PATH, O_RDONLY);
104            uint64_t tag = 0xdead00000000ULL;
105            fdsan_exchange_owner_tag(fd, 0, tag);
106            fdsan_close_with_tag(fd, 0);
107            exit(0);
108        }
109        default: {
110            waitpid(pid, &status, WUNTRACED);
111            EXPECT_EQ("fdsan_test_fatal_level", WIFEXITED(status), 0);
112            EXPECT_EQ("fdsan_test_fatal_level", WIFSTOPPED(status), 1);
113            EXPECT_EQ("fdsan_test_fatal_level", WSTOPSIG(status), SIGSTOP);
114            kill(pid, SIGCONT);
115            break;
116        }
117    }
118    return;
119}
120
121bool CreateFile()
122{
123    // 创建一个临时文件
124    // 指定文件路径
125    const char *file_path = "/data/local/tmp/test.txt";
126
127    // 创建文件并打开文件描述符
128    int fd = open(file_path, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR);
129    if (fd == -1) {
130        return false;
131    }
132
133    // 关闭文件描述符
134    close(fd);
135    return true;
136}
137
138
139void fdsan_test_internal_fopen_succeed()
140{
141    struct sigaction sigabrt = {
142        .sa_handler = signal_handler_abort,
143    };
144    sigaction(SIGABRT, &sigabrt, nullptr);
145    bool res = CreateFile();
146    if (!res) {
147        t_error("fdsan_test_internal_fopen create file failed");
148        return;
149    }
150    int status;
151    int pid = fork();
152    switch (pid) {
153        case -1: {
154            t_error("fork failed: %d\n", __LINE__);
155            break;
156        }
157        case 0: {
158            fdsan_set_error_level(FDSAN_ERROR_LEVEL_FATAL);
159            unsigned char str[1024];
160            FILE f;
161            FILE *ptr = __fopen_rb_ca(file_path, &f, str, sizeof(str));
162            EXPECT_NE("fdsan_test_internal_fopen_succeed open file failed", ptr, NULL);
163            if (ptr) {
164                __fclose_ca(ptr);
165            }
166            exit(0);
167        }
168        default: {
169            waitpid(pid, &status, WUNTRACED);
170            EXPECT_EQ("fdsan_test_fork_subprocess_disabled WIFEXITED", WIFEXITED(status), 1);
171            EXPECT_EQ("fdsan_test_fork_subprocess_disabled WIFSTOPPED", WIFSTOPPED(status), 0);
172            // 子进程应该能够匹配到对应的tag,不应该通过信号方式退出,这里检测子进程不会收到abort信号
173            EXPECT_EQ("fdsan_test_fork_subprocess_disabled WSTOPSIG", WSTOPSIG(status), 0);
174            kill(pid, SIGCONT);
175            break;
176        }
177    }
178    return;
179}
180
181int main()
182{
183    fdsan_test_get_tag_value();
184    fdsan_test_overflow();
185    fdsan_test_vfork();
186    fdsan_test_fatal_level();
187    fdsan_test_fork_subprocess_disabled();
188    fdsan_test_internal_fopen_succeed();
189    return t_status;
190}
191