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

Commit 83d9eda9 authored by Stephen Smalley's avatar Stephen Smalley
Browse files

Pass additional inputs when spawning apps via the Zygote and add SELinux permission checks.

When spawning an app process, the ActivityManagerService has additional information
about the app package that may be useful in setting a SELinux security context on the
process.  Extend the Process.start() interface to allow passing such information
to the Zygote spawner.  We originally considered using the existing zygoteArgs
argument, but found that those arguments are appended after the class name and
left uninterpreted by ZygoteConnection, merely passed along to the class or wrapper.
Thus we introduce a new seInfo argument for this purpose.

Modify the ZygoteConnection to interpret the new option and convey it to
forkAndSpecialize, as well as passing the nice name as a further input.
Also modify the ZygoteConnection to apply SELinux permission checks on
privileged operations.

Change-Id: I66045ffd33ca9898b1d026882bcc1c5baf3adc17
parent c07fca38
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -274,6 +274,7 @@ public class Process {
     * @param gids Additional group-ids associated with the process.
     * @param debugFlags Additional flags.
     * @param targetSdkVersion The target SDK version for the app.
     * @param seInfo null-ok SE Android information for the new process.
     * @param zygoteArgs Additional arguments to supply to the zygote process.
     * 
     * @return An object that describes the result of the attempt to start the process.
@@ -285,10 +286,11 @@ public class Process {
                                  final String niceName,
                                  int uid, int gid, int[] gids,
                                  int debugFlags, int targetSdkVersion,
                                  String seInfo,
                                  String[] zygoteArgs) {
        try {
            return startViaZygote(processClass, niceName, uid, gid, gids,
                    debugFlags, targetSdkVersion, zygoteArgs);
                    debugFlags, targetSdkVersion, seInfo, zygoteArgs);
        } catch (ZygoteStartFailedEx ex) {
            Log.e(LOG_TAG,
                    "Starting VM process through Zygote failed");
@@ -451,6 +453,7 @@ public class Process {
     * new process should setgroup() to.
     * @param debugFlags Additional flags.
     * @param targetSdkVersion The target SDK version for the app.
     * @param seInfo null-ok SE Android information for the new process.
     * @param extraArgs Additional arguments to supply to the zygote process.
     * @return An object that describes the result of the attempt to start the process.
     * @throws ZygoteStartFailedEx if process start failed for any reason
@@ -460,6 +463,7 @@ public class Process {
                                  final int uid, final int gid,
                                  final int[] gids,
                                  int debugFlags, int targetSdkVersion,
                                  String seInfo,
                                  String[] extraArgs)
                                  throws ZygoteStartFailedEx {
        synchronized(Process.class) {
@@ -510,6 +514,10 @@ public class Process {
                argsForZygote.add("--nice-name=" + niceName);
            }

            if (seInfo != null) {
                argsForZygote.add("--seinfo=" + seInfo);
            }

            argsForZygote.add(processClass);

            if (extraArgs != null) {
+106 −9
Original line number Diff line number Diff line
@@ -26,6 +26,8 @@ import android.util.Log;
import dalvik.system.PathClassLoader;
import dalvik.system.Zygote;

import android.os.SELinux;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
@@ -73,6 +75,7 @@ class ZygoteConnection {
    private final DataOutputStream mSocketOutStream;
    private final BufferedReader mSocketReader;
    private final Credentials peer;
    private final String peerSecurityContext;

    /**
     * A long-lived reference to the original command socket used to launch
@@ -109,6 +112,8 @@ class ZygoteConnection {
            Log.e(TAG, "Cannot read peer credentials", ex);
            throw ex;
        }

        peerSecurityContext = SELinux.getPeerContext(mSocket.getFileDescriptor());
    }

    /**
@@ -207,10 +212,11 @@ class ZygoteConnection {
        try {
            parsedArgs = new Arguments(args);

            applyUidSecurityPolicy(parsedArgs, peer);
            applyRlimitSecurityPolicy(parsedArgs, peer);
            applyCapabilitiesSecurityPolicy(parsedArgs, peer);
            applyInvokeWithSecurityPolicy(parsedArgs, peer);
            applyUidSecurityPolicy(parsedArgs, peer, peerSecurityContext);
            applyRlimitSecurityPolicy(parsedArgs, peer, peerSecurityContext);
            applyCapabilitiesSecurityPolicy(parsedArgs, peer, peerSecurityContext);
            applyInvokeWithSecurityPolicy(parsedArgs, peer, peerSecurityContext);
            applyseInfoSecurityPolicy(parsedArgs, peer, peerSecurityContext);

            applyDebuggerSystemProperty(parsedArgs);
            applyInvokeWithSystemProperty(parsedArgs);
@@ -229,7 +235,8 @@ class ZygoteConnection {
            }

            pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids, parsedArgs.debugFlags, rlimits);
                    parsedArgs.gids, parsedArgs.debugFlags, rlimits,
                    parsedArgs.seInfo, parsedArgs.niceName);
        } catch (IOException ex) {
            logAndPrintError(newStderr, "Exception creating pipe", ex);
        } catch (ErrnoException ex) {
@@ -352,6 +359,10 @@ class ZygoteConnection {
        long permittedCapabilities;
        long effectiveCapabilities;

        /** from --seinfo */
        boolean seInfoSpecified;
        String seInfo;

        /** from all --rlimit=r,c,m */
        ArrayList<int[]> rlimits;

@@ -429,6 +440,13 @@ class ZygoteConnection {
                    peerWait = true;
                } else if (arg.equals("--runtime-init")) {
                    runtimeInit = true;
                } else if (arg.startsWith("--seinfo=")) {
                    if (seInfoSpecified) {
                        throw new IllegalArgumentException(
                                "Duplicate arg specified");
                    }
                    seInfoSpecified = true;
                    seInfo = arg.substring(arg.indexOf('=') + 1);
                } else if (arg.startsWith("--capabilities=")) {
                    if (capabilitiesSpecified) {
                        throw new IllegalArgumentException(
@@ -591,7 +609,8 @@ class ZygoteConnection {
     * @param peer non-null; peer credentials
     * @throws ZygoteSecurityException
     */
    private static void applyUidSecurityPolicy(Arguments args, Credentials peer)
    private static void applyUidSecurityPolicy(Arguments args, Credentials peer,
            String peerSecurityContext)
            throws ZygoteSecurityException {

        int peerUid = peer.getUid();
@@ -624,6 +643,17 @@ class ZygoteConnection {
            }
        }

        if (args.uidSpecified || args.gidSpecified || args.gids != null) {
            boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext,
                                                         peerSecurityContext,
                                                         "zygote",
                                                         "specifyids");
            if (!allowed) {
                throw new ZygoteSecurityException(
                        "Peer may not specify uid's or gid's");
            }
        }

        // If not otherwise specified, uid and gid are inherited from peer
        if (!args.uidSpecified) {
            args.uid = peer.getUid();
@@ -664,7 +694,7 @@ class ZygoteConnection {
     * @throws ZygoteSecurityException
     */
    private static void applyRlimitSecurityPolicy(
            Arguments args, Credentials peer)
            Arguments args, Credentials peer, String peerSecurityContext)
            throws ZygoteSecurityException {

        int peerUid = peer.getUid();
@@ -676,6 +706,17 @@ class ZygoteConnection {
                        "This UID may not specify rlimits.");
            }
        }

        if (args.rlimits != null) {
            boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext,
                                                         peerSecurityContext,
                                                         "zygote",
                                                         "specifyrlimits");
            if (!allowed) {
                throw new ZygoteSecurityException(
                        "Peer may not specify rlimits");
            }
         }
    }

    /**
@@ -689,7 +730,7 @@ class ZygoteConnection {
     * @throws ZygoteSecurityException
     */
    private static void applyCapabilitiesSecurityPolicy(
            Arguments args, Credentials peer)
            Arguments args, Credentials peer, String peerSecurityContext)
            throws ZygoteSecurityException {

        if (args.permittedCapabilities == 0
@@ -698,6 +739,15 @@ class ZygoteConnection {
            return;
        }

        boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext,
                                                     peerSecurityContext,
                                                     "zygote",
                                                     "specifycapabilities");
        if (!allowed) {
            throw new ZygoteSecurityException(
                    "Peer may not specify capabilities");
        }

        if (peer.getUid() == 0) {
            // root may specify anything
            return;
@@ -747,7 +797,8 @@ class ZygoteConnection {
     * @param peer non-null; peer credentials
     * @throws ZygoteSecurityException
     */
    private static void applyInvokeWithSecurityPolicy(Arguments args, Credentials peer)
    private static void applyInvokeWithSecurityPolicy(Arguments args, Credentials peer,
            String peerSecurityContext)
            throws ZygoteSecurityException {
        int peerUid = peer.getUid();

@@ -755,6 +806,52 @@ class ZygoteConnection {
            throw new ZygoteSecurityException("Peer is not permitted to specify "
                    + "an explicit invoke-with wrapper command");
        }

        if (args.invokeWith != null) {
            boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext,
                                                         peerSecurityContext,
                                                         "zygote",
                                                         "specifyinvokewith");
            if (!allowed) {
                throw new ZygoteSecurityException("Peer is not permitted to specify "
                    + "an explicit invoke-with wrapper command");
            }
        }
    }

    /**
     * Applies zygote security policy for SEAndroid information.
     *
     * @param args non-null; zygote spawner arguments
     * @param peer non-null; peer credentials
     * @throws ZygoteSecurityException
     */
    private static void applyseInfoSecurityPolicy(
            Arguments args, Credentials peer, String peerSecurityContext)
            throws ZygoteSecurityException {
        int peerUid = peer.getUid();

        if (args.seInfo == null) {
            // nothing to check
            return;
        }

        if (!(peerUid == 0 || peerUid == Process.SYSTEM_UID)) {
            // All peers with UID other than root or SYSTEM_UID
            throw new ZygoteSecurityException(
                    "This UID may not specify SEAndroid info.");
        }

        boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext,
                                                     peerSecurityContext,
                                                     "zygote",
                                                     "specifyseinfo");
        if (!allowed) {
            throw new ZygoteSecurityException(
                    "Peer may not specify SEAndroid info");
        }

        return;
    }

    /**
+1 −1
Original line number Diff line number Diff line
@@ -1967,7 +1967,7 @@ public final class ActivityManagerService extends ActivityManagerNative
            // the PID of the new process, or else throw a RuntimeException.
            Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
                    app.processName, uid, uid, gids, debugFlags,
                    app.info.targetSdkVersion, null);
                    app.info.targetSdkVersion, null, null);
            BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
            synchronized (bs) {