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