xref: /aosp_15_r20/bionic/tests/fdsan_test.cpp (revision 8d67ca893c1523eb926b9080dbe4e2ffd2a27ba1)
1*8d67ca89SAndroid Build Coastguard Worker /*
2*8d67ca89SAndroid Build Coastguard Worker  * Copyright (C) 2018 The Android Open Source Project
3*8d67ca89SAndroid Build Coastguard Worker  *
4*8d67ca89SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*8d67ca89SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*8d67ca89SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*8d67ca89SAndroid Build Coastguard Worker  *
8*8d67ca89SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*8d67ca89SAndroid Build Coastguard Worker  *
10*8d67ca89SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*8d67ca89SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*8d67ca89SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*8d67ca89SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*8d67ca89SAndroid Build Coastguard Worker  * limitations under the License.
15*8d67ca89SAndroid Build Coastguard Worker  */
16*8d67ca89SAndroid Build Coastguard Worker 
17*8d67ca89SAndroid Build Coastguard Worker #include <gtest/gtest.h>
18*8d67ca89SAndroid Build Coastguard Worker 
19*8d67ca89SAndroid Build Coastguard Worker #include <dirent.h>
20*8d67ca89SAndroid Build Coastguard Worker #include <errno.h>
21*8d67ca89SAndroid Build Coastguard Worker #include <fcntl.h>
22*8d67ca89SAndroid Build Coastguard Worker #include <stdlib.h>
23*8d67ca89SAndroid Build Coastguard Worker #include <sys/types.h>
24*8d67ca89SAndroid Build Coastguard Worker #include <unistd.h>
25*8d67ca89SAndroid Build Coastguard Worker 
26*8d67ca89SAndroid Build Coastguard Worker #if defined(__BIONIC__)
27*8d67ca89SAndroid Build Coastguard Worker #include <android/fdsan.h>
28*8d67ca89SAndroid Build Coastguard Worker #include <bionic/reserved_signals.h>
29*8d67ca89SAndroid Build Coastguard Worker #endif
30*8d67ca89SAndroid Build Coastguard Worker 
31*8d67ca89SAndroid Build Coastguard Worker #include <unordered_map>
32*8d67ca89SAndroid Build Coastguard Worker 
33*8d67ca89SAndroid Build Coastguard Worker #include <android-base/silent_death_test.h>
34*8d67ca89SAndroid Build Coastguard Worker #include <android-base/unique_fd.h>
35*8d67ca89SAndroid Build Coastguard Worker 
36*8d67ca89SAndroid Build Coastguard Worker #define EXPECT_FDSAN_DEATH(expression, regex)                                                \
37*8d67ca89SAndroid Build Coastguard Worker   EXPECT_DEATH((android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_FATAL), expression), \
38*8d67ca89SAndroid Build Coastguard Worker                (regex))
39*8d67ca89SAndroid Build Coastguard Worker 
40*8d67ca89SAndroid Build Coastguard Worker struct fdsan : public ::testing::Test {
SetUpfdsan41*8d67ca89SAndroid Build Coastguard Worker   void SetUp() override {
42*8d67ca89SAndroid Build Coastguard Worker #if defined(__BIONIC__)
43*8d67ca89SAndroid Build Coastguard Worker     // The bionic unit test running forks for each test by default, which turns
44*8d67ca89SAndroid Build Coastguard Worker     // fdsan off as a side-effect, so we need to turn it back on.
45*8d67ca89SAndroid Build Coastguard Worker     android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_FATAL);
46*8d67ca89SAndroid Build Coastguard Worker #endif
47*8d67ca89SAndroid Build Coastguard Worker   }
48*8d67ca89SAndroid Build Coastguard Worker };
49*8d67ca89SAndroid Build Coastguard Worker 
50*8d67ca89SAndroid Build Coastguard Worker struct fdsan_DeathTest : public SilentDeathTest {
51*8d67ca89SAndroid Build Coastguard Worker #if defined(__BIONIC__)
SetUpfdsan_DeathTest52*8d67ca89SAndroid Build Coastguard Worker   void SetUp() override {
53*8d67ca89SAndroid Build Coastguard Worker     android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_FATAL);
54*8d67ca89SAndroid Build Coastguard Worker     signal(BIONIC_SIGNAL_DEBUGGER, SIG_DFL);  // Disable debuggerd.
55*8d67ca89SAndroid Build Coastguard Worker     SilentDeathTest::SetUp();
56*8d67ca89SAndroid Build Coastguard Worker   }
57*8d67ca89SAndroid Build Coastguard Worker #endif
58*8d67ca89SAndroid Build Coastguard Worker };
59*8d67ca89SAndroid Build Coastguard Worker 
TEST_F(fdsan,unowned_untagged_close)60*8d67ca89SAndroid Build Coastguard Worker TEST_F(fdsan, unowned_untagged_close) {
61*8d67ca89SAndroid Build Coastguard Worker #if defined(__BIONIC__)
62*8d67ca89SAndroid Build Coastguard Worker   int fd = open("/dev/null", O_RDONLY);
63*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(0, close(fd));
64*8d67ca89SAndroid Build Coastguard Worker #endif
65*8d67ca89SAndroid Build Coastguard Worker }
66*8d67ca89SAndroid Build Coastguard Worker 
TEST_F(fdsan,unowned_tagged_close)67*8d67ca89SAndroid Build Coastguard Worker TEST_F(fdsan, unowned_tagged_close) {
68*8d67ca89SAndroid Build Coastguard Worker #if defined(__BIONIC__)
69*8d67ca89SAndroid Build Coastguard Worker   int fd = open("/dev/null", O_RDONLY);
70*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(0, android_fdsan_close_with_tag(fd, 0));
71*8d67ca89SAndroid Build Coastguard Worker #endif
72*8d67ca89SAndroid Build Coastguard Worker }
73*8d67ca89SAndroid Build Coastguard Worker 
TEST_F(fdsan_DeathTest,unowned_improperly_tagged_close)74*8d67ca89SAndroid Build Coastguard Worker TEST_F(fdsan_DeathTest, unowned_improperly_tagged_close) {
75*8d67ca89SAndroid Build Coastguard Worker #if defined(__BIONIC__)
76*8d67ca89SAndroid Build Coastguard Worker   int fd = open("/dev/null", O_RDONLY);
77*8d67ca89SAndroid Build Coastguard Worker   EXPECT_FDSAN_DEATH(android_fdsan_close_with_tag(fd, 0xdeadbeef), "actually unowned");
78*8d67ca89SAndroid Build Coastguard Worker #endif
79*8d67ca89SAndroid Build Coastguard Worker }
80*8d67ca89SAndroid Build Coastguard Worker 
TEST_F(fdsan_DeathTest,unowned_incorrect_exchange)81*8d67ca89SAndroid Build Coastguard Worker TEST_F(fdsan_DeathTest, unowned_incorrect_exchange) {
82*8d67ca89SAndroid Build Coastguard Worker #if defined(__BIONIC__)
83*8d67ca89SAndroid Build Coastguard Worker   int fd = open("/dev/null", O_RDONLY);
84*8d67ca89SAndroid Build Coastguard Worker   EXPECT_FDSAN_DEATH(android_fdsan_exchange_owner_tag(fd, 0xbadc0de, 0xdeadbeef),
85*8d67ca89SAndroid Build Coastguard Worker                      "failed to exchange ownership");
86*8d67ca89SAndroid Build Coastguard Worker #endif
87*8d67ca89SAndroid Build Coastguard Worker }
88*8d67ca89SAndroid Build Coastguard Worker 
TEST_F(fdsan_DeathTest,owned_untagged_close)89*8d67ca89SAndroid Build Coastguard Worker TEST_F(fdsan_DeathTest, owned_untagged_close) {
90*8d67ca89SAndroid Build Coastguard Worker #if defined(__BIONIC__)
91*8d67ca89SAndroid Build Coastguard Worker   int fd = open("/dev/null", O_RDONLY);
92*8d67ca89SAndroid Build Coastguard Worker   android_fdsan_exchange_owner_tag(fd, 0, 0xdeadbeef);
93*8d67ca89SAndroid Build Coastguard Worker   EXPECT_FDSAN_DEATH(close(fd), "expected to be unowned, actually owned");
94*8d67ca89SAndroid Build Coastguard Worker #endif
95*8d67ca89SAndroid Build Coastguard Worker }
96*8d67ca89SAndroid Build Coastguard Worker 
TEST_F(fdsan,owned_tagged_close)97*8d67ca89SAndroid Build Coastguard Worker TEST_F(fdsan, owned_tagged_close) {
98*8d67ca89SAndroid Build Coastguard Worker #if defined(__BIONIC__)
99*8d67ca89SAndroid Build Coastguard Worker   int fd = open("/dev/null", O_RDONLY);
100*8d67ca89SAndroid Build Coastguard Worker   android_fdsan_exchange_owner_tag(fd, 0, 0xdeadbeef);
101*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(0, android_fdsan_close_with_tag(fd, 0xdeadbeef));
102*8d67ca89SAndroid Build Coastguard Worker #endif
103*8d67ca89SAndroid Build Coastguard Worker }
104*8d67ca89SAndroid Build Coastguard Worker 
TEST_F(fdsan_DeathTest,owned_improperly_tagged_close)105*8d67ca89SAndroid Build Coastguard Worker TEST_F(fdsan_DeathTest, owned_improperly_tagged_close) {
106*8d67ca89SAndroid Build Coastguard Worker #if defined(__BIONIC__)
107*8d67ca89SAndroid Build Coastguard Worker   int fd = open("/dev/null", O_RDONLY);
108*8d67ca89SAndroid Build Coastguard Worker   android_fdsan_exchange_owner_tag(fd, 0, 0xdeadbeef);
109*8d67ca89SAndroid Build Coastguard Worker   EXPECT_FDSAN_DEATH(android_fdsan_close_with_tag(fd, 0xdeadc0de), "expected to be owned");
110*8d67ca89SAndroid Build Coastguard Worker #endif
111*8d67ca89SAndroid Build Coastguard Worker }
112*8d67ca89SAndroid Build Coastguard Worker 
TEST_F(fdsan_DeathTest,owned_incorrect_exchange)113*8d67ca89SAndroid Build Coastguard Worker TEST_F(fdsan_DeathTest, owned_incorrect_exchange) {
114*8d67ca89SAndroid Build Coastguard Worker #if defined(__BIONIC__)
115*8d67ca89SAndroid Build Coastguard Worker   int fd = open("/dev/null", O_RDONLY);
116*8d67ca89SAndroid Build Coastguard Worker   android_fdsan_exchange_owner_tag(fd, 0, 0xdeadbeef);
117*8d67ca89SAndroid Build Coastguard Worker   EXPECT_FDSAN_DEATH(android_fdsan_exchange_owner_tag(fd, 0xbadc0de, 0xdeadbeef),
118*8d67ca89SAndroid Build Coastguard Worker                      "failed to exchange");
119*8d67ca89SAndroid Build Coastguard Worker #endif
120*8d67ca89SAndroid Build Coastguard Worker }
121*8d67ca89SAndroid Build Coastguard Worker 
TEST_F(fdsan_DeathTest,fopen)122*8d67ca89SAndroid Build Coastguard Worker TEST_F(fdsan_DeathTest, fopen) {
123*8d67ca89SAndroid Build Coastguard Worker #if defined(__BIONIC__)
124*8d67ca89SAndroid Build Coastguard Worker   FILE* f = fopen("/dev/null", "r");
125*8d67ca89SAndroid Build Coastguard Worker   ASSERT_TRUE(f);
126*8d67ca89SAndroid Build Coastguard Worker   EXPECT_FDSAN_DEATH(close(fileno(f)), "actually owned by FILE");
127*8d67ca89SAndroid Build Coastguard Worker #endif
128*8d67ca89SAndroid Build Coastguard Worker }
129*8d67ca89SAndroid Build Coastguard Worker 
TEST_F(fdsan_DeathTest,closedir)130*8d67ca89SAndroid Build Coastguard Worker TEST_F(fdsan_DeathTest, closedir) {
131*8d67ca89SAndroid Build Coastguard Worker #if defined(__BIONIC__)
132*8d67ca89SAndroid Build Coastguard Worker   DIR* dir = opendir("/dev/");
133*8d67ca89SAndroid Build Coastguard Worker   ASSERT_TRUE(dir);
134*8d67ca89SAndroid Build Coastguard Worker   EXPECT_FDSAN_DEATH(close(dirfd(dir)), "actually owned by DIR");
135*8d67ca89SAndroid Build Coastguard Worker #endif
136*8d67ca89SAndroid Build Coastguard Worker }
137*8d67ca89SAndroid Build Coastguard Worker 
TEST_F(fdsan,overflow)138*8d67ca89SAndroid Build Coastguard Worker TEST_F(fdsan, overflow) {
139*8d67ca89SAndroid Build Coastguard Worker #if defined(__BIONIC__)
140*8d67ca89SAndroid Build Coastguard Worker   std::unordered_map<int, uint64_t> fds;
141*8d67ca89SAndroid Build Coastguard Worker   for (int i = 0; i < 4096; ++i) {
142*8d67ca89SAndroid Build Coastguard Worker     int fd = open("/dev/null", O_RDONLY);
143*8d67ca89SAndroid Build Coastguard Worker     auto tag = 0xdead00000000ULL | i;
144*8d67ca89SAndroid Build Coastguard Worker     android_fdsan_exchange_owner_tag(fd, 0, tag);
145*8d67ca89SAndroid Build Coastguard Worker     fds[fd] = tag;
146*8d67ca89SAndroid Build Coastguard Worker   }
147*8d67ca89SAndroid Build Coastguard Worker 
148*8d67ca89SAndroid Build Coastguard Worker   for (auto [fd, tag] : fds) {
149*8d67ca89SAndroid Build Coastguard Worker     android_fdsan_close_with_tag(fd, tag);
150*8d67ca89SAndroid Build Coastguard Worker   }
151*8d67ca89SAndroid Build Coastguard Worker #endif
152*8d67ca89SAndroid Build Coastguard Worker }
153*8d67ca89SAndroid Build Coastguard Worker 
TEST_F(fdsan_DeathTest,owner_value_high)154*8d67ca89SAndroid Build Coastguard Worker TEST_F(fdsan_DeathTest, owner_value_high) {
155*8d67ca89SAndroid Build Coastguard Worker #if defined(__BIONIC__)
156*8d67ca89SAndroid Build Coastguard Worker   int fd = open("/dev/null", O_RDONLY);
157*8d67ca89SAndroid Build Coastguard Worker   uint64_t tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD, ~0ULL);
158*8d67ca89SAndroid Build Coastguard Worker   android_fdsan_exchange_owner_tag(fd, 0, tag);
159*8d67ca89SAndroid Build Coastguard Worker   EXPECT_FDSAN_DEATH(android_fdsan_exchange_owner_tag(fd, 0xbadc0de, 0xdeadbeef),
160*8d67ca89SAndroid Build Coastguard Worker                      "0xffffffffffffffff");
161*8d67ca89SAndroid Build Coastguard Worker #endif
162*8d67ca89SAndroid Build Coastguard Worker }
163*8d67ca89SAndroid Build Coastguard Worker 
TEST_F(fdsan_DeathTest,owner_value_low)164*8d67ca89SAndroid Build Coastguard Worker TEST_F(fdsan_DeathTest, owner_value_low) {
165*8d67ca89SAndroid Build Coastguard Worker #if defined(__BIONIC__)
166*8d67ca89SAndroid Build Coastguard Worker   int fd = open("/dev/null", O_RDONLY);
167*8d67ca89SAndroid Build Coastguard Worker   uint64_t tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD, 1);
168*8d67ca89SAndroid Build Coastguard Worker   android_fdsan_exchange_owner_tag(fd, 0, tag);
169*8d67ca89SAndroid Build Coastguard Worker   EXPECT_FDSAN_DEATH(android_fdsan_exchange_owner_tag(fd, 0xbadc0de, 0xdeadbeef),
170*8d67ca89SAndroid Build Coastguard Worker                      "0x1");
171*8d67ca89SAndroid Build Coastguard Worker #endif
172*8d67ca89SAndroid Build Coastguard Worker }
173*8d67ca89SAndroid Build Coastguard Worker 
TEST_F(fdsan_DeathTest,unique_fd_unowned_close)174*8d67ca89SAndroid Build Coastguard Worker TEST_F(fdsan_DeathTest, unique_fd_unowned_close) {
175*8d67ca89SAndroid Build Coastguard Worker #if defined(__BIONIC__)
176*8d67ca89SAndroid Build Coastguard Worker   android::base::unique_fd fd(open("/dev/null", O_RDONLY));
177*8d67ca89SAndroid Build Coastguard Worker   android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_FATAL);
178*8d67ca89SAndroid Build Coastguard Worker   EXPECT_FDSAN_DEATH(close(fd.get()), "expected to be unowned, actually owned by unique_fd");
179*8d67ca89SAndroid Build Coastguard Worker #endif
180*8d67ca89SAndroid Build Coastguard Worker }
181*8d67ca89SAndroid Build Coastguard Worker 
TEST_F(fdsan,unique_fd_untag_on_release)182*8d67ca89SAndroid Build Coastguard Worker TEST_F(fdsan, unique_fd_untag_on_release) {
183*8d67ca89SAndroid Build Coastguard Worker   android::base::unique_fd fd(open("/dev/null", O_RDONLY));
184*8d67ca89SAndroid Build Coastguard Worker   close(fd.release());
185*8d67ca89SAndroid Build Coastguard Worker }
186*8d67ca89SAndroid Build Coastguard Worker 
TEST_F(fdsan,unique_fd_move)187*8d67ca89SAndroid Build Coastguard Worker TEST_F(fdsan, unique_fd_move) {
188*8d67ca89SAndroid Build Coastguard Worker   android::base::unique_fd fd(open("/dev/null", O_RDONLY));
189*8d67ca89SAndroid Build Coastguard Worker   android::base::unique_fd fd_moved = std::move(fd);
190*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(-1, fd.get());
191*8d67ca89SAndroid Build Coastguard Worker   ASSERT_GT(fd_moved.get(), -1);
192*8d67ca89SAndroid Build Coastguard Worker }
193*8d67ca89SAndroid Build Coastguard Worker 
TEST_F(fdsan_DeathTest,unique_fd_unowned_close_after_move)194*8d67ca89SAndroid Build Coastguard Worker TEST_F(fdsan_DeathTest, unique_fd_unowned_close_after_move) {
195*8d67ca89SAndroid Build Coastguard Worker #if defined(__BIONIC__)
196*8d67ca89SAndroid Build Coastguard Worker   android::base::unique_fd fd(open("/dev/null", O_RDONLY));
197*8d67ca89SAndroid Build Coastguard Worker   android::base::unique_fd fd_moved = std::move(fd);
198*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(-1, fd.get());
199*8d67ca89SAndroid Build Coastguard Worker   ASSERT_GT(fd_moved.get(), -1);
200*8d67ca89SAndroid Build Coastguard Worker 
201*8d67ca89SAndroid Build Coastguard Worker   android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_FATAL);
202*8d67ca89SAndroid Build Coastguard Worker   EXPECT_FDSAN_DEATH(close(fd_moved.get()), "expected to be unowned, actually owned by unique_fd");
203*8d67ca89SAndroid Build Coastguard Worker #endif
204*8d67ca89SAndroid Build Coastguard Worker }
205*8d67ca89SAndroid Build Coastguard Worker 
TEST_F(fdsan,vfork)206*8d67ca89SAndroid Build Coastguard Worker TEST_F(fdsan, vfork) {
207*8d67ca89SAndroid Build Coastguard Worker   android::base::unique_fd fd(open("/dev/null", O_RDONLY));
208*8d67ca89SAndroid Build Coastguard Worker 
209*8d67ca89SAndroid Build Coastguard Worker   pid_t rc = vfork();
210*8d67ca89SAndroid Build Coastguard Worker   ASSERT_NE(-1, rc);
211*8d67ca89SAndroid Build Coastguard Worker 
212*8d67ca89SAndroid Build Coastguard Worker   if (rc == 0) {
213*8d67ca89SAndroid Build Coastguard Worker     close(fd.get());
214*8d67ca89SAndroid Build Coastguard Worker     _exit(0);
215*8d67ca89SAndroid Build Coastguard Worker   }
216*8d67ca89SAndroid Build Coastguard Worker 
217*8d67ca89SAndroid Build Coastguard Worker   int status;
218*8d67ca89SAndroid Build Coastguard Worker   pid_t wait_result = waitpid(rc, &status, 0);
219*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(wait_result, rc);
220*8d67ca89SAndroid Build Coastguard Worker   ASSERT_TRUE(WIFEXITED(status));
221*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(0, WEXITSTATUS(status));
222*8d67ca89SAndroid Build Coastguard Worker }
223