Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0c48b94e authored by Nick Kralevich's avatar Nick Kralevich
Browse files

ParcelFileDescriptor: updates for O_CLOEXEC (API >= Q)

For apps which target Q or above, add the O_CLOEXEC flags to
ParcelFileDescriptors.

O_CLOEXEC is essential for ensuring that file descriptors do not leak
across an exec() boundary. Setting O_CLOEXEC ensures that file
descriptors can't linger around unnecessarily in an exec()ed process
which doesn't use them, making more efficient use of resources.
Additionally, O_CLOEXEC is important in ensuring that untrusted
exec()ed code cannot take advantage of leaked file descriptors.

Test: Android compiles and boots
Bug: 120983106
Change-Id: Idb3eb8f0e43968396a3b3a8bddc26a8d94c55bde
parent 3e24ffd2
Loading
Loading
Loading
Loading
+25 −8
Original line number Diff line number Diff line
@@ -17,7 +17,11 @@
package android.os;

import static android.system.OsConstants.AF_UNIX;
import static android.system.OsConstants.F_DUPFD;
import static android.system.OsConstants.F_DUPFD_CLOEXEC;
import static android.system.OsConstants.O_CLOEXEC;
import static android.system.OsConstants.SEEK_SET;
import static android.system.OsConstants.SOCK_CLOEXEC;
import static android.system.OsConstants.SOCK_SEQPACKET;
import static android.system.OsConstants.SOCK_STREAM;
import static android.system.OsConstants.S_IROTH;
@@ -37,6 +41,7 @@ import android.system.StructStat;
import android.util.Log;

import dalvik.system.CloseGuard;
import dalvik.system.VMRuntime;

import libcore.io.IoUtils;
import libcore.io.Memory;
@@ -293,7 +298,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
    }

    private static FileDescriptor openInternal(File file, int mode) throws FileNotFoundException {
        final int flags = FileUtils.translateModePfdToPosix(mode);
        final int flags = FileUtils.translateModePfdToPosix(mode) | ifAtLeastQ(O_CLOEXEC);

        int realMode = S_IRWXU | S_IRWXG;
        if ((mode & MODE_WORLD_READABLE) != 0) realMode |= S_IROTH;
@@ -315,7 +320,9 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
     */
    public static ParcelFileDescriptor dup(FileDescriptor orig) throws IOException {
        try {
            final FileDescriptor fd = Os.dup(orig);
            final FileDescriptor fd = new FileDescriptor();
            int intfd = Os.fcntlInt(orig, (isAtLeastQ() ? F_DUPFD_CLOEXEC : F_DUPFD), 0);
            fd.setInt$(intfd);
            return new ParcelFileDescriptor(fd);
        } catch (ErrnoException e) {
            throw e.rethrowAsIOException();
@@ -351,7 +358,9 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
        original.setInt$(fd);

        try {
            final FileDescriptor dup = Os.dup(original);
            final FileDescriptor dup = new FileDescriptor();
            int intfd = Os.fcntlInt(original, (isAtLeastQ() ? F_DUPFD_CLOEXEC : F_DUPFD), 0);
            dup.setInt$(intfd);
            return new ParcelFileDescriptor(dup);
        } catch (ErrnoException e) {
            throw e.rethrowAsIOException();
@@ -413,7 +422,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
     */
    public static ParcelFileDescriptor[] createPipe() throws IOException {
        try {
            final FileDescriptor[] fds = Os.pipe();
            final FileDescriptor[] fds = Os.pipe2(ifAtLeastQ(O_CLOEXEC));
            return new ParcelFileDescriptor[] {
                    new ParcelFileDescriptor(fds[0]),
                    new ParcelFileDescriptor(fds[1]) };
@@ -435,7 +444,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
    public static ParcelFileDescriptor[] createReliablePipe() throws IOException {
        try {
            final FileDescriptor[] comm = createCommSocketPair();
            final FileDescriptor[] fds = Os.pipe();
            final FileDescriptor[] fds = Os.pipe2(ifAtLeastQ(O_CLOEXEC));
            return new ParcelFileDescriptor[] {
                    new ParcelFileDescriptor(fds[0], comm[0]),
                    new ParcelFileDescriptor(fds[1], comm[1]) };
@@ -459,7 +468,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
        try {
            final FileDescriptor fd0 = new FileDescriptor();
            final FileDescriptor fd1 = new FileDescriptor();
            Os.socketpair(AF_UNIX, type, 0, fd0, fd1);
            Os.socketpair(AF_UNIX, type | ifAtLeastQ(SOCK_CLOEXEC), 0, fd0, fd1);
            return new ParcelFileDescriptor[] {
                    new ParcelFileDescriptor(fd0),
                    new ParcelFileDescriptor(fd1) };
@@ -489,7 +498,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
            final FileDescriptor[] comm = createCommSocketPair();
            final FileDescriptor fd0 = new FileDescriptor();
            final FileDescriptor fd1 = new FileDescriptor();
            Os.socketpair(AF_UNIX, type, 0, fd0, fd1);
            Os.socketpair(AF_UNIX, type | ifAtLeastQ(SOCK_CLOEXEC), 0, fd0, fd1);
            return new ParcelFileDescriptor[] {
                    new ParcelFileDescriptor(fd0, comm[0]),
                    new ParcelFileDescriptor(fd1, comm[1]) };
@@ -505,7 +514,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
            // across multiple IO operations.
            final FileDescriptor comm1 = new FileDescriptor();
            final FileDescriptor comm2 = new FileDescriptor();
            Os.socketpair(AF_UNIX, SOCK_SEQPACKET, 0, comm1, comm2);
            Os.socketpair(AF_UNIX, SOCK_SEQPACKET | ifAtLeastQ(SOCK_CLOEXEC), 0, comm1, comm2);
            IoUtils.setBlocking(comm1, false);
            IoUtils.setBlocking(comm2, false);
            return new FileDescriptor[] { comm1, comm2 };
@@ -1111,4 +1120,12 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
            return "{" + status + ": " + msg + "}";
        }
    }

    private static boolean isAtLeastQ() {
        return (VMRuntime.getRuntime().getTargetSdkVersion() >= Build.VERSION_CODES.Q);
    }

    private static int ifAtLeastQ(int value) {
        return isAtLeastQ() ? value : 0;
    }
}