Merge changes from topic "fdtrack" am: bd2ac8d335 am: 31e9511fe1
Change-Id: Ie53f6dbad108faa4cb447f8d4184e1aa38761150
diff --git a/libc/Android.bp b/libc/Android.bp
index ef1bbe8..0f8ed3e 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -1085,7 +1085,7 @@
"bionic/clone.cpp",
"bionic/ctype.cpp",
"bionic/dirent.cpp",
- "bionic/dup2.cpp",
+ "bionic/dup.cpp",
"bionic/environ.cpp",
"bionic/error.cpp",
"bionic/eventfd_read.cpp",
@@ -1094,7 +1094,9 @@
"bionic/faccessat.cpp",
"bionic/fchmod.cpp",
"bionic/fchmodat.cpp",
+ "bionic/fcntl.cpp",
"bionic/fdsan.cpp",
+ "bionic/fdtrack.cpp",
"bionic/ffs.cpp",
"bionic/fgetxattr.cpp",
"bionic/flistxattr.cpp",
@@ -1163,6 +1165,7 @@
"bionic/realpath.cpp",
"bionic/reboot.cpp",
"bionic/recv.cpp",
+ "bionic/recvmsg.cpp",
"bionic/rename.cpp",
"bionic/rmdir.cpp",
"bionic/scandir.cpp",
@@ -1797,7 +1800,7 @@
name: "bionic_libc_platform_headers",
visibility: [
"//art:__subpackages__",
- "//bionic/libc:__subpackages__",
+ "//bionic:__subpackages__",
"//frameworks:__subpackages__",
"//external/perfetto:__subpackages__",
"//external/scudo:__subpackages__",
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index 517d5f9..1343e4e 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -123,12 +123,12 @@
ssize_t readv(int, const struct iovec*, int) all
ssize_t writev(int, const struct iovec*, int) all
int __fcntl64:fcntl64(int, int, void*) lp32
-int fcntl(int, int, void*) lp64
+int __fcntl:fcntl(int, int, void*) lp64
int flock(int, int) all
int __fchmod:fchmod(int, mode_t) all
-int dup(int) all
int pipe2(int*, int) all
-int dup3(int, int, int) all
+int __dup:dup(int) all
+int __dup3:dup3(int, int, int) all
int fsync(int) all
int fdatasync(int) all
int fchown:fchown32(int, uid_t, gid_t) arm,x86
@@ -254,9 +254,9 @@
int shutdown(int, int) arm,arm64,mips,mips64,x86_64
int setsockopt(int, int, int, const void*, socklen_t) arm,arm64,mips,mips64,x86_64
int getsockopt(int, int, int, void*, socklen_t*) arm,arm64,mips,mips64,x86_64
-ssize_t recvmsg(int, struct msghdr*, unsigned int) arm,arm64,mips,mips64,x86_64
+ssize_t __recvmsg:recvmsg(int, struct msghdr*, unsigned int) arm,arm64,mips,mips64,x86_64
ssize_t __sendmsg:sendmsg(int, const struct msghdr*, unsigned int) arm,arm64,mips,mips64,x86_64
-int recvmmsg(int, struct mmsghdr*, unsigned int, int, const struct timespec*) arm,arm64,mips,mips64,x86_64
+int __recvmmsg:recvmmsg(int, struct mmsghdr*, unsigned int, int, const struct timespec*) arm,arm64,mips,mips64,x86_64
int __sendmmsg:sendmmsg(int, struct mmsghdr*, unsigned int, int) arm,arm64,mips,mips64,x86_64
# sockets for x86. These are done as an "indexed" call to socketcall syscall.
@@ -273,9 +273,9 @@
int setsockopt:socketcall:14(int, int, int, const void*, socklen_t) x86
int getsockopt:socketcall:15(int, int, int, void*, socklen_t*) x86
int __sendmsg:socketcall:16(int, const struct msghdr*, unsigned int) x86
-int recvmsg:socketcall:17(int, struct msghdr*, unsigned int) x86
+int __recvmsg:socketcall:17(int, struct msghdr*, unsigned int) x86
int __accept4:socketcall:18(int, struct sockaddr*, socklen_t*, int) x86
-int recvmmsg:socketcall:19(int, struct mmsghdr*, unsigned int, int, const struct timespec*) x86
+int __recvmmsg:socketcall:19(int, struct mmsghdr*, unsigned int, int, const struct timespec*) x86
int __sendmmsg:socketcall:20(int, struct mmsghdr*, unsigned int, int) x86
# scheduler & real-time
diff --git a/libc/bionic/NetdClientDispatch.cpp b/libc/bionic/NetdClientDispatch.cpp
index 463ef36..e6f4a97 100644
--- a/libc/bionic/NetdClientDispatch.cpp
+++ b/libc/bionic/NetdClientDispatch.cpp
@@ -18,6 +18,8 @@
#include <sys/socket.h>
+#include "private/bionic_fdtrack.h"
+
#ifdef __i386__
#define __socketcall __attribute__((__cdecl__))
#else
@@ -53,7 +55,7 @@
};
int accept4(int fd, sockaddr* addr, socklen_t* addr_length, int flags) {
- return __netdClientDispatch.accept4(fd, addr, addr_length, flags);
+ return FDTRACK_CREATE(__netdClientDispatch.accept4(fd, addr, addr_length, flags));
}
int connect(int fd, const sockaddr* addr, socklen_t addr_length) {
@@ -74,5 +76,5 @@
}
int socket(int domain, int type, int protocol) {
- return __netdClientDispatch.socket(domain, type, protocol);
+ return FDTRACK_CREATE(__netdClientDispatch.socket(domain, type, protocol));
}
diff --git a/libc/bionic/dup2.cpp b/libc/bionic/dup.cpp
similarity index 83%
rename from libc/bionic/dup2.cpp
rename to libc/bionic/dup.cpp
index 98c5646..d9e89a5 100644
--- a/libc/bionic/dup2.cpp
+++ b/libc/bionic/dup.cpp
@@ -29,6 +29,15 @@
#include <fcntl.h>
#include <unistd.h>
+#include "private/bionic_fdtrack.h"
+
+extern "C" int __dup(int old_fd);
+extern "C" int __dup3(int old_fd, int new_fd, int flags);
+
+int dup(int old_fd) {
+ return FDTRACK_CREATE(__dup(old_fd));
+}
+
int dup2(int old_fd, int new_fd) {
// If old_fd is equal to new_fd and a valid file descriptor, dup2 returns
// old_fd without closing it. This is not true of dup3, so we have to
@@ -40,5 +49,9 @@
return old_fd;
}
- return dup3(old_fd, new_fd, 0);
+ return FDTRACK_CREATE(__dup3(old_fd, new_fd, 0));
+}
+
+int dup3(int old_fd, int new_fd, int flags) {
+ return FDTRACK_CREATE(__dup3(old_fd, new_fd, flags));
}
diff --git a/libc/bionic/fcntl.cpp b/libc/bionic/fcntl.cpp
new file mode 100644
index 0000000..c508131
--- /dev/null
+++ b/libc/bionic/fcntl.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdarg.h>
+#include <fcntl.h>
+
+#include "private/bionic_fdtrack.h"
+
+#if defined(__LP64__)
+
+extern "C" int __fcntl(int fd, int cmd, ...);
+
+int fcntl(int fd, int cmd, ...) {
+ va_list args;
+ va_start(args, cmd);
+
+ // This is a bit sketchy, especially because arg can be an int, but all of our
+ // supported 64-bit ABIs pass arg in a register.
+ void* arg = va_arg(args, void*);
+ va_end(args);
+
+ int rc = __fcntl(fd, cmd, arg);
+ if (cmd == F_DUPFD) {
+ return FDTRACK_CREATE_NAME("F_DUPFD", rc);
+ } else if (cmd == F_DUPFD_CLOEXEC) {
+ return FDTRACK_CREATE_NAME("F_DUPFD_CLOEXEC", rc);
+ }
+ return rc;
+}
+
+#else
+
+extern "C" int __fcntl64(int, int, ...);
+
+// For fcntl we use the fcntl64 system call to signal that we're using struct flock64.
+int fcntl(int fd, int cmd, ...) {
+ va_list ap;
+
+ va_start(ap, cmd);
+ void* arg = va_arg(ap, void*);
+ va_end(ap);
+
+ if (cmd == F_DUPFD) {
+ return FDTRACK_CREATE_NAME("F_DUPFD", __fcntl64(fd, cmd, arg));
+ } else if (cmd == F_DUPFD_CLOEXEC) {
+ return FDTRACK_CREATE_NAME("F_DUPFD_CLOEXEC", __fcntl64(fd, cmd, arg));
+ }
+ return __fcntl64(fd, cmd, arg);
+}
+
+#endif
diff --git a/libc/bionic/fdsan.cpp b/libc/bionic/fdsan.cpp
index d4ac71c..ebc680f 100644
--- a/libc/bionic/fdsan.cpp
+++ b/libc/bionic/fdsan.cpp
@@ -43,6 +43,7 @@
#include <platform/bionic/reserved_signals.h>
#include <sys/system_properties.h>
+#include "private/bionic_fdtrack.h"
#include "private/bionic_globals.h"
#include "private/bionic_inline_raise.h"
#include "pthread_internal.h"
@@ -245,6 +246,7 @@
}
int android_fdsan_close_with_tag(int fd, uint64_t expected_tag) {
+ FDTRACK_CLOSE(fd);
FdEntry* fde = GetFdEntry(fd);
if (!fde) {
return __close(fd);
diff --git a/libc/bionic/fdtrack.cpp b/libc/bionic/fdtrack.cpp
new file mode 100644
index 0000000..1123512
--- /dev/null
+++ b/libc/bionic/fdtrack.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdatomic.h>
+
+#include <platform/bionic/fdtrack.h>
+#include <platform/bionic/reserved_signals.h>
+
+#include "private/bionic_fdtrack.h"
+#include "private/bionic_tls.h"
+#include "private/bionic_globals.h"
+
+_Atomic(android_fdtrack_hook_t) __android_fdtrack_hook;
+
+bool android_fdtrack_get_enabled() {
+ return !__get_bionic_tls().fdtrack_disabled;
+}
+
+bool android_fdtrack_set_enabled(bool new_value) {
+ auto& tls = __get_bionic_tls();
+ bool prev = !tls.fdtrack_disabled;
+ tls.fdtrack_disabled = !new_value;
+ return prev;
+}
+
+bool android_fdtrack_compare_exchange_hook(android_fdtrack_hook_t* expected,
+ android_fdtrack_hook_t value) {
+ return atomic_compare_exchange_strong(&__android_fdtrack_hook, expected, value);
+}
+
+void __libc_init_fdtrack() {
+ // Register a no-op signal handler.
+ signal(BIONIC_SIGNAL_FDTRACK, [](int) {});
+}
diff --git a/libc/bionic/legacy_32_bit_support.cpp b/libc/bionic/legacy_32_bit_support.cpp
index 2de1bc7..f08e582 100644
--- a/libc/bionic/legacy_32_bit_support.cpp
+++ b/libc/bionic/legacy_32_bit_support.cpp
@@ -37,27 +37,17 @@
#include <sys/vfs.h>
#include <unistd.h>
+#include "private/bionic_fdtrack.h"
+
#if defined(__LP64__)
#error This code is only needed on 32-bit systems!
#endif
// System calls we need.
-extern "C" int __fcntl64(int, int, void*);
extern "C" int __llseek(int, unsigned long, unsigned long, off64_t*, int);
extern "C" int __preadv64(int, const struct iovec*, int, long, long);
extern "C" int __pwritev64(int, const struct iovec*, int, long, long);
-// For fcntl we use the fcntl64 system call to signal that we're using struct flock64.
-int fcntl(int fd, int cmd, ...) {
- va_list ap;
-
- va_start(ap, cmd);
- void* arg = va_arg(ap, void*);
- va_end(ap);
-
- return __fcntl64(fd, cmd, arg);
-}
-
// For lseek64 we need to use the llseek system call which splits the off64_t in two and
// returns the off64_t result via a pointer because 32-bit kernels can't return 64-bit results.
off64_t lseek64(int fd, off64_t off, int whence) {
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index e4106e9..12628f7 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -104,6 +104,7 @@
__system_properties_init(); // Requires 'environ'.
__libc_init_fdsan(); // Requires system properties (for debug.fdsan).
+ __libc_init_fdtrack();
SetDefaultHeapTaggingLevel();
}
diff --git a/libc/bionic/open.cpp b/libc/bionic/open.cpp
index 222e5d3..bd8685a 100644
--- a/libc/bionic/open.cpp
+++ b/libc/bionic/open.cpp
@@ -31,6 +31,7 @@
#include <stdlib.h>
#include <unistd.h>
+#include "private/bionic_fdtrack.h"
#include "private/bionic_fortify.h"
extern "C" int __openat(int, const char*, int, int);
@@ -62,13 +63,13 @@
va_end(args);
}
- return __openat(AT_FDCWD, pathname, force_O_LARGEFILE(flags), mode);
+ return FDTRACK_CREATE(__openat(AT_FDCWD, pathname, force_O_LARGEFILE(flags), mode));
}
__strong_alias(open64, open);
int __open_2(const char* pathname, int flags) {
if (needs_mode(flags)) __fortify_fatal("open: called with O_CREAT/O_TMPFILE but no mode");
- return __openat(AT_FDCWD, pathname, force_O_LARGEFILE(flags), 0);
+ return FDTRACK_CREATE_NAME("open", __openat(AT_FDCWD, pathname, force_O_LARGEFILE(flags), 0));
}
int openat(int fd, const char *pathname, int flags, ...) {
@@ -81,11 +82,11 @@
va_end(args);
}
- return __openat(fd, pathname, force_O_LARGEFILE(flags), mode);
+ return FDTRACK_CREATE_NAME("openat", __openat(fd, pathname, force_O_LARGEFILE(flags), mode));
}
__strong_alias(openat64, openat);
int __openat_2(int fd, const char* pathname, int flags) {
if (needs_mode(flags)) __fortify_fatal("open: called with O_CREAT/O_TMPFILE but no mode");
- return __openat(fd, pathname, force_O_LARGEFILE(flags), 0);
+ return FDTRACK_CREATE_NAME("openat", __openat(fd, pathname, force_O_LARGEFILE(flags), 0));
}
diff --git a/libc/bionic/recvmsg.cpp b/libc/bionic/recvmsg.cpp
new file mode 100644
index 0000000..003f43d
--- /dev/null
+++ b/libc/bionic/recvmsg.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <sys/socket.h>
+
+#include <async_safe/log.h>
+
+#include "private/bionic_fdtrack.h"
+
+extern "C" ssize_t __recvmsg(int __fd, struct msghdr* __msg, int __flags);
+extern "C" int __recvmmsg(int __fd, struct mmsghdr* __msgs, unsigned int __msg_count, int __flags,
+ const struct timespec* __timeout);
+
+static inline __attribute__((artificial)) __attribute__((always_inline)) void track_fds(
+ struct msghdr* msg, const char* function_name) {
+ if (!__android_fdtrack_hook) {
+ return;
+ }
+
+ for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
+ if (cmsg->cmsg_type != SCM_RIGHTS) {
+ continue;
+ }
+
+ if (cmsg->cmsg_len <= sizeof(struct cmsghdr)) {
+ continue;
+ }
+
+ size_t data_length = cmsg->cmsg_len - sizeof(struct cmsghdr);
+ if (data_length % sizeof(int) != 0) {
+ async_safe_fatal("invalid cmsg length: %zu", data_length);
+ }
+
+ for (size_t offset = 0; offset < data_length; offset += sizeof(int)) {
+ int fd;
+ memcpy(&fd, CMSG_DATA(cmsg) + offset, sizeof(int));
+ FDTRACK_CREATE_NAME(function_name, fd);
+ }
+ }
+}
+
+ssize_t recvmsg(int __fd, struct msghdr* __msg, int __flags) {
+ ssize_t rc = __recvmsg(__fd, __msg, __flags);
+ if (rc == -1) {
+ return -1;
+ }
+ track_fds(__msg, "recvmsg");
+ return rc;
+}
+
+int recvmmsg(int __fd, struct mmsghdr* __msgs, unsigned int __msg_count, int __flags,
+ const struct timespec* __timeout) {
+ int rc = __recvmmsg(__fd, __msgs, __msg_count, __flags, __timeout);
+ if (rc == -1) {
+ return -1;
+ }
+ for (int i = 0; i < rc; ++i) {
+ track_fds(&__msgs[i].msg_hdr, "recvmmsg");
+ }
+ return rc;
+}
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index 2710fb2..2ca4b21 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1752,6 +1752,9 @@
__system_property_set_filename;
__system_property_update;
android_fdsan_get_fd_table;
+ android_fdtrack_compare_exchange_hook; # llndk
+ android_fdtrack_get_enabled; # llndk
+ android_fdtrack_set_enabled; # llndk
android_net_res_stats_get_info_for_net;
android_net_res_stats_aggregate;
android_net_res_stats_get_usable_servers;
diff --git a/libc/platform/bionic/fdtrack.h b/libc/platform/bionic/fdtrack.h
new file mode 100644
index 0000000..6eb379b
--- /dev/null
+++ b/libc/platform/bionic/fdtrack.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+__BEGIN_DECLS
+
+// Types of an android_fdtrack_event.
+enum android_fdtrack_event_type {
+ // File descriptor creation: create is the active member of android_fdtrack_event::data.
+ ANDROID_FDTRACK_EVENT_TYPE_CREATE,
+
+ // File descriptor closed.
+ ANDROID_FDTRACK_EVENT_TYPE_CLOSE,
+};
+
+struct android_fdtrack_event {
+ // File descriptor for which this event occurred.
+ int fd;
+
+ // Type of event: this is one of the enumerators of android_fdtrack_event_type.
+ uint8_t type;
+
+ // Data for the event.
+ union {
+ struct {
+ const char* function_name;
+ } create;
+ } data;
+};
+
+// Callback invoked upon file descriptor creation/closure.
+typedef void (*android_fdtrack_hook_t)(struct android_fdtrack_event*);
+
+// Register a hook which is called to track fd lifecycle events.
+bool android_fdtrack_compare_exchange_hook(android_fdtrack_hook_t* expected, android_fdtrack_hook_t value) __INTRODUCED_IN(30);
+
+// Enable/disable fdtrack *on the current thread*.
+// This is primarily useful when performing operations which you don't want to track
+// (e.g. when emitting already-recorded information).
+bool android_fdtrack_get_enabled() __INTRODUCED_IN(30);
+bool android_fdtrack_set_enabled(bool new_value) __INTRODUCED_IN(30);
+
+__END_DECLS
diff --git a/libc/platform/bionic/reserved_signals.h b/libc/platform/bionic/reserved_signals.h
index 7634b27..4ac6455 100644
--- a/libc/platform/bionic/reserved_signals.h
+++ b/libc/platform/bionic/reserved_signals.h
@@ -42,14 +42,16 @@
// 36 (__SIGRTMIN + 4) platform profilers (heapprofd, traced_perf)
// 37 (__SIGRTMIN + 5) coverage (libprofile-extras)
// 38 (__SIGRTMIN + 6) heapprofd ART managed heap dumps
+// 39 (__SIGRTMIN + 7) fdtrack
//
// If you change this, also change __ndk_legacy___libc_current_sigrtmin
// in <android/legacy_signal_inlines.h> to match.
#define BIONIC_SIGNAL_DEBUGGER __SIGRTMIN + 3
#define BIONIC_SIGNAL_PROFILER __SIGRTMIN + 4
+#define BIONIC_SIGNAL_FDTRACK __SIGRTMIN + 7
-#define __SIGRT_RESERVED 7
+#define __SIGRT_RESERVED 8
static inline __always_inline sigset64_t filter_reserved_signals(sigset64_t sigset, int how) {
int (*block)(sigset64_t*, int);
int (*unblock)(sigset64_t*, int);
@@ -77,5 +79,6 @@
unblock(&sigset, __SIGRTMIN + 4);
unblock(&sigset, __SIGRTMIN + 5);
unblock(&sigset, __SIGRTMIN + 6);
+ unblock(&sigset, __SIGRTMIN + 7);
return sigset;
}
diff --git a/libc/private/bionic_fdtrack.h b/libc/private/bionic_fdtrack.h
new file mode 100644
index 0000000..174ba1d
--- /dev/null
+++ b/libc/private/bionic_fdtrack.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+#include <stdatomic.h>
+
+#include "platform/bionic/fdtrack.h"
+
+#include "bionic/pthread_internal.h"
+#include "private/bionic_tls.h"
+#include "private/ErrnoRestorer.h"
+
+extern "C" _Atomic(android_fdtrack_hook_t) __android_fdtrack_hook;
+
+// Macro to record file descriptor creation.
+// e.g.:
+// int socket(int domain, int type, int protocol) {
+// return FDTRACK_CREATE_NAME("socket", __socket(domain, type, protocol));
+// }
+#define FDTRACK_CREATE_NAME(name, fd_value) \
+ ({ \
+ int __fd = (fd_value); \
+ if (__fd != -1 && __predict_false(__android_fdtrack_hook)) { \
+ bionic_tls& tls = __get_bionic_tls(); \
+ /* fdtrack_disabled is only true during reentrant calls. */ \
+ if (!__predict_false(tls.fdtrack_disabled)) { \
+ ErrnoRestorer r; \
+ tls.fdtrack_disabled = true; \
+ android_fdtrack_event event; \
+ event.fd = __fd; \
+ event.type = ANDROID_FDTRACK_EVENT_TYPE_CREATE; \
+ event.data.create.function_name = name; \
+ __android_fdtrack_hook(&event); \
+ tls.fdtrack_disabled = false; \
+ } \
+ } \
+ __fd; \
+ })
+
+// Macro to record file descriptor creation, with the current function's name.
+// e.g.:
+// int socket(int domain, int type, int protocol) {
+// return FDTRACK_CREATE_NAME(__socket(domain, type, protocol));
+// }
+#define FDTRACK_CREATE(fd_value) FDTRACK_CREATE_NAME(__func__, (fd_value))
+
+// Macro to record file descriptor closure.
+// Note that this does not actually close the file descriptor.
+#define FDTRACK_CLOSE(fd_value) \
+ ({ \
+ int __fd = (fd_value); \
+ if (__fd != -1 && __predict_false(__android_fdtrack_hook)) { \
+ bionic_tls& tls = __get_bionic_tls(); \
+ if (!__predict_false(tls.fdtrack_disabled)) { \
+ int saved_errno = errno; \
+ tls.fdtrack_disabled = true; \
+ android_fdtrack_event event; \
+ event.fd = __fd; \
+ event.type = ANDROID_FDTRACK_EVENT_TYPE_CLOSE; \
+ __android_fdtrack_hook(&event); \
+ tls.fdtrack_disabled = false; \
+ errno = saved_errno; \
+ } \
+ } \
+ __fd; \
+ })
diff --git a/libc/private/bionic_globals.h b/libc/private/bionic_globals.h
index 8997ceb..4cc9bbe 100644
--- a/libc/private/bionic_globals.h
+++ b/libc/private/bionic_globals.h
@@ -100,6 +100,7 @@
__LIBC_HIDDEN__ libc_shared_globals* __libc_shared_globals();
__LIBC_HIDDEN__ void __libc_init_fdsan();
+__LIBC_HIDDEN__ void __libc_init_fdtrack();
__LIBC_HIDDEN__ void __libc_init_profiling_handlers();
__LIBC_HIDDEN__ void __libc_init_malloc(libc_globals* globals);
diff --git a/libc/private/bionic_tls.h b/libc/private/bionic_tls.h
index bb5c67b..80d645a 100644
--- a/libc/private/bionic_tls.h
+++ b/libc/private/bionic_tls.h
@@ -128,6 +128,9 @@
group_state_t group;
passwd_state_t passwd;
+ char fdtrack_disabled;
+ char padding[3];
+
// Initialize the main thread's final object using its bootstrap object.
void copy_from_bootstrap(const bionic_tls* boot __attribute__((unused))) {
// Nothing in bionic_tls needs to be preserved in the transition to the
diff --git a/libfdtrack/.clang-format b/libfdtrack/.clang-format
new file mode 120000
index 0000000..fd0645f
--- /dev/null
+++ b/libfdtrack/.clang-format
@@ -0,0 +1 @@
+../.clang-format-2
\ No newline at end of file
diff --git a/libfdtrack/Android.bp b/libfdtrack/Android.bp
new file mode 100644
index 0000000..fd13512
--- /dev/null
+++ b/libfdtrack/Android.bp
@@ -0,0 +1,18 @@
+cc_library_shared {
+ name: "libfdtrack",
+ srcs: ["fdtrack.cpp"],
+ stl: "libc++_static",
+
+ header_libs: ["bionic_libc_platform_headers"],
+ static_libs: [
+ "libasync_safe",
+ "libbase",
+ "libunwindstack",
+ "liblzma",
+ "liblog",
+ ],
+ version_script: "libfdtrack.map.txt",
+
+ allow_undefined_symbols: true,
+ recovery_available: true,
+}
diff --git a/libfdtrack/fdtrack.cpp b/libfdtrack/fdtrack.cpp
new file mode 100644
index 0000000..831a50d
--- /dev/null
+++ b/libfdtrack/fdtrack.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <inttypes.h>
+
+#include <array>
+#include <mutex>
+#include <vector>
+
+#include <android/fdsan.h>
+#include <bionic/fdtrack.h>
+
+#include <android-base/no_destructor.h>
+#include <android-base/thread_annotations.h>
+#include <async_safe/log.h>
+#include <bionic/reserved_signals.h>
+#include <unwindstack/LocalUnwinder.h>
+
+struct FdEntry {
+ std::mutex mutex;
+ std::vector<unwindstack::LocalFrameData> backtrace GUARDED_BY(mutex);
+};
+
+extern "C" void fdtrack_dump();
+static void fd_hook(android_fdtrack_event* event);
+
+// Backtraces for the first 4k file descriptors ought to be enough to diagnose an fd leak.
+static constexpr size_t kFdTableSize = 4096;
+static constexpr size_t kStackDepth = 10;
+
+static bool installed = false;
+static std::array<FdEntry, kFdTableSize> stack_traces;
+static unwindstack::LocalUnwinder& Unwinder() {
+ static android::base::NoDestructor<unwindstack::LocalUnwinder> unwinder;
+ return *unwinder.get();
+}
+
+__attribute__((constructor)) static void ctor() {
+ signal(BIONIC_SIGNAL_FDTRACK, [](int) { fdtrack_dump(); });
+ if (Unwinder().Init()) {
+ android_fdtrack_hook_t expected = nullptr;
+ installed = android_fdtrack_compare_exchange_hook(&expected, &fd_hook);
+ }
+}
+
+__attribute__((destructor)) static void dtor() {
+ if (installed) {
+ android_fdtrack_hook_t expected = &fd_hook;
+ android_fdtrack_compare_exchange_hook(&expected, nullptr);
+ }
+}
+
+FdEntry* GetFdEntry(int fd) {
+ if (fd >= 0 && fd < static_cast<int>(kFdTableSize)) {
+ return &stack_traces[fd];
+ }
+ return nullptr;
+}
+
+static void fd_hook(android_fdtrack_event* event) {
+ if (event->type == ANDROID_FDTRACK_EVENT_TYPE_CREATE) {
+ if (FdEntry* entry = GetFdEntry(event->fd); entry) {
+ std::lock_guard<std::mutex> lock(entry->mutex);
+ entry->backtrace.clear();
+ Unwinder().Unwind(&entry->backtrace, kStackDepth);
+ }
+ } else if (event->type == ANDROID_FDTRACK_EVENT_TYPE_CLOSE) {
+ if (FdEntry* entry = GetFdEntry(event->fd); entry) {
+ std::lock_guard<std::mutex> lock(entry->mutex);
+ entry->backtrace.clear();
+ }
+ }
+}
+
+void fdtrack_dump() {
+ if (!installed) {
+ async_safe_format_log(ANDROID_LOG_INFO, "fdtrack", "fdtrack not installed");
+ } else {
+ async_safe_format_log(ANDROID_LOG_INFO, "fdtrack", "fdtrack dumping...");
+ }
+
+ bool prev = android_fdtrack_set_enabled(false);
+ for (int fd = 0; fd < static_cast<int>(stack_traces.size()); ++fd) {
+ FdEntry* entry = GetFdEntry(fd);
+ if (!entry) {
+ continue;
+ }
+
+ if (!entry->mutex.try_lock()) {
+ async_safe_format_log(ANDROID_LOG_WARN, "fdtrack", "fd %d locked, skipping", fd);
+ continue;
+ }
+
+ if (entry->backtrace.empty()) {
+ continue;
+ }
+
+ uint64_t fdsan_owner = android_fdsan_get_owner_tag(fd);
+
+ if (fdsan_owner != 0) {
+ async_safe_format_log(ANDROID_LOG_INFO, "fdtrack", "fd %d: (owner = %#" PRIx64 ")", fd,
+ fdsan_owner);
+ } else {
+ async_safe_format_log(ANDROID_LOG_INFO, "fdtrack", "fd %d: (unowned)", fd);
+ }
+
+ const size_t frame_skip = 2;
+ for (size_t i = frame_skip; i < entry->backtrace.size(); ++i) {
+ auto& frame = entry->backtrace[i];
+ async_safe_format_log(ANDROID_LOG_INFO, "fdtrack", " %zu: %s+%" PRIu64, i - frame_skip,
+ frame.function_name.c_str(), frame.function_offset);
+ }
+
+ entry->mutex.unlock();
+ }
+ android_fdtrack_set_enabled(prev);
+}
diff --git a/libfdtrack/libfdtrack.map.txt b/libfdtrack/libfdtrack.map.txt
new file mode 100644
index 0000000..7a54c35
--- /dev/null
+++ b/libfdtrack/libfdtrack.map.txt
@@ -0,0 +1,6 @@
+LIBFDTRACK {
+ global:
+ fdtrack_dump;
+ local:
+ *;
+};
diff --git a/tests/Android.bp b/tests/Android.bp
index 7219fc5..1ef7b0e 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -91,6 +91,7 @@
"eventfd_test.cpp",
"fcntl_test.cpp",
"fdsan_test.cpp",
+ "fdtrack_test.cpp",
"fenv_test.cpp",
"_FILE_OFFSET_BITS_test.cpp",
"float_test.cpp",
diff --git a/tests/fdtrack_test.cpp b/tests/fdtrack_test.cpp
new file mode 100644
index 0000000..fca92ce
--- /dev/null
+++ b/tests/fdtrack_test.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#if defined(__BIONIC__)
+#include "platform/bionic/fdtrack.h"
+#endif
+
+#include <vector>
+
+#include <android-base/unique_fd.h>
+
+#if defined(__BIONIC__)
+std::vector<android_fdtrack_event> FdtrackRun(void (*func)()) {
+ // Each bionic test is run in separate process, so we can safely use a static here.
+ static std::vector<android_fdtrack_event> events;
+ events.clear();
+
+ android_fdtrack_hook_t previous = nullptr;
+ android_fdtrack_hook_t hook = [](android_fdtrack_event* event) {
+ events.push_back(*event);
+ };
+
+ if (!android_fdtrack_compare_exchange_hook(&previous, hook)) {
+ errx(1, "failed to exchange hook: previous hook was %p", previous);
+ }
+
+ if (previous) {
+ errx(1, "hook was already registered?");
+ abort();
+ }
+
+ func();
+
+ if (!android_fdtrack_compare_exchange_hook(&hook, nullptr)) {
+ errx(1, "failed to reset hook");
+ }
+
+ return std::move(events);
+}
+#endif
+
+TEST(fdtrack, open) {
+#if defined(__BIONIC__)
+ static int fd = -1;
+ auto events = FdtrackRun([]() { fd = open("/dev/null", O_WRONLY | O_CLOEXEC); });
+ ASSERT_NE(-1, fd);
+ ASSERT_EQ(1U, events.size());
+ ASSERT_EQ(fd, events[0].fd);
+ ASSERT_EQ(ANDROID_FDTRACK_EVENT_TYPE_CREATE, events[0].type);
+ ASSERT_STREQ("open", events[0].data.create.function_name);
+#endif
+}
+
+TEST(fdtrack, close) {
+#if defined(__BIONIC__)
+ static int fd = open("/dev/null", O_WRONLY | O_CLOEXEC);
+ ASSERT_NE(-1, fd);
+
+ auto events = FdtrackRun([]() { close(fd); });
+ ASSERT_EQ(1U, events.size());
+ ASSERT_EQ(fd, events[0].fd);
+ ASSERT_EQ(ANDROID_FDTRACK_EVENT_TYPE_CLOSE, events[0].type);
+#endif
+}
+
+TEST(fdtrack, enable_disable) {
+#if defined(__BIONIC__)
+ static int fd1 = -1;
+ static int fd2 = -1;
+ static int fd3 = -1;
+
+ auto events = FdtrackRun([]() {
+ if (!android_fdtrack_get_enabled()) {
+ errx(1, "fdtrack is disabled");
+ }
+ fd1 = open("/dev/null", O_WRONLY | O_CLOEXEC);
+ android_fdtrack_set_enabled(false);
+ fd2 = open("/dev/null", O_WRONLY | O_CLOEXEC);
+ android_fdtrack_set_enabled(true);
+ fd3 = open("/dev/null", O_WRONLY | O_CLOEXEC);
+ });
+
+ if (fd1 == -1 || fd2 == -1 || fd3 == -1) {
+ errx(1, "failed to open /dev/null");
+ }
+
+ ASSERT_EQ(2U, events.size());
+
+ ASSERT_EQ(fd1, events[0].fd);
+ ASSERT_EQ(ANDROID_FDTRACK_EVENT_TYPE_CREATE, events[0].type);
+ ASSERT_STREQ("open", events[0].data.create.function_name);
+
+ ASSERT_EQ(fd3, events[1].fd);
+ ASSERT_EQ(ANDROID_FDTRACK_EVENT_TYPE_CREATE, events[1].type);
+ ASSERT_STREQ("open", events[1].data.create.function_name);
+#endif
+}