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