1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in 12 * the documentation and/or other materials provided with the 13 * distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <android/fdsan.h> 30 31 #include <errno.h> 32 #include <inttypes.h> 33 #include <signal.h> 34 #include <stdarg.h> 35 #include <stdatomic.h> 36 #include <string.h> 37 #include <sys/cdefs.h> 38 #include <sys/mman.h> 39 #include <sys/syscall.h> 40 #include <unistd.h> 41 42 #include <async_safe/log.h> 43 #include <sys/system_properties.h> 44 45 #include "private/bionic_globals.h" 46 #include "private/bionic_inline_raise.h" 47 #include "pthread_internal.h" 48 49 extern "C" int ___close(int fd); 50 pid_t __get_cached_pid(); 51 52 static constexpr const char* kFdsanPropertyName = "debug.fdsan"; 53 54 template<size_t inline_fds> 55 FdEntry* FdTableImpl<inline_fds>::at(size_t idx) { 56 if (idx < inline_fds) { 57 return &entries[idx]; 58 } 59 60 // Try to create the overflow table ourselves. 61 FdTableOverflow* local_overflow = atomic_load(&overflow); 62 if (__predict_false(!local_overflow)) { 63 struct rlimit rlim = { .rlim_max = 32768 }; 64 getrlimit(RLIMIT_NOFILE, &rlim); 65 rlim_t max = rlim.rlim_max; 66 67 if (max == RLIM_INFINITY) { 68 // This isn't actually possible (the kernel has a hard limit), but just 69 // in case... 70 max = 32768; 71 } 72 73 if (idx > max) { 74 // This can happen if an fd is created and then the rlimit is lowered. 75 // In this case, just return nullptr and ignore the fd. 76 return nullptr; 77 } 78 79 size_t required_count = max - inline_fds; 80 size_t required_size = sizeof(FdTableOverflow) + required_count * sizeof(FdEntry); 81 size_t aligned_size = __BIONIC_ALIGN(required_size, PAGE_SIZE); 82 size_t aligned_count = (aligned_size - sizeof(FdTableOverflow)) / sizeof(FdEntry); 83 84 void* allocation = 85 mmap(nullptr, aligned_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 86 if (allocation == MAP_FAILED) { 87 async_safe_fatal("fdsan: mmap failed: %s", strerror(errno)); 88 } 89 90 FdTableOverflow* new_overflow = reinterpret_cast<FdTableOverflow*>(allocation); 91 new_overflow->len = aligned_count; 92 93 if (atomic_compare_exchange_strong(&overflow, &local_overflow, new_overflow)) { 94 local_overflow = new_overflow; 95 } else { 96 // Someone beat us to it. Deallocate and use theirs. 97 munmap(allocation, aligned_size); 98 } 99 } 100 101 size_t offset = idx - inline_fds; 102 if (local_overflow->len < offset) { 103 return nullptr; 104 } 105 return &local_overflow->entries[offset]; 106 } 107 108 void __libc_init_fdsan() { 109 constexpr auto default_level = ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE; 110 const prop_info* pi = __system_property_find(kFdsanPropertyName); 111 if (!pi) { 112 android_fdsan_set_error_level(default_level); 113 return; 114 } 115 __system_property_read_callback( 116 pi, 117 [](void*, const char*, const char* value, uint32_t) { 118 if (strcasecmp(value, "1") == 0 || strcasecmp(value, "fatal") == 0) { 119 android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_FATAL); 120 } else if (strcasecmp(value, "warn") == 0) { 121 android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ALWAYS); 122 } else if (strcasecmp(value, "warn_once") == 0) { 123 android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE); 124 } else { 125 if (strlen(value) != 0 && strcasecmp(value, "0") != 0) { 126 async_safe_format_log(ANDROID_LOG_ERROR, "libc", 127 "debug.fdsan set to unknown value '%s', disabling", value); 128 } 129 android_fdsan_set_error_level(default_level); 130 } 131 }, 132 nullptr); 133 } 134 135 static FdTable& GetFdTable() { 136 return __libc_shared_globals()->fd_table; 137 } 138 139 // Exposed to the platform to allow crash_dump to print out the fd table. 140 extern "C" void* android_fdsan_get_fd_table() { 141 return &GetFdTable(); 142 } 143 144 static FdEntry* GetFdEntry(int fd) { 145 if (fd < 0) { 146 return nullptr; 147 } 148 149 return GetFdTable().at(fd); 150 } 151 152 __printflike(1, 0) static void fdsan_error(const char* fmt, ...) { 153 auto& fd_table = GetFdTable(); 154 155 auto error_level = atomic_load(&fd_table.error_level); 156 if (error_level == ANDROID_FDSAN_ERROR_LEVEL_DISABLED) { 157 return; 158 } 159 160 // Lots of code will (sensibly) fork, blindly call close on all of their fds, 161 // and then exec. Compare our cached pid value against the real one to detect 162 // this scenario and permit it. 163 pid_t cached_pid = __get_cached_pid(); 164 if (cached_pid == 0 || cached_pid != syscall(__NR_getpid)) { 165 return; 166 } 167 168 struct { 169 size_t size; 170 char buf[512]; 171 } abort_message; 172 173 va_list va; 174 va_start(va, fmt); 175 if (error_level == ANDROID_FDSAN_ERROR_LEVEL_FATAL) { 176 async_safe_fatal_va_list("fdsan", fmt, va); 177 } else { 178 async_safe_format_log_va_list(ANDROID_LOG_ERROR, "fdsan", fmt, va); 179 va_end(va); 180 va_start(va, fmt); 181 size_t len = 182 async_safe_format_buffer_va_list(abort_message.buf, sizeof(abort_message.buf), fmt, va); 183 abort_message.size = len + sizeof(size_t); 184 } 185 va_end(va); 186 187 switch (error_level) { 188 case ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE: 189 atomic_compare_exchange_strong(&fd_table.error_level, &error_level, 190 ANDROID_FDSAN_ERROR_LEVEL_DISABLED); 191 __BIONIC_FALLTHROUGH; 192 case ANDROID_FDSAN_ERROR_LEVEL_WARN_ALWAYS: 193 // DEBUGGER_SIGNAL 194 inline_raise(__SIGRTMIN + 3, &abort_message); 195 break; 196 197 case ANDROID_FDSAN_ERROR_LEVEL_FATAL: 198 inline_raise(SIGABRT); 199 abort(); 200 201 case ANDROID_FDSAN_ERROR_LEVEL_DISABLED: 202 break; 203 } 204 } 205 206 uint64_t android_fdsan_create_owner_tag(android_fdsan_owner_type type, uint64_t tag) { 207 if (tag == 0) { 208 return 0; 209 } 210 211 if (__predict_false((type & 0xff) != type)) { 212 async_safe_fatal("invalid android_fdsan_owner_type value: %x", type); 213 } 214 215 uint64_t result = static_cast<uint64_t>(type) << 56; 216 uint64_t mask = (static_cast<uint64_t>(1) << 56) - 1; 217 result |= tag & mask; 218 return result; 219 } 220 221 const char* android_fdsan_get_tag_type(uint64_t tag) { 222 uint64_t type = tag >> 56; 223 switch (type) { 224 case ANDROID_FDSAN_OWNER_TYPE_FILE: 225 return "FILE*"; 226 case ANDROID_FDSAN_OWNER_TYPE_DIR: 227 return "DIR*"; 228 case ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD: 229 return "unique_fd"; 230 case ANDROID_FDSAN_OWNER_TYPE_FILEINPUTSTREAM: 231 return "FileInputStream"; 232 case ANDROID_FDSAN_OWNER_TYPE_FILEOUTPUTSTREAM: 233 return "FileOutputStream"; 234 case ANDROID_FDSAN_OWNER_TYPE_RANDOMACCESSFILE: 235 return "RandomAccessFile"; 236 case ANDROID_FDSAN_OWNER_TYPE_PARCELFILEDESCRIPTOR: 237 return "ParcelFileDescriptor"; 238 case ANDROID_FDSAN_OWNER_TYPE_SQLITE: 239 return "sqlite"; 240 case ANDROID_FDSAN_OWNER_TYPE_ART_FDFILE: 241 return "ART FdFile"; 242 case ANDROID_FDSAN_OWNER_TYPE_DATAGRAMSOCKETIMPL: 243 return "DatagramSocketImpl"; 244 case ANDROID_FDSAN_OWNER_TYPE_SOCKETIMPL: 245 return "SocketImpl"; 246 case ANDROID_FDSAN_OWNER_TYPE_ZIPARCHIVE: 247 return "ZipArchive"; 248 249 case ANDROID_FDSAN_OWNER_TYPE_GENERIC_00: 250 default: 251 return "native object of unknown type"; 252 253 case ANDROID_FDSAN_OWNER_TYPE_GENERIC_FF: 254 // If bits 48 to 56 are set, this is a sign-extended generic native pointer 255 uint64_t high_bits = tag >> 48; 256 if (high_bits == (1 << 16) - 1) { 257 return "native object of unknown type"; 258 } 259 260 return "Java object of unknown type"; 261 } 262 } 263 264 uint64_t android_fdsan_get_tag_value(uint64_t tag) { 265 // Lop off the most significant byte and sign extend. 266 return static_cast<uint64_t>(static_cast<int64_t>(tag << 8) >> 8); 267 } 268 269 int android_fdsan_close_with_tag(int fd, uint64_t expected_tag) { 270 FdEntry* fde = GetFdEntry(fd); 271 if (!fde) { 272 return ___close(fd); 273 } 274 275 uint64_t tag = expected_tag; 276 if (!atomic_compare_exchange_strong(&fde->close_tag, &tag, 0)) { 277 const char* expected_type = android_fdsan_get_tag_type(expected_tag); 278 uint64_t expected_owner = android_fdsan_get_tag_value(expected_tag); 279 const char* actual_type = android_fdsan_get_tag_type(tag); 280 uint64_t actual_owner = android_fdsan_get_tag_value(tag); 281 if (expected_tag && tag) { 282 fdsan_error( 283 "attempted to close file descriptor %d, " 284 "expected to be owned by %s 0x%" PRIx64 ", actually owned by %s 0x%" PRIx64, 285 fd, expected_type, expected_owner, actual_type, actual_owner); 286 } else if (expected_tag && !tag) { 287 fdsan_error( 288 "attempted to close file descriptor %d, " 289 "expected to be owned by %s 0x%" PRIx64 ", actually unowned", 290 fd, expected_type, expected_owner); 291 } else if (!expected_tag && tag) { 292 fdsan_error( 293 "attempted to close file descriptor %d, " 294 "expected to be unowned, actually owned by %s 0x%" PRIx64, 295 fd, actual_type, actual_owner); 296 } else if (!expected_tag && !tag) { 297 // This should never happen: our CAS failed, but expected == actual? 298 async_safe_fatal("fdsan atomic_compare_exchange_strong failed unexpectedly while closing"); 299 } 300 } 301 302 int rc = ___close(fd); 303 // If we were expecting to close with a tag, abort on EBADF. 304 if (expected_tag && rc == -1 && errno == EBADF) { 305 fdsan_error("double-close of file descriptor %d detected", fd); 306 } 307 return rc; 308 } 309 310 uint64_t android_fdsan_get_owner_tag(int fd) { 311 FdEntry* fde = GetFdEntry(fd); 312 if (!fde) { 313 return 0; 314 } 315 return fde->close_tag; 316 } 317 318 void android_fdsan_exchange_owner_tag(int fd, uint64_t expected_tag, uint64_t new_tag) { 319 FdEntry* fde = GetFdEntry(fd); 320 if (!fde) { 321 return; 322 } 323 324 uint64_t tag = expected_tag; 325 if (!atomic_compare_exchange_strong(&fde->close_tag, &tag, new_tag)) { 326 if (expected_tag && tag) { 327 fdsan_error( 328 "failed to exchange ownership of file descriptor: fd %d is " 329 "owned by %s 0x%" PRIx64 ", was expected to be owned by %s 0x%" PRIx64, 330 fd, android_fdsan_get_tag_type(tag), android_fdsan_get_tag_value(tag), 331 android_fdsan_get_tag_type(expected_tag), android_fdsan_get_tag_value(expected_tag)); 332 } else if (expected_tag && !tag) { 333 fdsan_error( 334 "failed to exchange ownership of file descriptor: fd %d is " 335 "unowned, was expected to be owned by %s 0x%" PRIx64, 336 fd, android_fdsan_get_tag_type(expected_tag), android_fdsan_get_tag_value(expected_tag)); 337 } else if (!expected_tag && tag) { 338 fdsan_error( 339 "failed to exchange ownership of file descriptor: fd %d is " 340 "owned by %s 0x%" PRIx64 ", was expected to be unowned", 341 fd, android_fdsan_get_tag_type(tag), android_fdsan_get_tag_value(tag)); 342 } else if (!expected_tag && !tag) { 343 // This should never happen: our CAS failed, but expected == actual? 344 async_safe_fatal( 345 "fdsan atomic_compare_exchange_strong failed unexpectedly while exchanging owner tag"); 346 } 347 } 348 } 349 350 android_fdsan_error_level android_fdsan_get_error_level() { 351 return GetFdTable().error_level; 352 } 353 354 android_fdsan_error_level android_fdsan_set_error_level(android_fdsan_error_level new_level) { 355 return atomic_exchange(&GetFdTable().error_level, new_level); 356 } 357 358 int close(int fd) { 359 int rc = android_fdsan_close_with_tag(fd, 0); 360 if (rc == -1 && errno == EINTR) { 361 return 0; 362 } 363 return rc; 364 } 365