summaryrefslogtreecommitdiffstats
path: root/services/java/com/android
diff options
context:
space:
mode:
authorRobert Craig <rpcraig@tycho.ncsc.mil>2013-03-18 06:30:15 -0400
committerRicardo Cerqueira <cyanogenmod@cerqueira.org>2013-07-18 21:02:23 +0100
commit7e092967f946dd541429f422c0087e50504d2f37 (patch)
tree681187fd02a5c87fc440332845cb844ce8c46bbe /services/java/com/android
parentc6767eb4b39784833d89d11683f854d55824c64c (diff)
downloadframeworks_base-7e092967f946dd541429f422c0087e50504d2f37.zip
frameworks_base-7e092967f946dd541429f422c0087e50504d2f37.tar.gz
frameworks_base-7e092967f946dd541429f422c0087e50504d2f37.tar.bz2
Move seinfo and install-time changes to inside PMS.
Per request by Google, move the install-time checks entirely inside PMS. Change-Id: I01f2a9084dfe7886087b1497070b0d7f2ad8479e
Diffstat (limited to 'services/java/com/android')
-rw-r--r--services/java/com/android/server/DevicePolicyManagerService.java7
-rw-r--r--services/java/com/android/server/pm/PackageManagerService.java24
-rw-r--r--services/java/com/android/server/pm/SELinuxMMAC.java514
3 files changed, 526 insertions, 19 deletions
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index de0ca83..df50a5e 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -45,7 +45,6 @@ import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
-import android.content.pm.SELinuxMMAC;
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
@@ -259,6 +258,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
+ private static final String MMAC_ENFORCE_PROPERTY = "persist.mmac.enforce";
+
private static final String SEPOLICY_PATH_SEPOLICY = "/data/security/sepolicy";
private static final String SEPOLICY_PATH_PROPCTXS = "/data/security/property_contexts";
@@ -3036,12 +3037,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return false;
}
- boolean systemState = SELinuxMMAC.getEnforcingMode();
+ boolean systemState = SystemProperties.getBoolean(MMAC_ENFORCE_PROPERTY, false);
boolean enforceMMAC = mmacAdmin.enforceMMAC;
if (!firstBoot || !systemState) {
if (systemState != enforceMMAC) {
Slog.v(TAG, "Changed MMAC enforcing status " + systemState + " to " + enforceMMAC);
- SELinuxMMAC.setEnforcingMode(enforceMMAC);
+ SystemProperties.set(MMAC_ENFORCE_PROPERTY, enforceMMAC ? "true" : "false");
}
}
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index b7a9a49..f0408d6 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -85,7 +85,6 @@ import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
-import android.content.pm.SELinuxMMAC;
import android.content.pm.ServiceInfo;
import android.content.pm.Signature;
import android.content.pm.ManifestDigest;
@@ -1041,6 +1040,8 @@ public class PackageManagerService extends IPackageManager.Stub {
readPermissions();
+ mFoundPolicyFile = SELinuxMMAC.readInstallPolicy();
+
mRestoredSettings = mSettings.readLPw(sUserManager.getUsers(false),
mSdkVersion, mOnlyCore);
long startTime = SystemClock.uptimeMillis();
@@ -1164,13 +1165,6 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
- // Find potential SELinux install policy
- long startPolicyTime = SystemClock.uptimeMillis();
- mFoundPolicyFile = SELinuxMMAC.readInstallPolicy();
- Slog.i(TAG, "Time to scan SELinux install policy: "
- + ((SystemClock.uptimeMillis()-startPolicyTime)/1000f)
- + " seconds");
-
// Find base frameworks (resource packages without code).
mFrameworkInstallObserver = new AppDirObserver(
mFrameworkDir.getPath(), OBSERVER_EVENTS, true);
@@ -3659,14 +3653,6 @@ public class PackageManagerService extends IPackageManager.Stub {
}
mScanningPath = scanFile;
- if (mFoundPolicyFile && !SELinuxMMAC.passInstallPolicyChecks(pkg) &&
- SELinuxMMAC.getEnforcingMode()) {
- Slog.w(TAG, "Installing application package " + pkg.packageName
- + " failed due to policy.");
- mLastScanError = PackageManager.INSTALL_FAILED_POLICY_REJECTED_PERMISSION;
- return null;
- }
-
if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
}
@@ -3895,6 +3881,12 @@ public class PackageManagerService extends IPackageManager.Stub {
if (mSettings.isDisabledSystemPackageLPr(pkg.packageName)) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+ } else if (mFoundPolicyFile && !SELinuxMMAC.passInstallPolicyChecks(pkg) &&
+ SELinuxMMAC.getEnforcingMode()) {
+ Slog.w(TAG, "Installing application package " + pkg.packageName
+ + " failed due to policy.");
+ mLastScanError = PackageManager.INSTALL_FAILED_POLICY_REJECTED_PERMISSION;
+ return null;
}
pkg.applicationInfo.uid = pkgSetting.appId;
diff --git a/services/java/com/android/server/pm/SELinuxMMAC.java b/services/java/com/android/server/pm/SELinuxMMAC.java
new file mode 100644
index 0000000..fbddba7
--- /dev/null
+++ b/services/java/com/android/server/pm/SELinuxMMAC.java
@@ -0,0 +1,514 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageParser;
+import android.content.pm.Signature;
+import android.os.Environment;
+import android.os.SystemProperties;
+import android.text.TextUtils;
+import android.util.Slog;
+import android.util.Xml;
+
+import com.android.internal.util.XmlUtils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.TreeSet;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+/**
+ * Centralized access to SELinux MMAC (middleware MAC) implementation.
+ * {@hide}
+ */
+public final class SELinuxMMAC {
+
+ private static final String TAG = "SELinuxMMAC";
+ private static final String MMAC_DENY = "MMAC_DENIAL:";
+ private static final String MMAC_ENFORCE_PROPERTY = "persist.mmac.enforce";
+ private static final boolean DEBUG_POLICY = true;
+ private static final boolean DEBUG_POLICY_INSTALL = DEBUG_POLICY || false;
+
+ // Signature based policy.
+ private static final HashMap<Signature, InstallPolicy> SIG_POLICY =
+ new HashMap<Signature, InstallPolicy>();
+
+ // Package name based policy.
+ private static final HashMap<String, InstallPolicy> PKG_POLICY =
+ new HashMap<String, InstallPolicy>();
+
+ // Locations of potential install policy files.
+ private static final File[] INSTALL_POLICY_FILE = {
+ new File(Environment.getDataDirectory(), "security/mac_permissions.xml"),
+ new File(Environment.getRootDirectory(), "etc/security/mac_permissions.xml"),
+ null};
+
+ private static void flushInstallPolicy() {
+ SIG_POLICY.clear();
+ PKG_POLICY.clear();
+ }
+
+ /**
+ * Parses an MMAC install policy from a predefined list of locations.
+ * @param none
+ * @return boolean indicating whether an install policy was correctly parsed.
+ */
+ public static boolean readInstallPolicy() {
+
+ return readInstallPolicy(INSTALL_POLICY_FILE);
+ }
+
+ /**
+ * Returns the current status of MMAC enforcing mode.
+ * @param none
+ * @return boolean indicating whether or not the device is in enforcing mode.
+ */
+ public static boolean getEnforcingMode() {
+ return SystemProperties.getBoolean(MMAC_ENFORCE_PROPERTY, false);
+ }
+
+ /**
+ * Sets the current status of MMAC enforcing mode.
+ * @param boolean value to set the enforcing state too.
+ */
+ public static void setEnforcingMode(boolean value) {
+ SystemProperties.set(MMAC_ENFORCE_PROPERTY, value ? "1" : "0");
+ }
+
+ /**
+ * Parses an MMAC install policy given as an argument.
+ * @param File object representing the path of the policy.
+ * @return boolean indicating whether the install policy was correctly parsed.
+ */
+ public static boolean readInstallPolicy(File policyFile) {
+
+ return readInstallPolicy(new File[]{policyFile,null});
+ }
+
+ private static boolean readInstallPolicy(File[] policyFiles) {
+
+ FileReader policyFile = null;
+ int i = 0;
+ while (policyFile == null && policyFiles != null && policyFiles[i] != null) {
+ try {
+ policyFile = new FileReader(policyFiles[i]);
+ break;
+ } catch (FileNotFoundException e) {
+ Slog.d(TAG,"Couldn't find install policy " + policyFiles[i].getPath());
+ }
+ i++;
+ }
+
+ if (policyFile == null) {
+ Slog.d(TAG, "MMAC install disabled.");
+ return false;
+ }
+
+ Slog.d(TAG, "MMAC install enabled using file " + policyFiles[i].getPath());
+
+ boolean enforcing = getEnforcingMode();
+ String mode = enforcing ? "enforcing" : "permissive";
+ Slog.d(TAG, "MMAC install starting in " + mode + " mode.");
+
+ flushInstallPolicy();
+
+ try {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(policyFile);
+
+ XmlUtils.beginDocument(parser, "policy");
+ while (true) {
+ XmlUtils.nextElement(parser);
+ if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
+ break;
+ }
+
+ String tagName = parser.getName();
+ if ("signer".equals(tagName)) {
+ String cert = parser.getAttributeValue(null, "signature");
+ if (cert == null) {
+ Slog.w(TAG, "<signer> without signature at "
+ + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+ Signature signature;
+ try {
+ signature = new Signature(cert);
+ } catch (IllegalArgumentException e) {
+ Slog.w(TAG, "<signer> with bad signature at "
+ + parser.getPositionDescription(), e);
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+ if (signature == null) {
+ Slog.w(TAG, "<signer> with null signature at "
+ + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+ InstallPolicy type = determineInstallPolicyType(parser, true);
+ if (type != null) {
+ if (DEBUG_POLICY_INSTALL) {
+ // Pretty print the cert
+ int rowLength = 75;
+ int certLength = cert.length();
+ int rows = certLength / rowLength;
+ Slog.i(TAG, "<signer> tag:");
+ for (int j = 0; j <= rows; j++) {
+ int start = rowLength * j;
+ int rowEndIndex = (rowLength * j) + rowLength;
+ int end = rowEndIndex < certLength ? rowEndIndex : certLength;
+ Slog.i(TAG, cert.substring(start, end));
+ }
+ Slog.i(TAG, " Assigned: " + type);
+ }
+
+ SIG_POLICY.put(signature, type);
+ }
+ } else if ("default".equals(tagName)) {
+ InstallPolicy type = determineInstallPolicyType(parser, true);
+ if (type != null) {
+ if (DEBUG_POLICY_INSTALL)
+ Slog.i(TAG, "<default> tag assigned " + type);
+
+ // The 'null' signature is the default seinfo value
+ SIG_POLICY.put(null, type);
+ }
+ } else if ("package".equals(tagName)) {
+ String pkgName = parser.getAttributeValue(null, "name");
+ if (pkgName == null) {
+ Slog.w(TAG, "<package> without name at "
+ + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+ InstallPolicy type = determineInstallPolicyType(parser, false);
+ if (type != null) {
+ if (DEBUG_POLICY_INSTALL)
+ Slog.i(TAG, "<package> outer tag: (" + pkgName +
+ ") assigned " + type);
+
+ PKG_POLICY.put(pkgName, type);
+ }
+ } else {
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+ }
+ } catch (XmlPullParserException e) {
+ Slog.w(TAG, "Got execption parsing ", e);
+ } catch (IOException e) {
+ Slog.w(TAG, "Got execption parsing ", e);
+ }
+ try {
+ policyFile.close();
+ } catch (IOException e) {
+ //omit
+ }
+ return true;
+ }
+
+ private static InstallPolicy determineInstallPolicyType(XmlPullParser parser,
+ boolean notInsidePackageTag) throws
+ IOException, XmlPullParserException {
+
+ final HashSet<String> denyPolicyPerms = new HashSet<String>();
+ final HashSet<String> allowPolicyPerms = new HashSet<String>();
+
+ final HashMap<String, InstallPolicy> pkgPolicy = new HashMap<String, InstallPolicy>();
+
+ int type;
+ int outerDepth = parser.getDepth();
+ boolean allowAll = false;
+ String seinfo = null;
+ while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG
+ || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG
+ || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if ("seinfo".equals(tagName)) {
+ String seinfoValue = parser.getAttributeValue(null, "value");
+ if (seinfoValue != null) {
+ seinfo = seinfoValue;
+ } else {
+ Slog.w(TAG, "<seinfo> without value at "
+ + parser.getPositionDescription());
+ }
+ } else if ("allow-permission".equals(tagName)) {
+ String permName = parser.getAttributeValue(null, "name");
+ if (permName != null) {
+ allowPolicyPerms.add(permName);
+ } else {
+ Slog.w(TAG, "<allow-permission> without name at "
+ + parser.getPositionDescription());
+ }
+ } else if ("deny-permission".equals(tagName)) {
+ String permName = parser.getAttributeValue(null, "name");
+ if (permName != null) {
+ denyPolicyPerms.add(permName);
+ } else {
+ Slog.w(TAG, "<deny-permission> without name at "
+ + parser.getPositionDescription());
+ }
+ } else if ("allow-all".equals(tagName)) {
+ allowAll = true;
+ } else if ("package".equals(tagName) && notInsidePackageTag) {
+ String pkgName = parser.getAttributeValue(null, "name");
+ if (pkgName != null) {
+ InstallPolicy policyType = determineInstallPolicyType(parser, false);
+ if (policyType != null) {
+ pkgPolicy.put(pkgName, policyType);
+ if (DEBUG_POLICY_INSTALL) {
+ Slog.i(TAG, "<package> inner tag: (" + pkgName +
+ ") assigned " + policyType);
+ }
+ }
+ continue;
+ } else {
+ Slog.w(TAG, "<package> inner tag without name at " +
+ parser.getPositionDescription());
+ }
+ }
+ XmlUtils.skipCurrentTag(parser);
+ }
+
+ // Order is important. Provide the least amount of privilege.
+ InstallPolicy permPolicyType = null;
+ if (denyPolicyPerms.size() > 0) {
+ permPolicyType = new BlackListPolicy(denyPolicyPerms, pkgPolicy, seinfo);
+ } else if (allowPolicyPerms.size() > 0) {
+ permPolicyType = new WhiteListPolicy(allowPolicyPerms, pkgPolicy, seinfo);
+ } else if (allowAll) {
+ permPolicyType = new InstallPolicy(null, pkgPolicy, seinfo);
+ } else if (!pkgPolicy.isEmpty()) {
+ // Consider the case where outside tag has no perms attached
+ // but has an inner package stanza. All the above cases assume that
+ // the outer stanza has permission tags, but here we want to ensure
+ // we capture the inner but deny all outer.
+ permPolicyType = new DenyPolicy(null, pkgPolicy, seinfo);
+ }
+
+ return permPolicyType;
+ }
+
+ static class InstallPolicy {
+
+ final HashSet<String> policyPerms;
+ final HashMap<String, InstallPolicy> pkgPolicy;
+ final private String seinfo;
+
+ InstallPolicy(HashSet<String> policyPerms, HashMap<String, InstallPolicy> pkgPolicy,
+ String seinfo) {
+
+ this.policyPerms = policyPerms;
+ this.pkgPolicy = pkgPolicy;
+ this.seinfo = seinfo;
+ }
+
+ boolean passedPolicyChecks(PackageParser.Package pkg) {
+ // ensure that local package policy takes precedence
+ if (pkgPolicy.containsKey(pkg.packageName)) {
+ return pkgPolicy.get(pkg.packageName).passedPolicyChecks(pkg);
+ }
+ return true;
+ }
+
+ String getSEinfo(String pkgName) {
+ if (pkgPolicy.containsKey(pkgName)) {
+ return pkgPolicy.get(pkgName).getSEinfo(pkgName);
+ }
+ return seinfo;
+ }
+
+ public String toString() {
+ StringBuilder out = new StringBuilder();
+ out.append("[");
+ if (policyPerms != null) {
+ out.append(TextUtils.join(",\n", new TreeSet<String>(policyPerms)));
+ } else {
+ out.append("allow-all");
+ }
+ out.append("]");
+ return out.toString();
+ }
+ }
+
+ static class WhiteListPolicy extends InstallPolicy {
+
+ WhiteListPolicy(HashSet<String> policyPerms, HashMap<String, InstallPolicy> pkgPolicy,
+ String seinfo) {
+
+ super(policyPerms, pkgPolicy, seinfo);
+ }
+
+ @Override
+ public boolean passedPolicyChecks(PackageParser.Package pkg) {
+ // ensure that local package policy takes precedence
+ if (pkgPolicy.containsKey(pkg.packageName)) {
+ return pkgPolicy.get(pkg.packageName).passedPolicyChecks(pkg);
+ }
+
+ Iterator itr = pkg.requestedPermissions.iterator();
+ while (itr.hasNext()) {
+ String perm = (String)itr.next();
+ if (!policyPerms.contains(perm)) {
+ Slog.w(TAG, MMAC_DENY + " Policy whitelist rejected package "
+ + pkg.packageName + ". The rejected permission is " + perm +
+ " The maximal set allowed is: " + toString());
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "allowed-permissions => \n" + super.toString();
+ }
+ }
+
+ static class BlackListPolicy extends InstallPolicy {
+
+ BlackListPolicy(HashSet<String> policyPerms, HashMap<String, InstallPolicy> pkgPolicy,
+ String seinfo) {
+
+ super(policyPerms, pkgPolicy, seinfo);
+ }
+
+ @Override
+ public boolean passedPolicyChecks(PackageParser.Package pkg) {
+ // ensure that local package policy takes precedence
+ if (pkgPolicy.containsKey(pkg.packageName)) {
+ return pkgPolicy.get(pkg.packageName).passedPolicyChecks(pkg);
+ }
+
+ Iterator itr = pkg.requestedPermissions.iterator();
+ while (itr.hasNext()) {
+ String perm = (String)itr.next();
+ if (policyPerms.contains(perm)) {
+ Slog.w(TAG, MMAC_DENY + " Policy blacklisted permission " + perm +
+ " for package " + pkg.packageName);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "denied-permissions => \n" + super.toString();
+ }
+ }
+
+ static class DenyPolicy extends InstallPolicy {
+
+ DenyPolicy(HashSet<String> policyPerms, HashMap<String, InstallPolicy> pkgPolicy,
+ String seinfo) {
+
+ super(policyPerms, pkgPolicy, seinfo);
+ }
+
+ @Override
+ public boolean passedPolicyChecks(PackageParser.Package pkg) {
+ // ensure that local package policy takes precedence
+ if (pkgPolicy.containsKey(pkg.packageName)) {
+ return pkgPolicy.get(pkg.packageName).passedPolicyChecks(pkg);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return "deny-all";
+ }
+ }
+
+ /**
+ * Detemines if the package passes policy. If the package does pass
+ * policy checks then an seinfo label is also assigned to the package.
+ * @param PackageParser.Package object representing the package
+ * to installed and labeled.
+ * @return boolean Indicates whether the package passed policy.
+ */
+ public static boolean passInstallPolicyChecks(PackageParser.Package pkg) {
+
+ // We just want one of the signatures to match.
+ for (Signature s : pkg.mSignatures) {
+ if (s == null) {
+ continue;
+ }
+
+ // Check for a non default signature policy.
+ if (SIG_POLICY.containsKey(s)) {
+ InstallPolicy policy = SIG_POLICY.get(s);
+ if (policy.passedPolicyChecks(pkg)) {
+ String seinfo = pkg.applicationInfo.seinfo = policy.getSEinfo(pkg.packageName);
+ if (DEBUG_POLICY_INSTALL)
+ Slog.i(TAG, "package (" + pkg.packageName + ") installed with " +
+ " seinfo=" + (seinfo == null ? "null" : seinfo));
+ return true;
+ }
+ }
+ }
+
+ // Check for a global per-package policy.
+ if (PKG_POLICY.containsKey(pkg.packageName)) {
+ boolean passed = false;
+ InstallPolicy policy = PKG_POLICY.get(pkg.packageName);
+ if (policy.passedPolicyChecks(pkg)) {
+ String seinfo = pkg.applicationInfo.seinfo = policy.getSEinfo(pkg.packageName);
+ if (DEBUG_POLICY_INSTALL)
+ Slog.i(TAG, "package (" + pkg.packageName + ") installed with " +
+ " seinfo=" + (seinfo == null ? "null" : seinfo));
+ passed = true;
+ }
+ return passed;
+ }
+
+ // Check for a default policy.
+ if (SIG_POLICY.containsKey(null)) {
+ boolean passed = false;
+ InstallPolicy policy = SIG_POLICY.get(null);
+ if (policy.passedPolicyChecks(pkg)) {
+ String seinfo = pkg.applicationInfo.seinfo = policy.getSEinfo(pkg.packageName);
+ if (DEBUG_POLICY_INSTALL)
+ Slog.i(TAG, "package (" + pkg.packageName + ") installed with " +
+ " seinfo=" + (seinfo == null ? "null" : seinfo));
+ passed = true;
+ }
+ return passed;
+ }
+
+ // If we get here it's because this package had no policy.
+ return false;
+ }
+}