1*8d67ca89SAndroid Build Coastguard Worker## fdsan 2*8d67ca89SAndroid Build Coastguard Worker 3*8d67ca89SAndroid Build Coastguard Worker[TOC] 4*8d67ca89SAndroid Build Coastguard Worker 5*8d67ca89SAndroid Build Coastguard Workerfdsan is a file descriptor sanitizer added to Android in API level 29. 6*8d67ca89SAndroid Build Coastguard WorkerIn API level 29, fdsan warns when it finds a bug. 7*8d67ca89SAndroid Build Coastguard WorkerIn API level 30, fdsan aborts when it finds a bug. 8*8d67ca89SAndroid Build Coastguard Worker 9*8d67ca89SAndroid Build Coastguard Worker### Background 10*8d67ca89SAndroid Build Coastguard Worker*What problem is fdsan trying to solve? Why should I care?* 11*8d67ca89SAndroid Build Coastguard Worker 12*8d67ca89SAndroid Build Coastguard Workerfdsan (file descriptor sanitizer) detects mishandling of file descriptor ownership, which tend to manifest as *use-after-close* and *double-close*. These errors are direct analogues of the memory allocation *use-after-free* and *double-free* bugs, but tend to be much more difficult to diagnose and fix. With `malloc` and `free`, implementations have free reign to detect errors and abort on double free. File descriptors, on the other hand, are mandated by the POSIX standard to be allocated with the lowest available number being returned for new allocations. As a result, many file descriptor bugs can *never* be noticed on the thread on which the error occurred, and will manifest as "impossible" behavior on another thread. 13*8d67ca89SAndroid Build Coastguard Worker 14*8d67ca89SAndroid Build Coastguard WorkerFor example, given two threads running the following code: 15*8d67ca89SAndroid Build Coastguard Worker```cpp 16*8d67ca89SAndroid Build Coastguard Workervoid thread_one() { 17*8d67ca89SAndroid Build Coastguard Worker int fd = open("/dev/null", O_RDONLY); 18*8d67ca89SAndroid Build Coastguard Worker close(fd); 19*8d67ca89SAndroid Build Coastguard Worker close(fd); 20*8d67ca89SAndroid Build Coastguard Worker} 21*8d67ca89SAndroid Build Coastguard Worker 22*8d67ca89SAndroid Build Coastguard Workervoid thread_two() { 23*8d67ca89SAndroid Build Coastguard Worker while (true) { 24*8d67ca89SAndroid Build Coastguard Worker int fd = open("log", O_WRONLY | O_APPEND); 25*8d67ca89SAndroid Build Coastguard Worker if (write(fd, "foo", 3) != 3) { 26*8d67ca89SAndroid Build Coastguard Worker err(1, "write failed!"); 27*8d67ca89SAndroid Build Coastguard Worker } 28*8d67ca89SAndroid Build Coastguard Worker } 29*8d67ca89SAndroid Build Coastguard Worker} 30*8d67ca89SAndroid Build Coastguard Worker``` 31*8d67ca89SAndroid Build Coastguard Workerthe following interleaving is possible: 32*8d67ca89SAndroid Build Coastguard Worker```cpp 33*8d67ca89SAndroid Build Coastguard Workerthread one thread two 34*8d67ca89SAndroid Build Coastguard Workeropen("/dev/null", O_RDONLY) = 123 35*8d67ca89SAndroid Build Coastguard Workerclose(123) = 0 36*8d67ca89SAndroid Build Coastguard Worker open("log", O_WRONLY | APPEND) = 123 37*8d67ca89SAndroid Build Coastguard Workerclose(123) = 0 38*8d67ca89SAndroid Build Coastguard Worker write(123, "foo", 3) = -1 (EBADF) 39*8d67ca89SAndroid Build Coastguard Worker err(1, "write failed!") 40*8d67ca89SAndroid Build Coastguard Worker``` 41*8d67ca89SAndroid Build Coastguard Worker 42*8d67ca89SAndroid Build Coastguard WorkerAssertion failures are probably the most innocuous result that can arise from these bugs: silent data corruption [[1](#footnotes), [2](#footnotes)] or security vulnerabilities are also possible (e.g. suppose thread two was saving user data to disk when a third thread came in and opened a socket to the Internet). 43*8d67ca89SAndroid Build Coastguard Worker 44*8d67ca89SAndroid Build Coastguard Worker### Design 45*8d67ca89SAndroid Build Coastguard Worker*What does fdsan do?* 46*8d67ca89SAndroid Build Coastguard Worker 47*8d67ca89SAndroid Build Coastguard Workerfdsan attempts to detect and/or prevent file descriptor mismanagement by enforcing file descriptor ownership. Like how most memory allocations can have their ownership handled by types such as `std::unique_ptr`, almost all file descriptors can be associated with a unique owner which is responsible for their closure. fdsan provides functions to associate a file descriptor with an owner; if someone tries to close a file descriptor that they don't own, depending on configuration, either a warning is emitted, or the process aborts. 48*8d67ca89SAndroid Build Coastguard Worker 49*8d67ca89SAndroid Build Coastguard WorkerThe way this is implemented is by providing functions to set a 64-bit closure tag on a file descriptor. The tag consists of an 8-bit type byte that identifies the type of the owner (`enum android_fdan_owner_type` in [`<android/fdsan.h>`](https://android.googlesource.com/platform/bionic/+/main/libc/include/android/fdsan.h)), and a 56-bit value. The value should ideally be something that uniquely identifies the object (object address for native objects and `System.identityHashCode` for Java objects), but in cases where it's hard to derive an identifier for the "owner" that should close a file descriptor, even using the same value for all file descriptors in the module can be useful, since it'll catch other code that closes your file descriptors. 50*8d67ca89SAndroid Build Coastguard Worker 51*8d67ca89SAndroid Build Coastguard WorkerIf a file descriptor that's been marked with a tag is closed with an incorrect tag, or without a tag, we know something has gone wrong, and can generate diagnostics or abort. 52*8d67ca89SAndroid Build Coastguard Worker 53*8d67ca89SAndroid Build Coastguard Worker### Enabling fdsan (as a user) 54*8d67ca89SAndroid Build Coastguard Worker*How do I use fdsan?* 55*8d67ca89SAndroid Build Coastguard Worker 56*8d67ca89SAndroid Build Coastguard Workerfdsan has four severity levels: 57*8d67ca89SAndroid Build Coastguard Worker - disabled (`ANDROID_FDSAN_ERROR_LEVEL_DISABLED`) 58*8d67ca89SAndroid Build Coastguard Worker - warn-once (`ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE`) 59*8d67ca89SAndroid Build Coastguard Worker - Upon detecting an error, emit a warning to logcat, generate a tombstone, and then continue execution with fdsan disabled. 60*8d67ca89SAndroid Build Coastguard Worker - warn-always (`ANDROID_FDSAN_ERROR_LEVEL_WARN_ALWAYS`) 61*8d67ca89SAndroid Build Coastguard Worker - Same as warn-once, except without disabling after the first warning. 62*8d67ca89SAndroid Build Coastguard Worker - fatal (`ANDROID_FDSAN_ERROR_LEVEL_FATAL`) 63*8d67ca89SAndroid Build Coastguard Worker - Abort upon detecting an error. 64*8d67ca89SAndroid Build Coastguard Worker 65*8d67ca89SAndroid Build Coastguard WorkerIn API level 29, fdsan had a global default of warn-once. 66*8d67ca89SAndroid Build Coastguard WorkerIn API level 30 and higher, fdsan has a global default of fatal. 67*8d67ca89SAndroid Build Coastguard Workerfdsan can be made more or less strict at runtime via the `android_fdsan_set_error_level` function in [`<android/fdsan.h>`](https://android.googlesource.com/platform/bionic/+/main/libc/include/android/fdsan.h). 68*8d67ca89SAndroid Build Coastguard Worker 69*8d67ca89SAndroid Build Coastguard WorkerThe likelihood of fdsan catching a file descriptor error is proportional to the percentage of file descriptors in your process that are tagged with an owner. 70*8d67ca89SAndroid Build Coastguard Worker 71*8d67ca89SAndroid Build Coastguard Worker### Using fdsan to fix a bug 72*8d67ca89SAndroid Build Coastguard Worker*No, really, how do I use fdsan?* 73*8d67ca89SAndroid Build Coastguard Worker 74*8d67ca89SAndroid Build Coastguard WorkerLet's look at a simple contrived example that uses sleeps to force a particular interleaving of thread execution. 75*8d67ca89SAndroid Build Coastguard Worker 76*8d67ca89SAndroid Build Coastguard Worker```cpp 77*8d67ca89SAndroid Build Coastguard Worker#include <err.h> 78*8d67ca89SAndroid Build Coastguard Worker#include <unistd.h> 79*8d67ca89SAndroid Build Coastguard Worker 80*8d67ca89SAndroid Build Coastguard Worker#include <chrono> 81*8d67ca89SAndroid Build Coastguard Worker#include <thread> 82*8d67ca89SAndroid Build Coastguard Worker#include <vector> 83*8d67ca89SAndroid Build Coastguard Worker 84*8d67ca89SAndroid Build Coastguard Worker#include <android-base/unique_fd.h> 85*8d67ca89SAndroid Build Coastguard Worker 86*8d67ca89SAndroid Build Coastguard Workerusing namespace std::chrono_literals; 87*8d67ca89SAndroid Build Coastguard Workerusing std::this_thread::sleep_for; 88*8d67ca89SAndroid Build Coastguard Worker 89*8d67ca89SAndroid Build Coastguard Workervoid victim() { 90*8d67ca89SAndroid Build Coastguard Worker sleep_for(300ms); 91*8d67ca89SAndroid Build Coastguard Worker int fd = dup(STDOUT_FILENO); 92*8d67ca89SAndroid Build Coastguard Worker sleep_for(200ms); 93*8d67ca89SAndroid Build Coastguard Worker ssize_t rc = write(fd, "good\n", 5); 94*8d67ca89SAndroid Build Coastguard Worker if (rc == -1) { 95*8d67ca89SAndroid Build Coastguard Worker err(1, "good failed to write?!"); 96*8d67ca89SAndroid Build Coastguard Worker } 97*8d67ca89SAndroid Build Coastguard Worker close(fd); 98*8d67ca89SAndroid Build Coastguard Worker} 99*8d67ca89SAndroid Build Coastguard Worker 100*8d67ca89SAndroid Build Coastguard Workervoid bystander() { 101*8d67ca89SAndroid Build Coastguard Worker sleep_for(100ms); 102*8d67ca89SAndroid Build Coastguard Worker int fd = dup(STDOUT_FILENO); 103*8d67ca89SAndroid Build Coastguard Worker sleep_for(300ms); 104*8d67ca89SAndroid Build Coastguard Worker close(fd); 105*8d67ca89SAndroid Build Coastguard Worker} 106*8d67ca89SAndroid Build Coastguard Worker 107*8d67ca89SAndroid Build Coastguard Workervoid offender() { 108*8d67ca89SAndroid Build Coastguard Worker int fd = dup(STDOUT_FILENO); 109*8d67ca89SAndroid Build Coastguard Worker close(fd); 110*8d67ca89SAndroid Build Coastguard Worker sleep_for(200ms); 111*8d67ca89SAndroid Build Coastguard Worker close(fd); 112*8d67ca89SAndroid Build Coastguard Worker} 113*8d67ca89SAndroid Build Coastguard Worker 114*8d67ca89SAndroid Build Coastguard Workerint main() { 115*8d67ca89SAndroid Build Coastguard Worker std::vector<std::thread> threads; 116*8d67ca89SAndroid Build Coastguard Worker for (auto function : { victim, bystander, offender }) { 117*8d67ca89SAndroid Build Coastguard Worker threads.emplace_back(function); 118*8d67ca89SAndroid Build Coastguard Worker } 119*8d67ca89SAndroid Build Coastguard Worker for (auto& thread : threads) { 120*8d67ca89SAndroid Build Coastguard Worker thread.join(); 121*8d67ca89SAndroid Build Coastguard Worker } 122*8d67ca89SAndroid Build Coastguard Worker} 123*8d67ca89SAndroid Build Coastguard Worker``` 124*8d67ca89SAndroid Build Coastguard Worker 125*8d67ca89SAndroid Build Coastguard WorkerWhen running the program, the threads' executions will be interleaved as follows: 126*8d67ca89SAndroid Build Coastguard Worker 127*8d67ca89SAndroid Build Coastguard Worker```cpp 128*8d67ca89SAndroid Build Coastguard Worker// victim bystander offender 129*8d67ca89SAndroid Build Coastguard Worker int fd = dup(1); // 3 130*8d67ca89SAndroid Build Coastguard Worker close(3); 131*8d67ca89SAndroid Build Coastguard Worker int fd = dup(1); // 3 132*8d67ca89SAndroid Build Coastguard Worker close(3); 133*8d67ca89SAndroid Build Coastguard Workerint fd = dup(1); // 3 134*8d67ca89SAndroid Build Coastguard Worker close(3); 135*8d67ca89SAndroid Build Coastguard Workerwrite(3, "good\n") = ; 136*8d67ca89SAndroid Build Coastguard Worker``` 137*8d67ca89SAndroid Build Coastguard Worker 138*8d67ca89SAndroid Build Coastguard Workerwhich results in the following output: 139*8d67ca89SAndroid Build Coastguard Worker 140*8d67ca89SAndroid Build Coastguard Worker fdsan_test: good failed to write?!: Bad file descriptor 141*8d67ca89SAndroid Build Coastguard Worker 142*8d67ca89SAndroid Build Coastguard WorkerThis implies that either we're accidentally closing out file descriptor too early, or someone else is helpfully closing it for us. Let's use `android::base::unique_fd` in `victim` to guard the file descriptor with fdsan: 143*8d67ca89SAndroid Build Coastguard Worker 144*8d67ca89SAndroid Build Coastguard Worker```diff 145*8d67ca89SAndroid Build Coastguard Worker--- a/fdsan_test.cpp 146*8d67ca89SAndroid Build Coastguard Worker+++ b/fdsan_test.cpp 147*8d67ca89SAndroid Build Coastguard Worker@@ -12,13 +12,12 @@ using std::this_thread::sleep_for; 148*8d67ca89SAndroid Build Coastguard Worker 149*8d67ca89SAndroid Build Coastguard Worker void victim() { 150*8d67ca89SAndroid Build Coastguard Worker sleep_for(200ms); 151*8d67ca89SAndroid Build Coastguard Worker- int fd = dup(STDOUT_FILENO); 152*8d67ca89SAndroid Build Coastguard Worker+ android::base::unique_fd fd(dup(STDOUT_FILENO)); 153*8d67ca89SAndroid Build Coastguard Worker sleep_for(200ms); 154*8d67ca89SAndroid Build Coastguard Worker ssize_t rc = write(fd, "good\n", 5); 155*8d67ca89SAndroid Build Coastguard Worker if (rc == -1) { 156*8d67ca89SAndroid Build Coastguard Worker err(1, "good failed to write?!"); 157*8d67ca89SAndroid Build Coastguard Worker } 158*8d67ca89SAndroid Build Coastguard Worker- close(fd); 159*8d67ca89SAndroid Build Coastguard Worker } 160*8d67ca89SAndroid Build Coastguard Worker 161*8d67ca89SAndroid Build Coastguard Worker void bystander() { 162*8d67ca89SAndroid Build Coastguard Worker``` 163*8d67ca89SAndroid Build Coastguard Worker 164*8d67ca89SAndroid Build Coastguard WorkerNow that we've guarded the file descriptor with fdsan, we should be able to find where the double close is: 165*8d67ca89SAndroid Build Coastguard Worker 166*8d67ca89SAndroid Build Coastguard Worker``` 167*8d67ca89SAndroid Build Coastguard Workerpid: 25587, tid: 25589, name: fdsan_test >>> fdsan_test <<< 168*8d67ca89SAndroid Build Coastguard Workersignal 35 (<debuggerd signal>), code -1 (SI_QUEUE), fault addr -------- 169*8d67ca89SAndroid Build Coastguard WorkerAbort message: 'attempted to close file descriptor 3, expected to be unowned, actually owned by unique_fd 0x7bf15dc448' 170*8d67ca89SAndroid Build Coastguard Worker x0 0000000000000000 x1 00000000000063f5 x2 0000000000000023 x3 0000007bf14de338 171*8d67ca89SAndroid Build Coastguard Worker x4 0000007bf14de3b8 x5 3463643531666237 x6 3463643531666237 x7 3834346364353166 172*8d67ca89SAndroid Build Coastguard Worker x8 00000000000000f0 x9 0000000000000000 x10 0000000000000059 x11 0000000000000035 173*8d67ca89SAndroid Build Coastguard Worker x12 0000007bf1bebcfa x13 0000007bf14ddf0a x14 0000007bf14ddf0a x15 0000000000000000 174*8d67ca89SAndroid Build Coastguard Worker x16 0000007bf1c33048 x17 0000007bf1ba9990 x18 0000000000000000 x19 00000000000063f3 175*8d67ca89SAndroid Build Coastguard Worker x20 00000000000063f5 x21 0000007bf14de588 x22 0000007bf1f1b864 x23 0000000000000001 176*8d67ca89SAndroid Build Coastguard Worker x24 0000007bf14de130 x25 0000007bf13e1000 x26 0000007bf1f1f580 x27 0000005ab43ab8f0 177*8d67ca89SAndroid Build Coastguard Worker x28 0000000000000000 x29 0000007bf14de400 178*8d67ca89SAndroid Build Coastguard Worker sp 0000007bf14ddff0 lr 0000007bf1b5fd6c pc 0000007bf1b5fd90 179*8d67ca89SAndroid Build Coastguard Worker 180*8d67ca89SAndroid Build Coastguard Workerbacktrace: 181*8d67ca89SAndroid Build Coastguard Worker #00 pc 0000000000008d90 /system/lib64/libc.so (fdsan_error(char const*, ...)+384) 182*8d67ca89SAndroid Build Coastguard Worker #01 pc 0000000000008ba8 /system/lib64/libc.so (android_fdsan_close_with_tag+632) 183*8d67ca89SAndroid Build Coastguard Worker #02 pc 00000000000092a0 /system/lib64/libc.so (close+16) 184*8d67ca89SAndroid Build Coastguard Worker #03 pc 00000000000003e4 /system/bin/fdsan_test (bystander()+84) 185*8d67ca89SAndroid Build Coastguard Worker #04 pc 0000000000000918 /system/bin/fdsan_test 186*8d67ca89SAndroid Build Coastguard Worker #05 pc 000000000006689c /system/lib64/libc.so (__pthread_start(void*)+36) 187*8d67ca89SAndroid Build Coastguard Worker #06 pc 000000000000712c /system/lib64/libc.so (__start_thread+68) 188*8d67ca89SAndroid Build Coastguard Worker``` 189*8d67ca89SAndroid Build Coastguard Worker 190*8d67ca89SAndroid Build Coastguard Worker...in the obviously correct bystander? What's going on here? 191*8d67ca89SAndroid Build Coastguard Worker 192*8d67ca89SAndroid Build Coastguard WorkerThe reason for this is (hopefully!) not a bug in fdsan, and will commonly be seen when tracking down double-closes in processes that have sparse fdsan coverage. What actually happened is that the culprit closed `bystander`'s file descriptor between its open and close, which resulted in `bystander` being blamed for closing `victim`'s fd. If we store `bystander`'s fd in a `unique_fd` as well, we should get something more useful: 193*8d67ca89SAndroid Build Coastguard Worker```diff 194*8d67ca89SAndroid Build Coastguard Worker--- a/tmp/fdsan_test.cpp 195*8d67ca89SAndroid Build Coastguard Worker+++ b/tmp/fdsan_test.cpp 196*8d67ca89SAndroid Build Coastguard Worker@@ -23,9 +23,8 @@ void victim() { 197*8d67ca89SAndroid Build Coastguard Worker 198*8d67ca89SAndroid Build Coastguard Worker void bystander() { 199*8d67ca89SAndroid Build Coastguard Worker sleep_for(100ms); 200*8d67ca89SAndroid Build Coastguard Worker- int fd = dup(STDOUT_FILENO); 201*8d67ca89SAndroid Build Coastguard Worker+ android::base::unique_fd fd(dup(STDOUT_FILENO)); 202*8d67ca89SAndroid Build Coastguard Worker sleep_for(200ms); 203*8d67ca89SAndroid Build Coastguard Worker- close(fd); 204*8d67ca89SAndroid Build Coastguard Worker } 205*8d67ca89SAndroid Build Coastguard Worker``` 206*8d67ca89SAndroid Build Coastguard Workergiving us: 207*8d67ca89SAndroid Build Coastguard Worker``` 208*8d67ca89SAndroid Build Coastguard Workerpid: 25779, tid: 25782, name: fdsan_test >>> fdsan_test <<< 209*8d67ca89SAndroid Build Coastguard Workersignal 35 (<debuggerd signal>), code -1 (SI_QUEUE), fault addr -------- 210*8d67ca89SAndroid Build Coastguard WorkerAbort message: 'attempted to close file descriptor 3, expected to be unowned, actually owned by unique_fd 0x6fef9ff448' 211*8d67ca89SAndroid Build Coastguard Worker x0 0000000000000000 x1 00000000000064b6 x2 0000000000000023 x3 0000006fef901338 212*8d67ca89SAndroid Build Coastguard Worker x4 0000006fef9013b8 x5 3466663966656636 x6 3466663966656636 x7 3834346666396665 213*8d67ca89SAndroid Build Coastguard Worker x8 00000000000000f0 x9 0000000000000000 x10 0000000000000059 x11 0000000000000039 214*8d67ca89SAndroid Build Coastguard Worker x12 0000006ff0055cfa x13 0000006fef900f0a x14 0000006fef900f0a x15 0000000000000000 215*8d67ca89SAndroid Build Coastguard Worker x16 0000006ff009d048 x17 0000006ff0013990 x18 0000000000000000 x19 00000000000064b3 216*8d67ca89SAndroid Build Coastguard Worker x20 00000000000064b6 x21 0000006fef901588 x22 0000006ff04ff864 x23 0000000000000001 217*8d67ca89SAndroid Build Coastguard Worker x24 0000006fef901130 x25 0000006fef804000 x26 0000006ff0503580 x27 0000006368aa18f8 218*8d67ca89SAndroid Build Coastguard Worker x28 0000000000000000 x29 0000006fef901400 219*8d67ca89SAndroid Build Coastguard Worker sp 0000006fef900ff0 lr 0000006feffc9d6c pc 0000006feffc9d90 220*8d67ca89SAndroid Build Coastguard Worker 221*8d67ca89SAndroid Build Coastguard Workerbacktrace: 222*8d67ca89SAndroid Build Coastguard Worker #00 pc 0000000000008d90 /system/lib64/libc.so (fdsan_error(char const*, ...)+384) 223*8d67ca89SAndroid Build Coastguard Worker #01 pc 0000000000008ba8 /system/lib64/libc.so (android_fdsan_close_with_tag+632) 224*8d67ca89SAndroid Build Coastguard Worker #02 pc 00000000000092a0 /system/lib64/libc.so (close+16) 225*8d67ca89SAndroid Build Coastguard Worker #03 pc 000000000000045c /system/bin/fdsan_test (offender()+68) 226*8d67ca89SAndroid Build Coastguard Worker #04 pc 0000000000000920 /system/bin/fdsan_test 227*8d67ca89SAndroid Build Coastguard Worker #05 pc 000000000006689c /system/lib64/libc.so (__pthread_start(void*)+36) 228*8d67ca89SAndroid Build Coastguard Worker #06 pc 000000000000712c /system/lib64/libc.so (__start_thread+68) 229*8d67ca89SAndroid Build Coastguard Worker``` 230*8d67ca89SAndroid Build Coastguard Worker 231*8d67ca89SAndroid Build Coastguard WorkerHooray! 232*8d67ca89SAndroid Build Coastguard Worker 233*8d67ca89SAndroid Build Coastguard WorkerIn a real application, things are probably not going to be as detectable or reproducible as our toy example, which is a good reason to try to maximize the usage of fdsan-enabled types like `unique_fd` and `ParcelFileDescriptor`, to improve the odds that double closes in other code get detected. 234*8d67ca89SAndroid Build Coastguard Worker 235*8d67ca89SAndroid Build Coastguard Worker### Enabling fdsan (as a C++ library implementer) 236*8d67ca89SAndroid Build Coastguard Worker 237*8d67ca89SAndroid Build Coastguard Workerfdsan operates via two main primitives. `android_fdsan_exchange_owner_tag` modifies a file descriptor's close tag, and `android_fdsan_close_with_tag` closes a file descriptor with its tag. In the `<android/fdsan.h>` header, these are marked with `__attribute__((weak))`, so instead of passing down the platform version from JNI, availability of the functions can be queried directly. An example implementation of unique_fd follows: 238*8d67ca89SAndroid Build Coastguard Worker 239*8d67ca89SAndroid Build Coastguard Worker```cpp 240*8d67ca89SAndroid Build Coastguard Worker/* 241*8d67ca89SAndroid Build Coastguard Worker * Copyright (C) 2018 The Android Open Source Project 242*8d67ca89SAndroid Build Coastguard Worker * All rights reserved. 243*8d67ca89SAndroid Build Coastguard Worker * 244*8d67ca89SAndroid Build Coastguard Worker * Redistribution and use in source and binary forms, with or without 245*8d67ca89SAndroid Build Coastguard Worker * modification, are permitted provided that the following conditions 246*8d67ca89SAndroid Build Coastguard Worker * are met: 247*8d67ca89SAndroid Build Coastguard Worker * * Redistributions of source code must retain the above copyright 248*8d67ca89SAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer. 249*8d67ca89SAndroid Build Coastguard Worker * * Redistributions in binary form must reproduce the above copyright 250*8d67ca89SAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer in 251*8d67ca89SAndroid Build Coastguard Worker * the documentation and/or other materials provided with the 252*8d67ca89SAndroid Build Coastguard Worker * distribution. 253*8d67ca89SAndroid Build Coastguard Worker * 254*8d67ca89SAndroid Build Coastguard Worker * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 255*8d67ca89SAndroid Build Coastguard Worker * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 256*8d67ca89SAndroid Build Coastguard Worker * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 257*8d67ca89SAndroid Build Coastguard Worker * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 258*8d67ca89SAndroid Build Coastguard Worker * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 259*8d67ca89SAndroid Build Coastguard Worker * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 260*8d67ca89SAndroid Build Coastguard Worker * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 261*8d67ca89SAndroid Build Coastguard Worker * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 262*8d67ca89SAndroid Build Coastguard Worker * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 263*8d67ca89SAndroid Build Coastguard Worker * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 264*8d67ca89SAndroid Build Coastguard Worker * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 265*8d67ca89SAndroid Build Coastguard Worker * SUCH DAMAGE. 266*8d67ca89SAndroid Build Coastguard Worker */ 267*8d67ca89SAndroid Build Coastguard Worker 268*8d67ca89SAndroid Build Coastguard Worker#pragma once 269*8d67ca89SAndroid Build Coastguard Worker 270*8d67ca89SAndroid Build Coastguard Worker#include <android/fdsan.h> 271*8d67ca89SAndroid Build Coastguard Worker#include <unistd.h> 272*8d67ca89SAndroid Build Coastguard Worker 273*8d67ca89SAndroid Build Coastguard Worker#include <utility> 274*8d67ca89SAndroid Build Coastguard Worker 275*8d67ca89SAndroid Build Coastguard Workerstruct unique_fd { 276*8d67ca89SAndroid Build Coastguard Worker unique_fd() = default; 277*8d67ca89SAndroid Build Coastguard Worker 278*8d67ca89SAndroid Build Coastguard Worker explicit unique_fd(int fd) { 279*8d67ca89SAndroid Build Coastguard Worker reset(fd); 280*8d67ca89SAndroid Build Coastguard Worker } 281*8d67ca89SAndroid Build Coastguard Worker 282*8d67ca89SAndroid Build Coastguard Worker unique_fd(const unique_fd& copy) = delete; 283*8d67ca89SAndroid Build Coastguard Worker unique_fd(unique_fd&& move) { 284*8d67ca89SAndroid Build Coastguard Worker *this = std::move(move); 285*8d67ca89SAndroid Build Coastguard Worker } 286*8d67ca89SAndroid Build Coastguard Worker 287*8d67ca89SAndroid Build Coastguard Worker ~unique_fd() { 288*8d67ca89SAndroid Build Coastguard Worker reset(); 289*8d67ca89SAndroid Build Coastguard Worker } 290*8d67ca89SAndroid Build Coastguard Worker 291*8d67ca89SAndroid Build Coastguard Worker unique_fd& operator=(const unique_fd& copy) = delete; 292*8d67ca89SAndroid Build Coastguard Worker unique_fd& operator=(unique_fd&& move) { 293*8d67ca89SAndroid Build Coastguard Worker if (this == &move) { 294*8d67ca89SAndroid Build Coastguard Worker return *this; 295*8d67ca89SAndroid Build Coastguard Worker } 296*8d67ca89SAndroid Build Coastguard Worker 297*8d67ca89SAndroid Build Coastguard Worker reset(); 298*8d67ca89SAndroid Build Coastguard Worker 299*8d67ca89SAndroid Build Coastguard Worker if (move.fd_ != -1) { 300*8d67ca89SAndroid Build Coastguard Worker fd_ = move.fd_; 301*8d67ca89SAndroid Build Coastguard Worker move.fd_ = -1; 302*8d67ca89SAndroid Build Coastguard Worker 303*8d67ca89SAndroid Build Coastguard Worker // Acquire ownership from the moved-from object. 304*8d67ca89SAndroid Build Coastguard Worker exchange_tag(fd_, move.tag(), tag()); 305*8d67ca89SAndroid Build Coastguard Worker } 306*8d67ca89SAndroid Build Coastguard Worker 307*8d67ca89SAndroid Build Coastguard Worker return *this; 308*8d67ca89SAndroid Build Coastguard Worker } 309*8d67ca89SAndroid Build Coastguard Worker 310*8d67ca89SAndroid Build Coastguard Worker int get() { return fd_; } 311*8d67ca89SAndroid Build Coastguard Worker 312*8d67ca89SAndroid Build Coastguard Worker int release() { 313*8d67ca89SAndroid Build Coastguard Worker if (fd_ == -1) { 314*8d67ca89SAndroid Build Coastguard Worker return -1; 315*8d67ca89SAndroid Build Coastguard Worker } 316*8d67ca89SAndroid Build Coastguard Worker 317*8d67ca89SAndroid Build Coastguard Worker int fd = fd_; 318*8d67ca89SAndroid Build Coastguard Worker fd_ = -1; 319*8d67ca89SAndroid Build Coastguard Worker 320*8d67ca89SAndroid Build Coastguard Worker // Release ownership. 321*8d67ca89SAndroid Build Coastguard Worker exchange_tag(fd, tag(), 0); 322*8d67ca89SAndroid Build Coastguard Worker return fd; 323*8d67ca89SAndroid Build Coastguard Worker } 324*8d67ca89SAndroid Build Coastguard Worker 325*8d67ca89SAndroid Build Coastguard Worker void reset(int new_fd = -1) { 326*8d67ca89SAndroid Build Coastguard Worker if (fd_ != -1) { 327*8d67ca89SAndroid Build Coastguard Worker close(fd_, tag()); 328*8d67ca89SAndroid Build Coastguard Worker fd_ = -1; 329*8d67ca89SAndroid Build Coastguard Worker } 330*8d67ca89SAndroid Build Coastguard Worker 331*8d67ca89SAndroid Build Coastguard Worker if (new_fd != -1) { 332*8d67ca89SAndroid Build Coastguard Worker fd_ = new_fd; 333*8d67ca89SAndroid Build Coastguard Worker 334*8d67ca89SAndroid Build Coastguard Worker // Acquire ownership of the presumably unowned fd. 335*8d67ca89SAndroid Build Coastguard Worker exchange_tag(fd_, 0, tag()); 336*8d67ca89SAndroid Build Coastguard Worker } 337*8d67ca89SAndroid Build Coastguard Worker } 338*8d67ca89SAndroid Build Coastguard Worker 339*8d67ca89SAndroid Build Coastguard Worker private: 340*8d67ca89SAndroid Build Coastguard Worker int fd_ = -1; 341*8d67ca89SAndroid Build Coastguard Worker 342*8d67ca89SAndroid Build Coastguard Worker // The obvious choice of tag to use is the address of the object. 343*8d67ca89SAndroid Build Coastguard Worker uint64_t tag() { 344*8d67ca89SAndroid Build Coastguard Worker return reinterpret_cast<uint64_t>(this); 345*8d67ca89SAndroid Build Coastguard Worker } 346*8d67ca89SAndroid Build Coastguard Worker 347*8d67ca89SAndroid Build Coastguard Worker // These functions are marked with __attribute__((weak)), so that their 348*8d67ca89SAndroid Build Coastguard Worker // availability can be determined at runtime. These wrappers will use them 349*8d67ca89SAndroid Build Coastguard Worker // if available, and fall back to no-ops or regular close on devices older 350*8d67ca89SAndroid Build Coastguard Worker // than API level 29. 351*8d67ca89SAndroid Build Coastguard Worker static void exchange_tag(int fd, uint64_t old_tag, uint64_t new_tag) { 352*8d67ca89SAndroid Build Coastguard Worker if (android_fdsan_exchange_owner_tag) { 353*8d67ca89SAndroid Build Coastguard Worker android_fdsan_exchange_owner_tag(fd, old_tag, new_tag); 354*8d67ca89SAndroid Build Coastguard Worker } 355*8d67ca89SAndroid Build Coastguard Worker } 356*8d67ca89SAndroid Build Coastguard Worker 357*8d67ca89SAndroid Build Coastguard Worker static int close(int fd, uint64_t tag) { 358*8d67ca89SAndroid Build Coastguard Worker if (android_fdsan_close_with_tag) { 359*8d67ca89SAndroid Build Coastguard Worker return android_fdsan_close_with_tag(fd, tag); 360*8d67ca89SAndroid Build Coastguard Worker } else { 361*8d67ca89SAndroid Build Coastguard Worker return ::close(fd); 362*8d67ca89SAndroid Build Coastguard Worker } 363*8d67ca89SAndroid Build Coastguard Worker } 364*8d67ca89SAndroid Build Coastguard Worker}; 365*8d67ca89SAndroid Build Coastguard Worker``` 366*8d67ca89SAndroid Build Coastguard Worker 367*8d67ca89SAndroid Build Coastguard Worker### Frequently seen bugs 368*8d67ca89SAndroid Build Coastguard Worker * Native APIs not making it clear when they take ownership of a file descriptor. <br/> 369*8d67ca89SAndroid Build Coastguard Worker * Solution: accept `unique_fd` instead of `int` in functions that take ownership. 370*8d67ca89SAndroid Build Coastguard Worker * [Example one](https://android-review.googlesource.com/c/platform/system/core/+/721985), [two](https://android-review.googlesource.com/c/platform/frameworks/native/+/709451) 371*8d67ca89SAndroid Build Coastguard Worker * Receiving a `ParcelFileDescriptor` via Intent, and then passing it into JNI code that ends up calling close on it. <br/> 372*8d67ca89SAndroid Build Coastguard Worker * Solution: ¯\\\_(ツ)\_/¯. Use fdsan? 373*8d67ca89SAndroid Build Coastguard Worker * [Example one](https://android-review.googlesource.com/c/platform/system/bt/+/710104), [two](https://android-review.googlesource.com/c/platform/frameworks/base/+/732305) 374*8d67ca89SAndroid Build Coastguard Worker 375*8d67ca89SAndroid Build Coastguard Worker### Footnotes 376*8d67ca89SAndroid Build Coastguard Worker1. [How To Corrupt An SQLite Database File](https://www.sqlite.org/howtocorrupt.html#_continuing_to_use_a_file_descriptor_after_it_has_been_closed) 377*8d67ca89SAndroid Build Coastguard Worker 378*8d67ca89SAndroid Build Coastguard Worker2. [<b><i>50%</i></b> of Facebook's iOS crashes caused by a file descriptor double close leading to SQLite database corruption](https://code.fb.com/ios/debugging-file-corruption-on-ios/) 379