Introduce api to track fd ownership in libc.
Add two functions to allow objects that own a file descriptor to
enforce that only they can close their file descriptor.
Use them in FILE* and DIR*.
Bug: http://b/110100358
Test: bionic_unit_tests
Test: aosp/master boots without errors
Test: treehugger
Change-Id: Iecd6e8b26c62217271e0822dc3d2d7888b091a45
diff --git a/libc/stdio/stdio.cpp b/libc/stdio/stdio.cpp
index 1f08ea1..050157b 100644
--- a/libc/stdio/stdio.cpp
+++ b/libc/stdio/stdio.cpp
@@ -46,6 +46,8 @@
#include <sys/wait.h>
#include <unistd.h>
+#include <android/fdsan.h>
+
#include <async_safe/log.h>
#include "local.h"
@@ -54,6 +56,8 @@
#include "private/ErrnoRestorer.h"
#include "private/thread_private.h"
+extern "C" int ___close(int fd);
+
#define ALIGNBYTES (sizeof(uintptr_t) - 1)
#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES)
@@ -102,6 +106,19 @@
FILE* stderr = &__sF[2];
static pthread_mutex_t __stdio_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+
+static uint64_t __get_file_tag(FILE* fp) {
+ // Don't use a tag for the standard streams.
+ // They don't really own their file descriptors, because the values are well-known, and you're
+ // allowed to do things like `close(STDIN_FILENO); open("foo", O_RDONLY)` when single-threaded.
+ if (fp == stdin || fp == stderr || fp == stdout) {
+ return 0;
+ }
+
+ return android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_FILE,
+ reinterpret_cast<uint64_t>(fp));
+}
+
struct glue __sglue = { nullptr, 3, __sF };
static struct glue* lastglue = &__sglue;
@@ -219,6 +236,7 @@
FILE* fp = __sfp();
if (fp != nullptr) {
fp->_file = fd;
+ android_fdsan_exchange_owner_tag(fd, 0, __get_file_tag(fp));
fp->_flags = flags;
fp->_cookie = fp;
fp->_read = __sread;
@@ -373,6 +391,7 @@
fp->_flags = flags;
fp->_file = fd;
+ android_fdsan_exchange_owner_tag(fd, 0, __get_file_tag(fp));
fp->_cookie = fp;
fp->_read = __sread;
fp->_write = __swrite;
@@ -518,7 +537,7 @@
int __sclose(void* cookie) {
FILE* fp = reinterpret_cast<FILE*>(cookie);
- return close(fp->_file);
+ return android_fdsan_close_with_tag(fp->_file, __get_file_tag(fp));
}
static off64_t __seek_unlocked(FILE* fp, off64_t offset, int whence) {