summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Smalley <sds@tycho.nsa.gov>2012-01-13 08:34:17 -0500
committerStephen Smalley <sds@tycho.nsa.gov>2012-04-02 13:34:45 -0400
commit83d9eda9c2c411e3480c52f01e192bf3c86be8e9 (patch)
tree5ec3c369b2754e5b38c4d38ed273589a11c63f64
parentc07fca3831baf4d812dd724f506b4ed23dcc39e0 (diff)
downloadframeworks_base-83d9eda9c2c411e3480c52f01e192bf3c86be8e9.zip
frameworks_base-83d9eda9c2c411e3480c52f01e192bf3c86be8e9.tar.gz
frameworks_base-83d9eda9c2c411e3480c52f01e192bf3c86be8e9.tar.bz2
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
-rw-r--r--core/java/android/os/Process.java10
-rw-r--r--core/java/com/android/internal/os/ZygoteConnection.java115
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java2
3 files changed, 116 insertions, 11 deletions
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index e1bc275..50567b2 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -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) {
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 9af7e96..b016e99 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -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;
}
/**
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index cffb391..5044554 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -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) {