Merge "Add support for bionic fd ownership enforcement."
diff --git a/luni/src/main/java/libcore/io/ForwardingOs.java b/luni/src/main/java/libcore/io/ForwardingOs.java
index f141694..48c4e1c 100644
--- a/luni/src/main/java/libcore/io/ForwardingOs.java
+++ b/luni/src/main/java/libcore/io/ForwardingOs.java
@@ -70,6 +70,8 @@
     public void chmod(String path, int mode) throws ErrnoException { os.chmod(path, mode); }
     public void chown(String path, int uid, int gid) throws ErrnoException { os.chown(path, uid, gid); }
     public void close(FileDescriptor fd) throws ErrnoException { os.close(fd); }
+    public void android_fdsan_exchange_owner_tag(FileDescriptor fd, long previousOwnerId, long newOwnerId) { os.android_fdsan_exchange_owner_tag(fd, previousOwnerId, newOwnerId); }
+
     public void connect(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException { os.connect(fd, address, port); }
     public void connect(FileDescriptor fd, SocketAddress address) throws ErrnoException, SocketException { os.connect(fd, address); }
     public FileDescriptor dup(FileDescriptor oldFd) throws ErrnoException { return os.dup(oldFd); }
diff --git a/luni/src/main/java/libcore/io/IoBridge.java b/luni/src/main/java/libcore/io/IoBridge.java
index fcd8b9a..338400b 100644
--- a/luni/src/main/java/libcore/io/IoBridge.java
+++ b/luni/src/main/java/libcore/io/IoBridge.java
@@ -229,9 +229,10 @@
     }
 
     /**
-     * Closes the supplied file descriptor and sends a signal to any threads are currently blocking.
-     * In order for the signal to be sent the blocked threads must have registered with
-     * the AsynchronousCloseMonitor before they entered the blocking operation.
+     * Closes the Unix file descriptor associated with the supplied file descriptor and sends a
+     * signal to any threads are currently blocking. In order for the signal to be sent the blocked
+     * threads must have registered with the AsynchronousCloseMonitor before they entered the
+     * blocking operation. {@code fd} will be invalid after this call.
      *
      * <p>This method is a no-op if passed a {@code null} or already-closed file descriptor.
      */
@@ -239,15 +240,13 @@
         if (fd == null || !fd.valid()) {
             return;
         }
-        int intFd = fd.getInt$();
-        fd.setInt$(-1);
-        FileDescriptor oldFd = new FileDescriptor();
-        oldFd.setInt$(intFd);
+        // fd is invalid after we call release.
+        FileDescriptor oldFd = fd.release$();
         AsynchronousCloseMonitor.signalBlockedThreads(oldFd);
         try {
             Libcore.os.close(oldFd);
         } catch (ErrnoException errnoException) {
-            // TODO: are there any cases in which we should throw?
+            throw errnoException.rethrowAsIOException();
         }
     }
 
diff --git a/luni/src/main/java/libcore/io/IoUtils.java b/luni/src/main/java/libcore/io/IoUtils.java
index b01759d..43b800c 100644
--- a/luni/src/main/java/libcore/io/IoUtils.java
+++ b/luni/src/main/java/libcore/io/IoUtils.java
@@ -26,7 +26,9 @@
 import java.net.Socket;
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
+import java.util.Objects;
 import java.util.Random;
+import libcore.util.NonNull;
 import static android.system.OsConstants.*;
 
 public final class IoUtils {
@@ -34,17 +36,74 @@
     }
 
     /**
+     * Acquires ownership of an integer file descriptor from a FileDescriptor.
+     *
+     * This method invalidates the FileDescriptor passed in.
+     *
+     * The important part of this function is that you are taking ownership of a resource that you
+     * must either clean up yourself, or hand off to some other object that does that for you.
+     *
+     * See bionic/include/android/fdsan.h for more details.
+     *
+     * @param fd FileDescriptor to take ownership from, must be non-null.
+     * @throws NullPointerException if fd is null
+     */
+    public static int acquireRawFd(@NonNull FileDescriptor fd) {
+        Objects.requireNonNull(fd);
+
+        FileDescriptor copy = fd.release$();
+        // Get the numeric Unix file descriptor. -1 means it is invalid; for example if
+        // {@link FileDescriptor#release$()} has already been called on the FileDescriptor.
+        int rawFd = copy.getInt$();
+        long previousOwnerId = copy.getOwnerId$();
+        if (rawFd != -1 && previousOwnerId != FileDescriptor.NO_OWNER) {
+          // Clear the file descriptor's owner ID, aborting if the previous value isn't as expected.
+          Libcore.os.android_fdsan_exchange_owner_tag(copy, previousOwnerId,
+                                                      FileDescriptor.NO_OWNER);
+        }
+        return rawFd;
+    }
+
+    /**
+     * Assigns ownership of an unowned FileDescriptor.
+     *
+     * Associates the supplied FileDescriptor and the underlying Unix file descriptor with an owner
+     * ID derived from the supplied {@code owner} object. If the FileDescriptor already has an
+     * associated owner an {@link IllegalStateException} will be thrown. If the underlying Unix
+     * file descriptor already has an associated owner, the process will abort.
+     *
+     * See bionic/include/android/fdsan.h for more details.
+     *
+     * @param fd FileDescriptor to take ownership from, must be non-null.
+     * @throws NullPointerException if fd or owner are null
+     * @throws IllegalStateException if fd is already owned
+     */
+    public static void setFdOwner(@NonNull FileDescriptor fd, @NonNull Object owner) {
+        Objects.requireNonNull(fd);
+        Objects.requireNonNull(owner);
+
+        long previousOwnerId = fd.getOwnerId$();
+        if (previousOwnerId != FileDescriptor.NO_OWNER) {
+            throw new IllegalStateException("Attempted to take ownership of already-owned " +
+                                            "FileDescriptor");
+        }
+
+        // ownerId is not required to be unique but should be stable and should attempt to avoid
+        // collision with identifiers generated both here and in native code (which are simply the
+        // address of the owning object). identityHashCode(Object) meets these requirements.
+        int ownerId = System.identityHashCode(owner);
+        fd.setOwnerId$(ownerId);
+
+        // Set the file descriptor's owner ID, aborting if the previous value isn't as expected.
+        Libcore.os.android_fdsan_exchange_owner_tag(fd, previousOwnerId, ownerId);
+    }
+
+    /**
      * Calls close(2) on 'fd'. Also resets the internal int to -1. Does nothing if 'fd' is null
      * or invalid.
      */
     public static void close(FileDescriptor fd) throws IOException {
-        try {
-            if (fd != null && fd.valid()) {
-                Libcore.os.close(fd);
-            }
-        } catch (ErrnoException errnoException) {
-            throw errnoException.rethrowAsIOException();
-        }
+        IoBridge.closeAndSignalBlockedThreads(fd);
     }
 
     /**
diff --git a/luni/src/main/java/libcore/io/Linux.java b/luni/src/main/java/libcore/io/Linux.java
index 807e5a2..bdbdcf7 100644
--- a/luni/src/main/java/libcore/io/Linux.java
+++ b/luni/src/main/java/libcore/io/Linux.java
@@ -60,7 +60,10 @@
             throws ErrnoException;
     public native void chmod(String path, int mode) throws ErrnoException;
     public native void chown(String path, int uid, int gid) throws ErrnoException;
+
     public native void close(FileDescriptor fd) throws ErrnoException;
+    public native void android_fdsan_exchange_owner_tag(FileDescriptor fd, long previousOwnerId, long newOwnerId);
+
     public native void connect(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException;
     public native void connect(FileDescriptor fd, SocketAddress address) throws ErrnoException, SocketException;
     public native FileDescriptor dup(FileDescriptor oldFd) throws ErrnoException;
diff --git a/luni/src/main/java/libcore/io/Os.java b/luni/src/main/java/libcore/io/Os.java
index 61584b4..f791915 100644
--- a/luni/src/main/java/libcore/io/Os.java
+++ b/luni/src/main/java/libcore/io/Os.java
@@ -54,7 +54,10 @@
     public void capset(StructCapUserHeader hdr, StructCapUserData[] data) throws ErrnoException;
     public void chmod(String path, int mode) throws ErrnoException;
     public void chown(String path, int uid, int gid) throws ErrnoException;
+
     public void close(FileDescriptor fd) throws ErrnoException;
+    public void android_fdsan_exchange_owner_tag(FileDescriptor fd, long previousOwnerId, long newOwnerId);
+
     public void connect(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException;
     public void connect(FileDescriptor fd, SocketAddress address) throws ErrnoException, SocketException;
     public FileDescriptor dup(FileDescriptor oldFd) throws ErrnoException;
diff --git a/luni/src/main/native/libcore_io_Linux.cpp b/luni/src/main/native/libcore_io_Linux.cpp
index 30da35c..5a64218 100644
--- a/luni/src/main/native/libcore_io_Linux.cpp
+++ b/luni/src/main/native/libcore_io_Linux.cpp
@@ -49,8 +49,13 @@
 
 #include <memory>
 
+#if defined(__BIONIC__)
+#include <android/fdsan.h>
+#endif
+
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/macros.h>
 #include <android-base/strings.h>
 #include <log/log.h>
 #include <nativehelper/AsynchronousCloseMonitor.h>
@@ -1089,10 +1094,29 @@
     int fd = jniGetFDFromFileDescriptor(env, javaFd);
     jniSetFileDescriptorOfFD(env, javaFd, -1);
 
+#if defined(__BIONIC__)
+    jlong ownerId = jniGetOwnerIdFromFileDescriptor(env, javaFd);
+
+    // Close with bionic's fd ownership tracking (which returns 0 in the case of EINTR).
+    throwIfMinusOne(env, "close", android_fdsan_close_with_tag(fd, ownerId));
+#else
     // Even if close(2) fails with EINTR, the fd will have been closed.
     // Using TEMP_FAILURE_RETRY will either lead to EBADF or closing someone else's fd.
     // http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
     throwIfMinusOne(env, "close", close(fd));
+#endif
+}
+
+static void Linux_android_fdsan_exchange_owner_tag(JNIEnv* env, jclass,
+                                                   jobject javaFd,
+                                                   jlong expectedOwnerId,
+                                                   jlong newOwnerId) {
+#if defined(__BIONIC__)
+    int fd = jniGetFDFromFileDescriptor(env, javaFd);
+    android_fdsan_exchange_owner_tag(fd, expectedOwnerId, newOwnerId);
+#else
+    UNUSED(env, javaFd, expectedOwnerId, newOwnerId);
+#endif
 }
 
 static void Linux_connect(JNIEnv* env, jobject, jobject javaFd, jobject javaAddress, jint port) {
@@ -2467,6 +2491,7 @@
 static JNINativeMethod gMethods[] = {
     NATIVE_METHOD(Linux, accept, "(Ljava/io/FileDescriptor;Ljava/net/SocketAddress;)Ljava/io/FileDescriptor;"),
     NATIVE_METHOD(Linux, access, "(Ljava/lang/String;I)Z"),
+    NATIVE_METHOD(Linux, android_fdsan_exchange_owner_tag, "(Ljava/io/FileDescriptor;JJ)V"),
     NATIVE_METHOD(Linux, android_getaddrinfo, "(Ljava/lang/String;Landroid/system/StructAddrinfo;I)[Ljava/net/InetAddress;"),
     NATIVE_METHOD(Linux, bind, "(Ljava/io/FileDescriptor;Ljava/net/InetAddress;I)V"),
     NATIVE_METHOD_OVERLOAD(Linux, bind, "(Ljava/io/FileDescriptor;Ljava/net/SocketAddress;)V", SocketAddress),
diff --git a/ojluni/src/main/java/java/io/FileDescriptor.java b/ojluni/src/main/java/java/io/FileDescriptor.java
index 36d8133..a2c833d 100644
--- a/ojluni/src/main/java/java/io/FileDescriptor.java
+++ b/ojluni/src/main/java/java/io/FileDescriptor.java
@@ -54,6 +54,15 @@
     // fetching the descriptor value.
     private int descriptor;
 
+    // Android-added: Track fd owner to guard against accidental closure. http://b/110100358
+    // The owner on the libc side is an pointer-sized value that can be set to an arbitrary
+    // value (with 0 meaning 'unowned'). libcore chooses to use System.identityHashCode.
+    private long ownerId = NO_OWNER;
+
+    // Android-added: value of ownerId indicating that a FileDescriptor is unowned.
+    /** @hide */
+    public static final long NO_OWNER = 0L;
+
     /**
      * Constructs an (invalid) FileDescriptor
      * object.
@@ -160,6 +169,43 @@
         this.descriptor = fd;
     }
 
+    // BEGIN Android-added: Methods to enable ownership enforcement of Unix file descriptors.
+    /**
+     * Returns the owner ID of this FileDescriptor. It's highly unlikely you should be calling this.
+     * Please discuss your needs with a libcore maintainer before using this method.
+     * @hide internal use only
+     */
+    public long getOwnerId$() {
+        return this.ownerId;
+    }
+
+    /**
+     * Sets the owner ID of this FileDescriptor. The owner ID does not need to be unique, but it is
+     * assumed that clashes are rare. See bionic/include/android/fdsan.h for more details.
+     *
+     * It's highly unlikely you should be calling this.
+     * Please discuss your needs with a libcore maintainer before using this method.
+     * @param owner the owner ID of the Object that is responsible for closing this FileDescriptor
+     * @hide internal use only
+     */
+    public void setOwnerId$(long newOwnerId) {
+        this.ownerId = newOwnerId;
+    }
+
+    /**
+     * Returns a copy of this FileDescriptor, and sets this to an invalid state.
+     * @hide internal use only
+     */
+    public FileDescriptor release$() {
+      FileDescriptor result = new FileDescriptor();
+      result.descriptor = this.descriptor;
+      result.ownerId = this.ownerId;
+      this.descriptor = -1;
+      this.ownerId = FileDescriptor.NO_OWNER;
+      return result;
+    }
+    // END Android-added: Methods to enable ownership enforcement of Unix file descriptors.
+
     /**
      * @hide internal use only
      */
diff --git a/ojluni/src/main/java/java/io/FileInputStream.java b/ojluni/src/main/java/java/io/FileInputStream.java
index 8df5f4d..5551b68 100755
--- a/ojluni/src/main/java/java/io/FileInputStream.java
+++ b/ojluni/src/main/java/java/io/FileInputStream.java
@@ -34,6 +34,7 @@
 import sun.nio.ch.FileChannelImpl;
 import libcore.io.IoBridge;
 import libcore.io.IoTracker;
+import libcore.io.IoUtils;
 
 
 /**
@@ -166,6 +167,9 @@
 
         open(name);
 
+        // Android-added: File descriptor ownership tracking.
+        IoUtils.setFdOwner(this.fd, this);
+
         // Android-added: CloseGuard support.
         guard.open("close");
     }
diff --git a/ojluni/src/main/java/java/io/FileOutputStream.java b/ojluni/src/main/java/java/io/FileOutputStream.java
index f29a741..9bd1bc6 100755
--- a/ojluni/src/main/java/java/io/FileOutputStream.java
+++ b/ojluni/src/main/java/java/io/FileOutputStream.java
@@ -34,6 +34,7 @@
 import sun.nio.ch.FileChannelImpl;
 import libcore.io.IoBridge;
 import libcore.io.IoTracker;
+import libcore.io.IoUtils;
 
 /**
  * A file output stream is an output stream for writing data to a
@@ -237,6 +238,9 @@
 
         open(name, append);
 
+        // Android-added: File descriptor ownership tracking.
+        IoUtils.setFdOwner(this.fd, this);
+
         // Android-added: CloseGuard support.
         guard.open("close");
     }
diff --git a/ojluni/src/main/java/java/io/RandomAccessFile.java b/ojluni/src/main/java/java/io/RandomAccessFile.java
index a83829f..06683ad 100755
--- a/ojluni/src/main/java/java/io/RandomAccessFile.java
+++ b/ojluni/src/main/java/java/io/RandomAccessFile.java
@@ -34,6 +34,7 @@
 import dalvik.system.CloseGuard;
 import libcore.io.IoBridge;
 import libcore.io.IoTracker;
+import libcore.io.IoUtils;
 import libcore.io.Libcore;
 import static android.system.OsConstants.*;
 
@@ -286,6 +287,7 @@
 
         // BEGIN Android-changed: Use IoBridge.open() instead of open.
         fd = IoBridge.open(name, imode);
+        IoUtils.setFdOwner(fd, this);
         maybeSync();
         guard.open("close");
         // END Android-changed: Use IoBridge.open() instead of open.