Merge "Revert "Reland: Soft-enable MAC address restrictions with allowlist.""
diff --git a/libc/bionic/fdsan.cpp b/libc/bionic/fdsan.cpp
index 043510c..48e8674 100644
--- a/libc/bionic/fdsan.cpp
+++ b/libc/bionic/fdsan.cpp
@@ -137,14 +137,6 @@
     return;
   }
 
-  // Lots of code will (sensibly) fork, call close on all of their fds,
-  // and then exec. Compare our cached pid value against the real one to detect
-  // this scenario and permit it.
-  pid_t cached_pid = __get_cached_pid();
-  if (cached_pid == 0 || cached_pid != syscall(__NR_getpid)) {
-    return;
-  }
-
   struct {
     size_t size;
     char buf[512];
diff --git a/libc/bionic/fdtrack.cpp b/libc/bionic/fdtrack.cpp
index 1123512..89a208f 100644
--- a/libc/bionic/fdtrack.cpp
+++ b/libc/bionic/fdtrack.cpp
@@ -37,8 +37,14 @@
 
 _Atomic(android_fdtrack_hook_t) __android_fdtrack_hook;
 
+bool __android_fdtrack_globally_disabled = false;
+
+void android_fdtrack_set_globally_enabled(bool new_value) {
+  __android_fdtrack_globally_disabled = !new_value;
+}
+
 bool android_fdtrack_get_enabled() {
-  return !__get_bionic_tls().fdtrack_disabled;
+  return !__get_bionic_tls().fdtrack_disabled && !__android_fdtrack_globally_disabled;
 }
 
 bool android_fdtrack_set_enabled(bool new_value) {
diff --git a/libc/bionic/fork.cpp b/libc/bionic/fork.cpp
index 8c5cf2b..d432c6d 100644
--- a/libc/bionic/fork.cpp
+++ b/libc/bionic/fork.cpp
@@ -31,6 +31,7 @@
 #include <android/fdsan.h>
 
 #include "private/bionic_defs.h"
+#include "private/bionic_fdtrack.h"
 #include "pthread_internal.h"
 
 __BIONIC_WEAK_FOR_NATIVE_BRIDGE_INLINE
@@ -55,9 +56,10 @@
   int result = __clone_for_fork();
 
   if (result == 0) {
-    // Disable fdsan post-fork, so we don't falsely trigger on processes that
+    // Disable fdsan and fdtrack post-fork, so we don't falsely trigger on processes that
     // fork, close all of their fds, and then exec.
     android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_DISABLED);
+    android_fdtrack_set_globally_enabled(false);
 
     // Reset the stack_and_tls VMA name so it doesn't end with a tid from the
     // parent process.
diff --git a/libc/dns/resolv/res_data.c b/libc/dns/resolv/res_data.c
index 9bc02e7..4f8df69 100644
--- a/libc/dns/resolv/res_data.c
+++ b/libc/dns/resolv/res_data.c
@@ -40,6 +40,7 @@
 #include <ctype.h>
 #include <netdb.h>
 #include "resolv_private.h"
+#include <pthread.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -82,11 +83,9 @@
 
 int  res_ourserver_p(const res_state, const struct sockaddr *);
 
-#define res_need_init()   ((_nres.options & RES_INIT) == 0U)
+static pthread_once_t once_control = PTHREAD_ONCE_INIT;
 
-int
-res_init(void) {
-	int rv;
+static void init_once(void) {
 	extern int __res_vinit(res_state, int);
 #ifdef COMPAT__RES
 	/*
@@ -140,11 +139,21 @@
 	if (!_nres.id)
 		_nres.id = res_randomid();
 
-	rv = __res_vinit(&_nres, 1);
+	__res_vinit(&_nres, 1);
 #ifdef COMPAT__RES
 	__res_put_old_state(&_nres);
 #endif
-	return rv;
+}
+
+int
+res_init(void) {
+    pthread_once(&once_control, init_once);
+    return 0;
+}
+
+static res_state get_static_res_state() {
+    pthread_once(&once_control, init_once);
+    return &_nres;
 }
 
 void
@@ -159,10 +168,7 @@
 
 void
 fp_nquery(const u_char *msg, int len, FILE *file) {
-	if (res_need_init() && res_init() == -1)
-		return;
-
-	res_pquery(&_nres, msg, len, file);
+	res_pquery(get_static_res_state(), msg, len, file);
 }
 
 int
@@ -175,11 +181,7 @@
 	    u_char *buf,		/* buffer to put query */
 	    int buflen)			/* size of buffer */
 {
-	if (res_need_init() && res_init() == -1) {
-		RES_SET_H_ERRNO(&_nres, NETDB_INTERNAL);
-		return (-1);
-	}
-	return (res_nmkquery(&_nres, op, dname, class, type,
+	return (res_nmkquery(get_static_res_state(), op, dname, class, type,
 			     data, datalen,
 			     newrr_in, buf, buflen));
 }
@@ -187,12 +189,7 @@
 #ifdef _LIBRESOLV
 int
 res_mkupdate(ns_updrec *rrecp_in, u_char *buf, int buflen) {
-	if (res_need_init() && res_init() == -1) {
-		RES_SET_H_ERRNO(&_nres, NETDB_INTERNAL);
-		return (-1);
-	}
-
-	return (res_nmkupdate(&_nres, rrecp_in, buf, buflen));
+	return (res_nmkupdate(get_static_res_state(), rrecp_in, buf, buflen));
 }
 #endif
 
@@ -202,11 +199,7 @@
 	  u_char *answer,	/* buffer to put answer */
 	  int anslen)		/* size of answer buffer */
 {
-	if (res_need_init() && res_init() == -1) {
-		RES_SET_H_ERRNO(&_nres, NETDB_INTERNAL);
-		return (-1);
-	}
-	return (res_nquery(&_nres, name, class, type, answer, anslen));
+	return (res_nquery(get_static_res_state(), name, class, type, answer, anslen));
 }
 
 void
@@ -226,12 +219,7 @@
 
 int
 res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) {
-	if (res_need_init() && res_init() == -1) {
-		/* errno should have been set by res_init() in this case. */
-		return (-1);
-	}
-
-	return (res_nsend(&_nres, buf, buflen, ans, anssiz));
+	return (res_nsend(get_static_res_state(), buf, buflen, ans, anssiz));
 }
 
 #ifdef _LIBRESOLV
@@ -239,12 +227,7 @@
 res_sendsigned(const u_char *buf, int buflen, ns_tsig_key *key,
 	       u_char *ans, int anssiz)
 {
-	if (res_need_init() && res_init() == -1) {
-		/* errno should have been set by res_init() in this case. */
-		return (-1);
-	}
-
-	return (res_nsendsigned(&_nres, buf, buflen, key, ans, anssiz));
+	return (res_nsendsigned(get_static_res_state(), buf, buflen, key, ans, anssiz));
 }
 #endif
 
@@ -256,12 +239,7 @@
 #ifdef _LIBRESOLV
 int
 res_update(ns_updrec *rrecp_in) {
-	if (res_need_init() && res_init() == -1) {
-		RES_SET_H_ERRNO(&_nres, NETDB_INTERNAL);
-		return (-1);
-	}
-
-	return (res_nupdate(&_nres, rrecp_in, NULL));
+	return (res_nupdate(get_static_res_state(), rrecp_in, NULL));
 }
 #endif
 
@@ -271,12 +249,7 @@
 	   u_char *answer,	/* buffer to put answer */
 	   int anslen)		/* size of answer */
 {
-	if (res_need_init() && res_init() == -1) {
-		RES_SET_H_ERRNO(&_nres, NETDB_INTERNAL);
-		return (-1);
-	}
-
-	return (res_nsearch(&_nres, name, class, type, answer, anslen));
+	return (res_nsearch(get_static_res_state(), name, class, type, answer, anslen));
 }
 
 int
@@ -286,12 +259,7 @@
 		u_char *answer,		/* buffer to put answer */
 		int anslen)		/* size of answer */
 {
-	if (res_need_init() && res_init() == -1) {
-		RES_SET_H_ERRNO(&_nres, NETDB_INTERNAL);
-		return (-1);
-	}
-
-	return (res_nquerydomain(&_nres, name, domain,
+	return (res_nquerydomain(get_static_res_state(), name, domain,
 				 class, type,
 				 answer, anslen));
 }
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index 51a1076..c31e306 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1772,6 +1772,7 @@
     android_fdtrack_compare_exchange_hook; # llndk
     android_fdtrack_get_enabled; # llndk
     android_fdtrack_set_enabled; # llndk
+    android_fdtrack_set_globally_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
index 6eb379b..fe6ca84 100644
--- a/libc/platform/bionic/fdtrack.h
+++ b/libc/platform/bionic/fdtrack.h
@@ -70,4 +70,8 @@
 bool android_fdtrack_get_enabled() __INTRODUCED_IN(30);
 bool android_fdtrack_set_enabled(bool new_value) __INTRODUCED_IN(30);
 
+// Globally enable/disable fdtrack.
+// This is primaryily useful to reenable fdtrack after it's been automatically disabled post-fork.
+void android_fdtrack_set_globally_enabled(bool new_value) __INTRODUCED_IN(31);
+
 __END_DECLS
diff --git a/libc/private/bionic_fdtrack.h b/libc/private/bionic_fdtrack.h
index 259897c..c05b32b 100644
--- a/libc/private/bionic_fdtrack.h
+++ b/libc/private/bionic_fdtrack.h
@@ -28,41 +28,43 @@
 
 #pragma once
 
-#include <sys/cdefs.h>
 #include <stdatomic.h>
+#include <sys/cdefs.h>
 
 #include "platform/bionic/fdtrack.h"
 
 #include "bionic/pthread_internal.h"
-#include "private/bionic_tls.h"
 #include "private/ErrnoRestorer.h"
+#include "private/bionic_tls.h"
 
 extern "C" _Atomic(android_fdtrack_hook_t) __android_fdtrack_hook;
+extern "C" bool __android_fdtrack_globally_disabled;
 
 // 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) &&  \
-        !__predict_false(__get_thread()->is_vforked())) {         \
-      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;                   \
-        atomic_load(&__android_fdtrack_hook)(&event);             \
-        tls.fdtrack_disabled = false;                             \
-      }                                                           \
-    }                                                             \
-    __fd;                                                         \
+#define FDTRACK_CREATE_NAME(name, fd_value)                        \
+  ({                                                               \
+    int __fd = (fd_value);                                         \
+    if (__fd != -1 && __predict_false(__android_fdtrack_hook) &&   \
+        !__predict_false(__get_thread()->is_vforked())) {          \
+      bionic_tls& tls = __get_bionic_tls();                        \
+      /* fdtrack_disabled is only true during reentrant calls. */  \
+      if (!__predict_false(tls.fdtrack_disabled) &&                \
+          !__predict_false(__android_fdtrack_globally_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;                    \
+        atomic_load (&__android_fdtrack_hook)(&event);             \
+        tls.fdtrack_disabled = false;                              \
+      }                                                            \
+    }                                                              \
+    __fd;                                                          \
   })
 
 // Macro to record file descriptor creation, with the current function's name.
@@ -74,22 +76,23 @@
 
 // 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) && \
-        !__predict_false(__get_thread()->is_vforked())) {        \
-      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;           \
-        atomic_load(&__android_fdtrack_hook)(&event);            \
-        tls.fdtrack_disabled = false;                            \
-        errno = saved_errno;                                     \
-      }                                                          \
-    }                                                            \
-    __fd;                                                        \
+#define FDTRACK_CLOSE(fd_value)                                    \
+  ({                                                               \
+    int __fd = (fd_value);                                         \
+    if (__fd != -1 && __predict_false(__android_fdtrack_hook) &&   \
+        !__predict_false(__get_thread()->is_vforked())) {          \
+      bionic_tls& tls = __get_bionic_tls();                        \
+      if (!__predict_false(tls.fdtrack_disabled) &&                \
+          !__predict_false(__android_fdtrack_globally_disabled)) { \
+        int saved_errno = errno;                                   \
+        tls.fdtrack_disabled = true;                               \
+        android_fdtrack_event event;                               \
+        event.fd = __fd;                                           \
+        event.type = ANDROID_FDTRACK_EVENT_TYPE_CLOSE;             \
+        atomic_load (&__android_fdtrack_hook)(&event);             \
+        tls.fdtrack_disabled = false;                              \
+        errno = saved_errno;                                       \
+      }                                                            \
+    }                                                              \
+    __fd;                                                          \
   })
diff --git a/libfdtrack/fdtrack.cpp b/libfdtrack/fdtrack.cpp
index fd56274..2e9cfbc 100644
--- a/libfdtrack/fdtrack.cpp
+++ b/libfdtrack/fdtrack.cpp
@@ -93,6 +93,8 @@
     android_fdtrack_hook_t expected = nullptr;
     installed = android_fdtrack_compare_exchange_hook(&expected, &fd_hook);
   }
+
+  android_fdtrack_set_globally_enabled(true);
 }
 
 __attribute__((destructor)) static void dtor() {
diff --git a/tests/fdtrack_test.cpp b/tests/fdtrack_test.cpp
index 13f1b2e..9fcb402 100644
--- a/tests/fdtrack_test.cpp
+++ b/tests/fdtrack_test.cpp
@@ -57,8 +57,13 @@
   }
 }
 
-std::vector<android_fdtrack_event> FdtrackRun(void (*func)()) {
+std::vector<android_fdtrack_event> FdtrackRun(void (*func)(), bool reenable = true) {
   // Each bionic test is run in separate process, so we can safely use a static here.
+  // However, since they're all forked, we need to reenable fdtrack.
+  if (reenable) {
+    android_fdtrack_set_globally_enabled(true);
+  }
+
   static std::vector<android_fdtrack_event> events;
   events.clear();
 
@@ -129,6 +134,21 @@
 #endif
 }
 
+TEST(fdtrack, fork) {
+#if defined(__BIONIC__)
+  ASSERT_EXIT(
+      []() {
+        static int fd = open("/dev/null", O_WRONLY | O_CLOEXEC);
+        ASSERT_NE(-1, fd);
+
+        auto events = FdtrackRun([]() { close(fd); }, false);
+        ASSERT_EQ(0U, events.size());
+        exit(0);
+      }(),
+      testing::ExitedWithCode(0), "");
+#endif
+}
+
 TEST(fdtrack, enable_disable) {
 #if defined(__BIONIC__)
   static int fd1 = -1;
diff --git a/tests/time_test.cpp b/tests/time_test.cpp
index 7c2c890..16299cc 100644
--- a/tests/time_test.cpp
+++ b/tests/time_test.cpp
@@ -851,11 +851,15 @@
 }
 
 TEST(time, clock) {
-  // clock(3) is hard to test, but a 1s sleep should cost less than 20ms.
+  // clock(3) is hard to test, but a 1s sleep should cost less than 10ms on average.
+  static const clock_t N = 5;
+  static const clock_t mean_limit_ms = 10;
   clock_t t0 = clock();
-  sleep(1);
+  for (size_t i = 0; i < N; ++i) {
+    sleep(1);
+  }
   clock_t t1 = clock();
-  ASSERT_LT(t1 - t0, 20 * (CLOCKS_PER_SEC / 1000));
+  ASSERT_LT(t1 - t0, N * mean_limit_ms * (CLOCKS_PER_SEC / 1000));
 }
 
 static pid_t GetInvalidPid() {