Merge "Pass additional inputs when spawning apps via the Zygote and add SELinux permission checks."
This commit is contained in:
@ -274,6 +274,7 @@ public class Process {
|
|||||||
* @param gids Additional group-ids associated with the process.
|
* @param gids Additional group-ids associated with the process.
|
||||||
* @param debugFlags Additional flags.
|
* @param debugFlags Additional flags.
|
||||||
* @param targetSdkVersion The target SDK version for the app.
|
* @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.
|
* @param zygoteArgs Additional arguments to supply to the zygote process.
|
||||||
*
|
*
|
||||||
* @return An object that describes the result of the attempt to start the 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,
|
final String niceName,
|
||||||
int uid, int gid, int[] gids,
|
int uid, int gid, int[] gids,
|
||||||
int debugFlags, int targetSdkVersion,
|
int debugFlags, int targetSdkVersion,
|
||||||
|
String seInfo,
|
||||||
String[] zygoteArgs) {
|
String[] zygoteArgs) {
|
||||||
try {
|
try {
|
||||||
return startViaZygote(processClass, niceName, uid, gid, gids,
|
return startViaZygote(processClass, niceName, uid, gid, gids,
|
||||||
debugFlags, targetSdkVersion, zygoteArgs);
|
debugFlags, targetSdkVersion, seInfo, zygoteArgs);
|
||||||
} catch (ZygoteStartFailedEx ex) {
|
} catch (ZygoteStartFailedEx ex) {
|
||||||
Log.e(LOG_TAG,
|
Log.e(LOG_TAG,
|
||||||
"Starting VM process through Zygote failed");
|
"Starting VM process through Zygote failed");
|
||||||
@ -451,6 +453,7 @@ public class Process {
|
|||||||
* new process should setgroup() to.
|
* new process should setgroup() to.
|
||||||
* @param debugFlags Additional flags.
|
* @param debugFlags Additional flags.
|
||||||
* @param targetSdkVersion The target SDK version for the app.
|
* @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.
|
* @param extraArgs Additional arguments to supply to the zygote process.
|
||||||
* @return An object that describes the result of the attempt to start the process.
|
* @return An object that describes the result of the attempt to start the process.
|
||||||
* @throws ZygoteStartFailedEx if process start failed for any reason
|
* @throws ZygoteStartFailedEx if process start failed for any reason
|
||||||
@ -460,6 +463,7 @@ public class Process {
|
|||||||
final int uid, final int gid,
|
final int uid, final int gid,
|
||||||
final int[] gids,
|
final int[] gids,
|
||||||
int debugFlags, int targetSdkVersion,
|
int debugFlags, int targetSdkVersion,
|
||||||
|
String seInfo,
|
||||||
String[] extraArgs)
|
String[] extraArgs)
|
||||||
throws ZygoteStartFailedEx {
|
throws ZygoteStartFailedEx {
|
||||||
synchronized(Process.class) {
|
synchronized(Process.class) {
|
||||||
@ -510,6 +514,10 @@ public class Process {
|
|||||||
argsForZygote.add("--nice-name=" + niceName);
|
argsForZygote.add("--nice-name=" + niceName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (seInfo != null) {
|
||||||
|
argsForZygote.add("--seinfo=" + seInfo);
|
||||||
|
}
|
||||||
|
|
||||||
argsForZygote.add(processClass);
|
argsForZygote.add(processClass);
|
||||||
|
|
||||||
if (extraArgs != null) {
|
if (extraArgs != null) {
|
||||||
|
@ -26,6 +26,8 @@ import android.util.Log;
|
|||||||
import dalvik.system.PathClassLoader;
|
import dalvik.system.PathClassLoader;
|
||||||
import dalvik.system.Zygote;
|
import dalvik.system.Zygote;
|
||||||
|
|
||||||
|
import android.os.SELinux;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
@ -73,6 +75,7 @@ class ZygoteConnection {
|
|||||||
private final DataOutputStream mSocketOutStream;
|
private final DataOutputStream mSocketOutStream;
|
||||||
private final BufferedReader mSocketReader;
|
private final BufferedReader mSocketReader;
|
||||||
private final Credentials peer;
|
private final Credentials peer;
|
||||||
|
private final String peerSecurityContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A long-lived reference to the original command socket used to launch
|
* 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);
|
Log.e(TAG, "Cannot read peer credentials", ex);
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
peerSecurityContext = SELinux.getPeerContext(mSocket.getFileDescriptor());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -207,10 +212,11 @@ class ZygoteConnection {
|
|||||||
try {
|
try {
|
||||||
parsedArgs = new Arguments(args);
|
parsedArgs = new Arguments(args);
|
||||||
|
|
||||||
applyUidSecurityPolicy(parsedArgs, peer);
|
applyUidSecurityPolicy(parsedArgs, peer, peerSecurityContext);
|
||||||
applyRlimitSecurityPolicy(parsedArgs, peer);
|
applyRlimitSecurityPolicy(parsedArgs, peer, peerSecurityContext);
|
||||||
applyCapabilitiesSecurityPolicy(parsedArgs, peer);
|
applyCapabilitiesSecurityPolicy(parsedArgs, peer, peerSecurityContext);
|
||||||
applyInvokeWithSecurityPolicy(parsedArgs, peer);
|
applyInvokeWithSecurityPolicy(parsedArgs, peer, peerSecurityContext);
|
||||||
|
applyseInfoSecurityPolicy(parsedArgs, peer, peerSecurityContext);
|
||||||
|
|
||||||
applyDebuggerSystemProperty(parsedArgs);
|
applyDebuggerSystemProperty(parsedArgs);
|
||||||
applyInvokeWithSystemProperty(parsedArgs);
|
applyInvokeWithSystemProperty(parsedArgs);
|
||||||
@ -229,7 +235,8 @@ class ZygoteConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid,
|
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid,
|
||||||
parsedArgs.gids, parsedArgs.debugFlags, rlimits);
|
parsedArgs.gids, parsedArgs.debugFlags, rlimits,
|
||||||
|
parsedArgs.seInfo, parsedArgs.niceName);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
logAndPrintError(newStderr, "Exception creating pipe", ex);
|
logAndPrintError(newStderr, "Exception creating pipe", ex);
|
||||||
} catch (ErrnoException ex) {
|
} catch (ErrnoException ex) {
|
||||||
@ -352,6 +359,10 @@ class ZygoteConnection {
|
|||||||
long permittedCapabilities;
|
long permittedCapabilities;
|
||||||
long effectiveCapabilities;
|
long effectiveCapabilities;
|
||||||
|
|
||||||
|
/** from --seinfo */
|
||||||
|
boolean seInfoSpecified;
|
||||||
|
String seInfo;
|
||||||
|
|
||||||
/** from all --rlimit=r,c,m */
|
/** from all --rlimit=r,c,m */
|
||||||
ArrayList<int[]> rlimits;
|
ArrayList<int[]> rlimits;
|
||||||
|
|
||||||
@ -429,6 +440,13 @@ class ZygoteConnection {
|
|||||||
peerWait = true;
|
peerWait = true;
|
||||||
} else if (arg.equals("--runtime-init")) {
|
} else if (arg.equals("--runtime-init")) {
|
||||||
runtimeInit = true;
|
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=")) {
|
} else if (arg.startsWith("--capabilities=")) {
|
||||||
if (capabilitiesSpecified) {
|
if (capabilitiesSpecified) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
@ -591,7 +609,8 @@ class ZygoteConnection {
|
|||||||
* @param peer non-null; peer credentials
|
* @param peer non-null; peer credentials
|
||||||
* @throws ZygoteSecurityException
|
* @throws ZygoteSecurityException
|
||||||
*/
|
*/
|
||||||
private static void applyUidSecurityPolicy(Arguments args, Credentials peer)
|
private static void applyUidSecurityPolicy(Arguments args, Credentials peer,
|
||||||
|
String peerSecurityContext)
|
||||||
throws ZygoteSecurityException {
|
throws ZygoteSecurityException {
|
||||||
|
|
||||||
int peerUid = peer.getUid();
|
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 not otherwise specified, uid and gid are inherited from peer
|
||||||
if (!args.uidSpecified) {
|
if (!args.uidSpecified) {
|
||||||
args.uid = peer.getUid();
|
args.uid = peer.getUid();
|
||||||
@ -664,7 +694,7 @@ class ZygoteConnection {
|
|||||||
* @throws ZygoteSecurityException
|
* @throws ZygoteSecurityException
|
||||||
*/
|
*/
|
||||||
private static void applyRlimitSecurityPolicy(
|
private static void applyRlimitSecurityPolicy(
|
||||||
Arguments args, Credentials peer)
|
Arguments args, Credentials peer, String peerSecurityContext)
|
||||||
throws ZygoteSecurityException {
|
throws ZygoteSecurityException {
|
||||||
|
|
||||||
int peerUid = peer.getUid();
|
int peerUid = peer.getUid();
|
||||||
@ -676,6 +706,17 @@ class ZygoteConnection {
|
|||||||
"This UID may not specify rlimits.");
|
"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
|
* @throws ZygoteSecurityException
|
||||||
*/
|
*/
|
||||||
private static void applyCapabilitiesSecurityPolicy(
|
private static void applyCapabilitiesSecurityPolicy(
|
||||||
Arguments args, Credentials peer)
|
Arguments args, Credentials peer, String peerSecurityContext)
|
||||||
throws ZygoteSecurityException {
|
throws ZygoteSecurityException {
|
||||||
|
|
||||||
if (args.permittedCapabilities == 0
|
if (args.permittedCapabilities == 0
|
||||||
@ -698,6 +739,15 @@ class ZygoteConnection {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext,
|
||||||
|
peerSecurityContext,
|
||||||
|
"zygote",
|
||||||
|
"specifycapabilities");
|
||||||
|
if (!allowed) {
|
||||||
|
throw new ZygoteSecurityException(
|
||||||
|
"Peer may not specify capabilities");
|
||||||
|
}
|
||||||
|
|
||||||
if (peer.getUid() == 0) {
|
if (peer.getUid() == 0) {
|
||||||
// root may specify anything
|
// root may specify anything
|
||||||
return;
|
return;
|
||||||
@ -747,7 +797,8 @@ class ZygoteConnection {
|
|||||||
* @param peer non-null; peer credentials
|
* @param peer non-null; peer credentials
|
||||||
* @throws ZygoteSecurityException
|
* @throws ZygoteSecurityException
|
||||||
*/
|
*/
|
||||||
private static void applyInvokeWithSecurityPolicy(Arguments args, Credentials peer)
|
private static void applyInvokeWithSecurityPolicy(Arguments args, Credentials peer,
|
||||||
|
String peerSecurityContext)
|
||||||
throws ZygoteSecurityException {
|
throws ZygoteSecurityException {
|
||||||
int peerUid = peer.getUid();
|
int peerUid = peer.getUid();
|
||||||
|
|
||||||
@ -755,6 +806,52 @@ class ZygoteConnection {
|
|||||||
throw new ZygoteSecurityException("Peer is not permitted to specify "
|
throw new ZygoteSecurityException("Peer is not permitted to specify "
|
||||||
+ "an explicit invoke-with wrapper command");
|
+ "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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1967,7 +1967,7 @@ public final class ActivityManagerService extends ActivityManagerNative
|
|||||||
// the PID of the new process, or else throw a RuntimeException.
|
// the PID of the new process, or else throw a RuntimeException.
|
||||||
Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
|
Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
|
||||||
app.processName, uid, uid, gids, debugFlags,
|
app.processName, uid, uid, gids, debugFlags,
|
||||||
app.info.targetSdkVersion, null);
|
app.info.targetSdkVersion, null, null);
|
||||||
|
|
||||||
BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
|
BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
|
||||||
synchronized (bs) {
|
synchronized (bs) {
|
||||||
|
Reference in New Issue
Block a user