From 7e092967f946dd541429f422c0087e50504d2f37 Mon Sep 17 00:00:00 2001 From: Robert Craig Date: Mon, 18 Mar 2013 06:30:15 -0400 Subject: Move seinfo and install-time changes to inside PMS. Per request by Google, move the install-time checks entirely inside PMS. Change-Id: I01f2a9084dfe7886087b1497070b0d7f2ad8479e --- .../android/server/DevicePolicyManagerService.java | 7 +- .../android/server/pm/PackageManagerService.java | 24 +- .../java/com/android/server/pm/SELinuxMMAC.java | 514 ++++++++++++++++++++ services/tests/servicestests/Android.mk | 30 +- services/tests/servicestests/apks/Android.mk | 7 + .../apks/FrameworkServicesTests_apk.mk | 12 + .../apks/mmac_install_media/Android.mk | 10 + .../apks/mmac_install_media/AndroidManifest.xml | 27 ++ .../frameworks/servicestests/DoNothing.java | 21 + .../apks/mmac_install_platform/Android.mk | 10 + .../apks/mmac_install_platform/AndroidManifest.xml | 27 ++ .../frameworks/servicestests/DoNothing.java | 21 + .../apks/mmac_install_platform_2/Android.mk | 10 + .../mmac_install_platform_2/AndroidManifest.xml | 27 ++ .../frameworks/servicestests/DoNothing.java | 21 + .../servicestests/res/raw/mmac_default_all.xml | 15 + .../servicestests/res/raw/mmac_default_black.xml | 16 + .../res/raw/mmac_default_black_deny.xml | 16 + .../res/raw/mmac_default_inner_pkg.xml | 23 + .../res/raw/mmac_default_inner_pkg_deny.xml | 21 + .../res/raw/mmac_default_inner_pkg_out_empty.xml | 21 + .../res/raw/mmac_default_null_seinfo.xml | 14 + .../servicestests/res/raw/mmac_default_white.xml | 18 + .../res/raw/mmac_default_white_deny.xml | 15 + .../res/raw/mmac_diff_name_deny_outer.xml | 30 ++ .../res/raw/mmac_diff_name_skip_outer.xml | 28 ++ .../raw/mmac_inner_seinfo_null_outer_seinfo.xml | 28 ++ .../res/raw/mmac_inside_pkg_allow_all.xml | 30 ++ .../res/raw/mmac_inside_pkg_allow_black.xml | 31 ++ .../res/raw/mmac_inside_pkg_allow_null_seinfo.xml | 32 ++ .../res/raw/mmac_inside_pkg_allow_white.xml | 33 ++ .../res/raw/mmac_inside_pkg_deny_default.xml | 33 ++ .../res/raw/mmac_inside_pkg_deny_noother.xml | 30 ++ .../res/raw/mmac_inside_pkg_deny_pkg.xml | 30 ++ .../tests/servicestests/res/raw/mmac_no_match.xml | 15 + .../res/raw/mmac_outer_no_rule_catch_inner.xml | 28 ++ .../tests/servicestests/res/raw/mmac_pkg_all.xml | 20 + .../tests/servicestests/res/raw/mmac_pkg_black.xml | 21 + .../servicestests/res/raw/mmac_pkg_deny_black.xml | 21 + .../servicestests/res/raw/mmac_pkg_deny_white.xml | 20 + .../servicestests/res/raw/mmac_pkg_null_seinfo.xml | 22 + .../tests/servicestests/res/raw/mmac_pkg_white.xml | 23 + .../res/raw/mmac_same_name_diff_cert.xml | 30 ++ .../tests/servicestests/res/raw/mmac_sig_all.xml | 26 + .../tests/servicestests/res/raw/mmac_sig_black.xml | 26 + .../res/raw/mmac_sig_deny_default_allow.xml | 21 + .../res/raw/mmac_sig_deny_default_deny.xml | 21 + .../res/raw/mmac_sig_deny_noother.xml | 16 + .../res/raw/mmac_sig_deny_pkg_allow.xml | 26 + .../res/raw/mmac_sig_deny_pkg_deny.xml | 26 + .../tests/servicestests/res/raw/mmac_sig_null.xml | 25 + .../tests/servicestests/res/raw/mmac_sig_white.xml | 29 ++ .../com/android/server/pm/SELinuxMMACTests.java | 523 +++++++++++++++++++++ 53 files changed, 2151 insertions(+), 20 deletions(-) create mode 100644 services/java/com/android/server/pm/SELinuxMMAC.java create mode 100644 services/tests/servicestests/apks/Android.mk create mode 100644 services/tests/servicestests/apks/FrameworkServicesTests_apk.mk create mode 100644 services/tests/servicestests/apks/mmac_install_media/Android.mk create mode 100644 services/tests/servicestests/apks/mmac_install_media/AndroidManifest.xml create mode 100644 services/tests/servicestests/apks/mmac_install_media/src/com/android/frameworks/servicestests/DoNothing.java create mode 100644 services/tests/servicestests/apks/mmac_install_platform/Android.mk create mode 100644 services/tests/servicestests/apks/mmac_install_platform/AndroidManifest.xml create mode 100644 services/tests/servicestests/apks/mmac_install_platform/src/com/android/frameworks/servicestests/DoNothing.java create mode 100644 services/tests/servicestests/apks/mmac_install_platform_2/Android.mk create mode 100644 services/tests/servicestests/apks/mmac_install_platform_2/AndroidManifest.xml create mode 100644 services/tests/servicestests/apks/mmac_install_platform_2/src/com/android/frameworks/servicestests/DoNothing.java create mode 100644 services/tests/servicestests/res/raw/mmac_default_all.xml create mode 100644 services/tests/servicestests/res/raw/mmac_default_black.xml create mode 100644 services/tests/servicestests/res/raw/mmac_default_black_deny.xml create mode 100644 services/tests/servicestests/res/raw/mmac_default_inner_pkg.xml create mode 100644 services/tests/servicestests/res/raw/mmac_default_inner_pkg_deny.xml create mode 100644 services/tests/servicestests/res/raw/mmac_default_inner_pkg_out_empty.xml create mode 100644 services/tests/servicestests/res/raw/mmac_default_null_seinfo.xml create mode 100644 services/tests/servicestests/res/raw/mmac_default_white.xml create mode 100644 services/tests/servicestests/res/raw/mmac_default_white_deny.xml create mode 100644 services/tests/servicestests/res/raw/mmac_diff_name_deny_outer.xml create mode 100644 services/tests/servicestests/res/raw/mmac_diff_name_skip_outer.xml create mode 100644 services/tests/servicestests/res/raw/mmac_inner_seinfo_null_outer_seinfo.xml create mode 100644 services/tests/servicestests/res/raw/mmac_inside_pkg_allow_all.xml create mode 100644 services/tests/servicestests/res/raw/mmac_inside_pkg_allow_black.xml create mode 100644 services/tests/servicestests/res/raw/mmac_inside_pkg_allow_null_seinfo.xml create mode 100644 services/tests/servicestests/res/raw/mmac_inside_pkg_allow_white.xml create mode 100644 services/tests/servicestests/res/raw/mmac_inside_pkg_deny_default.xml create mode 100644 services/tests/servicestests/res/raw/mmac_inside_pkg_deny_noother.xml create mode 100644 services/tests/servicestests/res/raw/mmac_inside_pkg_deny_pkg.xml create mode 100644 services/tests/servicestests/res/raw/mmac_no_match.xml create mode 100644 services/tests/servicestests/res/raw/mmac_outer_no_rule_catch_inner.xml create mode 100644 services/tests/servicestests/res/raw/mmac_pkg_all.xml create mode 100644 services/tests/servicestests/res/raw/mmac_pkg_black.xml create mode 100644 services/tests/servicestests/res/raw/mmac_pkg_deny_black.xml create mode 100644 services/tests/servicestests/res/raw/mmac_pkg_deny_white.xml create mode 100644 services/tests/servicestests/res/raw/mmac_pkg_null_seinfo.xml create mode 100644 services/tests/servicestests/res/raw/mmac_pkg_white.xml create mode 100644 services/tests/servicestests/res/raw/mmac_same_name_diff_cert.xml create mode 100644 services/tests/servicestests/res/raw/mmac_sig_all.xml create mode 100644 services/tests/servicestests/res/raw/mmac_sig_black.xml create mode 100644 services/tests/servicestests/res/raw/mmac_sig_deny_default_allow.xml create mode 100644 services/tests/servicestests/res/raw/mmac_sig_deny_default_deny.xml create mode 100644 services/tests/servicestests/res/raw/mmac_sig_deny_noother.xml create mode 100644 services/tests/servicestests/res/raw/mmac_sig_deny_pkg_allow.xml create mode 100644 services/tests/servicestests/res/raw/mmac_sig_deny_pkg_deny.xml create mode 100644 services/tests/servicestests/res/raw/mmac_sig_null.xml create mode 100644 services/tests/servicestests/res/raw/mmac_sig_white.xml create mode 100644 services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTests.java (limited to 'services') 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 SIG_POLICY = + new HashMap(); + + // Package name based policy. + private static final HashMap PKG_POLICY = + new HashMap(); + + // 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, " without signature at " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } + Signature signature; + try { + signature = new Signature(cert); + } catch (IllegalArgumentException e) { + Slog.w(TAG, " with bad signature at " + + parser.getPositionDescription(), e); + XmlUtils.skipCurrentTag(parser); + continue; + } + if (signature == null) { + Slog.w(TAG, " 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, " 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, " 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, " without name at " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } + InstallPolicy type = determineInstallPolicyType(parser, false); + if (type != null) { + if (DEBUG_POLICY_INSTALL) + Slog.i(TAG, " 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 denyPolicyPerms = new HashSet(); + final HashSet allowPolicyPerms = new HashSet(); + + final HashMap pkgPolicy = new HashMap(); + + 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, " 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, " 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, " 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, " inner tag: (" + pkgName + + ") assigned " + policyType); + } + } + continue; + } else { + Slog.w(TAG, " 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 policyPerms; + final HashMap pkgPolicy; + final private String seinfo; + + InstallPolicy(HashSet policyPerms, HashMap 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(policyPerms))); + } else { + out.append("allow-all"); + } + out.append("]"); + return out.toString(); + } + } + + static class WhiteListPolicy extends InstallPolicy { + + WhiteListPolicy(HashSet policyPerms, HashMap 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 policyPerms, HashMap 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 policyPerms, HashMap 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; + } +} diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk index 81a2c14..e303a09 100644 --- a/services/tests/servicestests/Android.mk +++ b/services/tests/servicestests/Android.mk @@ -1,4 +1,14 @@ -LOCAL_PATH:= $(call my-dir) +ACTUAL_LOCAL_PATH := $(call my-dir) + +# this var will hold all the test apk module names later. +FrameworkServicesTests_all_apks := + +# We have to include the subdir makefiles first +# so that FrameworkServicesTests_all_apks will be populated correctly. +include $(call all-makefiles-under,$(ACTUAL_LOCAL_PATH)) + +LOCAL_PATH := $(ACTUAL_LOCAL_PATH) + include $(CLEAR_VARS) # We only want this apk build for tests. @@ -18,5 +28,23 @@ LOCAL_PACKAGE_NAME := FrameworksServicesTests LOCAL_CERTIFICATE := platform +# intermediate dir to include all the test apks as raw resource +FrameworkServicesTests_intermediates := $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME))/test_apks/res +LOCAL_RESOURCE_DIR := $(FrameworkServicesTests_intermediates) $(LOCAL_PATH)/res + include $(BUILD_PACKAGE) +# Rules to copy all the test apks to the intermediate raw resource directory +FrameworkServicesTests_all_apks_res := $(addprefix $(FrameworkServicesTests_intermediates)/raw/, \ + $(foreach a, $(FrameworkServicesTests_all_apks), $(patsubst FrameworkServicesTests_%,%,$(a)))) + +$(FrameworkServicesTests_all_apks_res): $(FrameworkServicesTests_intermediates)/raw/%: $(call intermediates-dir-for,APPS,FrameworkServicesTests_%)/package.apk | $(ACP) + $(call copy-file-to-new-target) + +# Use R_file_stamp as dependency because we want the test apks in place before the R.java is generated. +$(R_file_stamp) : $(FrameworkServicesTests_all_apks_res) + +FrameworkServicesTests_all_apks := +FrameworkServicesTests_intermediates := +FrameworkServicesTests_all_apks_res := + diff --git a/services/tests/servicestests/apks/Android.mk b/services/tests/servicestests/apks/Android.mk new file mode 100644 index 0000000..bd1512b --- /dev/null +++ b/services/tests/servicestests/apks/Android.mk @@ -0,0 +1,7 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +FrameworkServicesTests_BUILD_PACKAGE := $(LOCAL_PATH)/FrameworkServicesTests_apk.mk + +# build sub packages +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/services/tests/servicestests/apks/FrameworkServicesTests_apk.mk b/services/tests/servicestests/apks/FrameworkServicesTests_apk.mk new file mode 100644 index 0000000..1240cb8 --- /dev/null +++ b/services/tests/servicestests/apks/FrameworkServicesTests_apk.mk @@ -0,0 +1,12 @@ + +LOCAL_MODULE_TAGS := tests + +# Disable dexpreopt. +LOCAL_DEX_PREOPT := false + +# Make sure every package name gets the FrameworkServicesTests_ prefix. +LOCAL_PACKAGE_NAME := FrameworkServicesTests_$(LOCAL_PACKAGE_NAME) + +FrameworkServicesTests_all_apks += $(LOCAL_PACKAGE_NAME) + +include $(BUILD_PACKAGE) diff --git a/services/tests/servicestests/apks/mmac_install_media/Android.mk b/services/tests/servicestests/apks/mmac_install_media/Android.mk new file mode 100644 index 0000000..ea9d948 --- /dev/null +++ b/services/tests/servicestests/apks/mmac_install_media/Android.mk @@ -0,0 +1,10 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_PACKAGE_NAME := signed_media + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_CERTIFICATE := media + +include $(FrameworkServicesTests_BUILD_PACKAGE) diff --git a/services/tests/servicestests/apks/mmac_install_media/AndroidManifest.xml b/services/tests/servicestests/apks/mmac_install_media/AndroidManifest.xml new file mode 100644 index 0000000..fb7587a --- /dev/null +++ b/services/tests/servicestests/apks/mmac_install_media/AndroidManifest.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + diff --git a/services/tests/servicestests/apks/mmac_install_media/src/com/android/frameworks/servicestests/DoNothing.java b/services/tests/servicestests/apks/mmac_install_media/src/com/android/frameworks/servicestests/DoNothing.java new file mode 100644 index 0000000..3f3a35c --- /dev/null +++ b/services/tests/servicestests/apks/mmac_install_media/src/com/android/frameworks/servicestests/DoNothing.java @@ -0,0 +1,21 @@ +/* + * 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.frameworks.servicestests; + +public class DoNothing { + +} diff --git a/services/tests/servicestests/apks/mmac_install_platform/Android.mk b/services/tests/servicestests/apks/mmac_install_platform/Android.mk new file mode 100644 index 0000000..5cdd9ba --- /dev/null +++ b/services/tests/servicestests/apks/mmac_install_platform/Android.mk @@ -0,0 +1,10 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_PACKAGE_NAME := signed_platform + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_CERTIFICATE := platform + +include $(FrameworkServicesTests_BUILD_PACKAGE) diff --git a/services/tests/servicestests/apks/mmac_install_platform/AndroidManifest.xml b/services/tests/servicestests/apks/mmac_install_platform/AndroidManifest.xml new file mode 100644 index 0000000..b11b37a --- /dev/null +++ b/services/tests/servicestests/apks/mmac_install_platform/AndroidManifest.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + diff --git a/services/tests/servicestests/apks/mmac_install_platform/src/com/android/frameworks/servicestests/DoNothing.java b/services/tests/servicestests/apks/mmac_install_platform/src/com/android/frameworks/servicestests/DoNothing.java new file mode 100644 index 0000000..3f3a35c --- /dev/null +++ b/services/tests/servicestests/apks/mmac_install_platform/src/com/android/frameworks/servicestests/DoNothing.java @@ -0,0 +1,21 @@ +/* + * 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.frameworks.servicestests; + +public class DoNothing { + +} diff --git a/services/tests/servicestests/apks/mmac_install_platform_2/Android.mk b/services/tests/servicestests/apks/mmac_install_platform_2/Android.mk new file mode 100644 index 0000000..5d8c2c8 --- /dev/null +++ b/services/tests/servicestests/apks/mmac_install_platform_2/Android.mk @@ -0,0 +1,10 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_PACKAGE_NAME := signed_platform_2 + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_CERTIFICATE := platform + +include $(FrameworkServicesTests_BUILD_PACKAGE) diff --git a/services/tests/servicestests/apks/mmac_install_platform_2/AndroidManifest.xml b/services/tests/servicestests/apks/mmac_install_platform_2/AndroidManifest.xml new file mode 100644 index 0000000..cb60867 --- /dev/null +++ b/services/tests/servicestests/apks/mmac_install_platform_2/AndroidManifest.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + diff --git a/services/tests/servicestests/apks/mmac_install_platform_2/src/com/android/frameworks/servicestests/DoNothing.java b/services/tests/servicestests/apks/mmac_install_platform_2/src/com/android/frameworks/servicestests/DoNothing.java new file mode 100644 index 0000000..3f3a35c --- /dev/null +++ b/services/tests/servicestests/apks/mmac_install_platform_2/src/com/android/frameworks/servicestests/DoNothing.java @@ -0,0 +1,21 @@ +/* + * 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.frameworks.servicestests; + +public class DoNothing { + +} diff --git a/services/tests/servicestests/res/raw/mmac_default_all.xml b/services/tests/servicestests/res/raw/mmac_default_all.xml new file mode 100644 index 0000000..63a2f12 --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_default_all.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_default_black.xml b/services/tests/servicestests/res/raw/mmac_default_black.xml new file mode 100644 index 0000000..7d30351 --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_default_black.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_default_black_deny.xml b/services/tests/servicestests/res/raw/mmac_default_black_deny.xml new file mode 100644 index 0000000..ddd779c --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_default_black_deny.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_default_inner_pkg.xml b/services/tests/servicestests/res/raw/mmac_default_inner_pkg.xml new file mode 100644 index 0000000..b7c3e36 --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_default_inner_pkg.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_default_inner_pkg_deny.xml b/services/tests/servicestests/res/raw/mmac_default_inner_pkg_deny.xml new file mode 100644 index 0000000..6909273 --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_default_inner_pkg_deny.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_default_inner_pkg_out_empty.xml b/services/tests/servicestests/res/raw/mmac_default_inner_pkg_out_empty.xml new file mode 100644 index 0000000..0e7c72b --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_default_inner_pkg_out_empty.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_default_null_seinfo.xml b/services/tests/servicestests/res/raw/mmac_default_null_seinfo.xml new file mode 100644 index 0000000..20d4a2c --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_default_null_seinfo.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_default_white.xml b/services/tests/servicestests/res/raw/mmac_default_white.xml new file mode 100644 index 0000000..c7f6eab --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_default_white.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_default_white_deny.xml b/services/tests/servicestests/res/raw/mmac_default_white_deny.xml new file mode 100644 index 0000000..0c49ce8 --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_default_white_deny.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_diff_name_deny_outer.xml b/services/tests/servicestests/res/raw/mmac_diff_name_deny_outer.xml new file mode 100644 index 0000000..e9e852c --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_diff_name_deny_outer.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_diff_name_skip_outer.xml b/services/tests/servicestests/res/raw/mmac_diff_name_skip_outer.xml new file mode 100644 index 0000000..996e80b --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_diff_name_skip_outer.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_inner_seinfo_null_outer_seinfo.xml b/services/tests/servicestests/res/raw/mmac_inner_seinfo_null_outer_seinfo.xml new file mode 100644 index 0000000..8348812 --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_inner_seinfo_null_outer_seinfo.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_inside_pkg_allow_all.xml b/services/tests/servicestests/res/raw/mmac_inside_pkg_allow_all.xml new file mode 100644 index 0000000..f98f80a --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_inside_pkg_allow_all.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_inside_pkg_allow_black.xml b/services/tests/servicestests/res/raw/mmac_inside_pkg_allow_black.xml new file mode 100644 index 0000000..19d46bc --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_inside_pkg_allow_black.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_inside_pkg_allow_null_seinfo.xml b/services/tests/servicestests/res/raw/mmac_inside_pkg_allow_null_seinfo.xml new file mode 100644 index 0000000..f48bee0 --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_inside_pkg_allow_null_seinfo.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_inside_pkg_allow_white.xml b/services/tests/servicestests/res/raw/mmac_inside_pkg_allow_white.xml new file mode 100644 index 0000000..83eeb7f --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_inside_pkg_allow_white.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_inside_pkg_deny_default.xml b/services/tests/servicestests/res/raw/mmac_inside_pkg_deny_default.xml new file mode 100644 index 0000000..92f92e1 --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_inside_pkg_deny_default.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_inside_pkg_deny_noother.xml b/services/tests/servicestests/res/raw/mmac_inside_pkg_deny_noother.xml new file mode 100644 index 0000000..e7d7930 --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_inside_pkg_deny_noother.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_inside_pkg_deny_pkg.xml b/services/tests/servicestests/res/raw/mmac_inside_pkg_deny_pkg.xml new file mode 100644 index 0000000..e39e7f0 --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_inside_pkg_deny_pkg.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_no_match.xml b/services/tests/servicestests/res/raw/mmac_no_match.xml new file mode 100644 index 0000000..4f8621a --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_no_match.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_outer_no_rule_catch_inner.xml b/services/tests/servicestests/res/raw/mmac_outer_no_rule_catch_inner.xml new file mode 100644 index 0000000..996e80b --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_outer_no_rule_catch_inner.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_pkg_all.xml b/services/tests/servicestests/res/raw/mmac_pkg_all.xml new file mode 100644 index 0000000..6d9c9c9 --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_pkg_all.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_pkg_black.xml b/services/tests/servicestests/res/raw/mmac_pkg_black.xml new file mode 100644 index 0000000..a52167c --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_pkg_black.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_pkg_deny_black.xml b/services/tests/servicestests/res/raw/mmac_pkg_deny_black.xml new file mode 100644 index 0000000..4aa6555 --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_pkg_deny_black.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_pkg_deny_white.xml b/services/tests/servicestests/res/raw/mmac_pkg_deny_white.xml new file mode 100644 index 0000000..fbb4625 --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_pkg_deny_white.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_pkg_null_seinfo.xml b/services/tests/servicestests/res/raw/mmac_pkg_null_seinfo.xml new file mode 100644 index 0000000..ed9030d --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_pkg_null_seinfo.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_pkg_white.xml b/services/tests/servicestests/res/raw/mmac_pkg_white.xml new file mode 100644 index 0000000..7c3de78 --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_pkg_white.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_same_name_diff_cert.xml b/services/tests/servicestests/res/raw/mmac_same_name_diff_cert.xml new file mode 100644 index 0000000..b376cd0 --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_same_name_diff_cert.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_sig_all.xml b/services/tests/servicestests/res/raw/mmac_sig_all.xml new file mode 100644 index 0000000..513b890 --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_sig_all.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_sig_black.xml b/services/tests/servicestests/res/raw/mmac_sig_black.xml new file mode 100644 index 0000000..2a54380 --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_sig_black.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_sig_deny_default_allow.xml b/services/tests/servicestests/res/raw/mmac_sig_deny_default_allow.xml new file mode 100644 index 0000000..4f2b808 --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_sig_deny_default_allow.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_sig_deny_default_deny.xml b/services/tests/servicestests/res/raw/mmac_sig_deny_default_deny.xml new file mode 100644 index 0000000..f2e9200 --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_sig_deny_default_deny.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_sig_deny_noother.xml b/services/tests/servicestests/res/raw/mmac_sig_deny_noother.xml new file mode 100644 index 0000000..a82e9e6 --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_sig_deny_noother.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_sig_deny_pkg_allow.xml b/services/tests/servicestests/res/raw/mmac_sig_deny_pkg_allow.xml new file mode 100644 index 0000000..e994946 --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_sig_deny_pkg_allow.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_sig_deny_pkg_deny.xml b/services/tests/servicestests/res/raw/mmac_sig_deny_pkg_deny.xml new file mode 100644 index 0000000..014bdc6 --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_sig_deny_pkg_deny.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_sig_null.xml b/services/tests/servicestests/res/raw/mmac_sig_null.xml new file mode 100644 index 0000000..86ab088 --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_sig_null.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/res/raw/mmac_sig_white.xml b/services/tests/servicestests/res/raw/mmac_sig_white.xml new file mode 100644 index 0000000..66fe3a7 --- /dev/null +++ b/services/tests/servicestests/res/raw/mmac_sig_white.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTests.java b/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTests.java new file mode 100644 index 0000000..d4c2d57 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTests.java @@ -0,0 +1,523 @@ +/* + * 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.PackageManagerTests; +import android.content.pm.PackageParser; +import android.content.res.Resources; +import android.content.res.Resources.NotFoundException; +import android.net.Uri; +import android.os.FileUtils; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.LargeTest; +import android.util.DisplayMetrics; +import android.util.Log; + +import com.android.frameworks.servicestests.R; + +import java.io.File; +import java.io.FileReader; +import java.io.InputStream; + +/** Test {@link SELinuxMMAC} functionality. */ +public class SELinuxMMACTests extends AndroidTestCase { + + private static final String TAG = "SELinuxMMACTests"; + + private static File MAC_INSTALL_TMP; + private static File APK_INSTALL_TMP; + private static final String MAC_INSTALL_TMP_NAME = "mac_install_policy"; + private static final String APK_INSTALL_TMP_NAME = "install.apk"; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + // Need a tmp file to hold the various mmac install files. + File filesDir = mContext.getFilesDir(); + MAC_INSTALL_TMP = new File(filesDir, MAC_INSTALL_TMP_NAME); + assertNotNull(MAC_INSTALL_TMP); + + // Need a tmp file to hold the apk + APK_INSTALL_TMP = new File(filesDir, APK_INSTALL_TMP_NAME); + assertNotNull(APK_INSTALL_TMP); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + + // Just in case still around + MAC_INSTALL_TMP.delete(); + APK_INSTALL_TMP.delete(); + + // Reload the original policy + SELinuxMMAC.readInstallPolicy(); + } + + void failStr(String errMsg) { + Log.w(TAG, "errMsg="+errMsg); + fail(errMsg); + } + + void failStr(Exception e) { + failStr(e.getMessage()); + } + + private PackageParser.Package parsePackage(Uri packageURI) { + final String archiveFilePath = packageURI.getPath(); + PackageParser packageParser = new PackageParser(archiveFilePath); + File sourceFile = new File(archiveFilePath); + DisplayMetrics metrics = new DisplayMetrics(); + metrics.setToDefaults(); + PackageParser.Package pkg = packageParser.parsePackage(sourceFile, + archiveFilePath, + metrics, 0); + assertNotNull(pkg); + assertTrue(packageParser.collectCertificates(pkg,0)); + packageParser = null; + return pkg; + } + + Uri getResourceURI(int fileResId, File outFile) { + Resources res = mContext.getResources(); + InputStream is = null; + try { + is = res.openRawResource(fileResId); + } catch (NotFoundException e) { + failStr("Failed to load resource with id: " + fileResId); + } + assertNotNull(is); + FileUtils.setPermissions(outFile.getPath(), + FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IRWXO, + -1, -1); + assertTrue(FileUtils.copyToFile(is, outFile)); + FileUtils.setPermissions(outFile.getPath(), + FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IRWXO, + -1, -1); + return Uri.fromFile(outFile); + } + + /** + * Takes the policy xml file as a resource, the apk as a resource, + * the expected seinfo string, and the expected install value. + * We mock a package install here by calling parsePackage. + */ + void checkInstallMMAC(int policyRes, int apkRes, + String expectedSeinfo, + boolean expectedPassed) { + // grab policy file + Uri policyURI = getResourceURI(policyRes, MAC_INSTALL_TMP); + assertNotNull(policyURI); + // parse the policy file + boolean ret = SELinuxMMAC.readInstallPolicy(new File(policyURI.getPath())); + assertTrue(ret); + // grab the apk + Uri apkURI = getResourceURI(apkRes, APK_INSTALL_TMP); + assertNotNull(apkURI); + // "install" the apk + PackageParser.Package pkg = parsePackage(apkURI); + assertNotNull(pkg); + assertNotNull(pkg.packageName); + // check for correct passed policy value + boolean passed = SELinuxMMAC.passInstallPolicyChecks(pkg); + assertEquals(expectedPassed, passed); + // check for correct seinfo label + String seinfo = pkg.applicationInfo.seinfo; + if (seinfo == null) + seinfo = "null"; + assertEquals(expectedSeinfo, seinfo); + + // delete policy and apk + MAC_INSTALL_TMP.delete(); + APK_INSTALL_TMP.delete(); + } + + /* + * Requested policy file doesn't exist. + */ + @LargeTest + public void testINSTALL_POLICY_BADPATH() { + boolean ret = SELinuxMMAC.readInstallPolicy(new File("/d/o/e/s/n/t/e/x/i/s/t")); + assertFalse(ret); + } + + /* + * Requested policy file is null object. + */ + @LargeTest + public void testINSTALL_POLICY_NULL() { + boolean ret = SELinuxMMAC.readInstallPolicy(null); + assertFalse(ret); + } + + /* + * No need to test a valid install policy file. All the tests + * below test it implicitly. + */ + + /* + * Signature stanza hits. apk is installed from allow-all. + */ + @LargeTest + public void testSIGNATURE_ALLOWALL_INSTALLED() { + checkInstallMMAC(R.raw.mmac_sig_all, R.raw.signed_platform, + "platform", true); + } + + /* + * Signature stanza hits. apk is installed from whitelist. + */ + @LargeTest + public void testSIGNATURE_WHITELIST_INSTALLED() { + checkInstallMMAC(R.raw.mmac_sig_white, R.raw.signed_platform, + "platform", true); + } + + /* + * Signature stanza hits. apk is installed from blacklist. + */ + @LargeTest + public void testSIGNATURE_BLACKLIST_INSTALLED() { + checkInstallMMAC(R.raw.mmac_sig_black, R.raw.signed_platform, + "platform", true); + } + + /* + * Signature stanza hits. apk is installed. null seinfo tag. + */ + @LargeTest + public void testSIGNATURE_INSTALLED_NULL_SEINFO() { + checkInstallMMAC(R.raw.mmac_sig_null, R.raw.signed_platform, + "null", true); + } + + /* + * Signature stanza hits. apk is denied. + * Package stanza allows. + */ + @LargeTest + public void testSIGNATURE_DENIED_PACKAGE_ALLOWS() { + checkInstallMMAC(R.raw.mmac_sig_deny_pkg_allow, R.raw.signed_platform, + "package", true); + } + + /* + * Signature stanza hits. apk is denied. + * Package stanza then denys. + */ + @LargeTest + public void testSIGNATURE_DENIED_PACKAGE_DENY() { + checkInstallMMAC(R.raw.mmac_sig_deny_pkg_deny, R.raw.signed_platform, + "null", false); + } + + /* + * Signature stanza hits. apk is denied. + * Default stanza allows. + */ + @LargeTest + public void testSIGNATURE_DENIED_DEFAULT_ALLOWS() { + checkInstallMMAC(R.raw.mmac_sig_deny_default_allow, R.raw.signed_platform, + "default", true); + } + + /* + * Signature stanza hits yet denys. Default stanza hits and denys. + */ + @LargeTest + public void testSIGNATURE_DENY_DEFAULT_DENY() { + checkInstallMMAC(R.raw.mmac_sig_deny_default_deny, R.raw.signed_platform, + "null", false); + } + + /* + * Signature stanza hits. apk is denied. + * No other policy present. + */ + @LargeTest + public void testSIGNATURE_DENIED_NOOTHER_POLICY() { + checkInstallMMAC(R.raw.mmac_sig_deny_noother, R.raw.signed_platform, + "null", false); + } + + /* + * Package stanza hits. apk is installed from allow-all. + */ + @LargeTest + public void testPACKAGE_ALLOWALL_INSTALLED() { + checkInstallMMAC(R.raw.mmac_pkg_all, R.raw.signed_platform, + "package", true); + } + + /* + * Package stanza hits. apk is installed from whitelist. + */ + @LargeTest + public void testPACKAGE_WHITELIST_INSTALLED() { + checkInstallMMAC(R.raw.mmac_pkg_white, R.raw.signed_platform, + "package", true); + } + + /* + * Package stanza hits. apk is installed from blacklist. + */ + @LargeTest + public void testPACKAGE_BLACKLIST_INSTALLED() { + checkInstallMMAC(R.raw.mmac_pkg_black, R.raw.signed_platform, + "package", true); + } + + /* + * Package stanza hits. apk is installed. seinfo is null. + */ + @LargeTest + public void testPACKAGE_INSTALLED_NULL_SEINFO() { + checkInstallMMAC(R.raw.mmac_pkg_null_seinfo, R.raw.signed_platform, + "null", true); + } + + /* + * Package stanza hits. apk is denied on whitelist. + */ + @LargeTest + public void testPACKAGE_WHITELIST_DENIED() { + checkInstallMMAC(R.raw.mmac_pkg_deny_white, R.raw.signed_platform, + "null", false); + } + + /* + * Package stanza hits. apk is denied on blacklist. + */ + @LargeTest + public void testPACKAGE_BLACKLIST_DENIED() { + checkInstallMMAC(R.raw.mmac_pkg_deny_black, R.raw.signed_platform, + "null", false); + } + + /* + * Default stanza hits. apk is installed from allowall. + */ + @LargeTest + public void testDEFAULT_ALLOWALL_INSTALLED() { + checkInstallMMAC(R.raw.mmac_default_all, R.raw.signed_platform, + "default", true); + } + + /* + * Default stanza hits. apk is installed from whitelist. + */ + @LargeTest + public void testDEFAULT_WHITELIST_INSTALLED() { + checkInstallMMAC(R.raw.mmac_default_white, R.raw.signed_platform, + "default", true); + } + + /* + * Default stanza hits. apk is installed from blacklist. + */ + @LargeTest + public void testDEFAULT_BLACKLIST_INSTALLED() { + checkInstallMMAC(R.raw.mmac_default_black, R.raw.signed_platform, + "default", true); + } + + /* + * Default stanza hits. apk installed. null seinfo. + */ + @LargeTest + public void testDEFAULT_INSTALLED_NULL_SEINFO() { + checkInstallMMAC(R.raw.mmac_default_null_seinfo, R.raw.signed_platform, + "null", true); + } + + /* + * Default stanza hits. apk is denied on whitelist. + */ + @LargeTest + public void testDEFAULT_WHITELIST_DENIED() { + checkInstallMMAC(R.raw.mmac_default_white_deny, R.raw.signed_platform, + "null", false); + } + + /* + * Default stanza hits. apk is denied on blacklist. + */ + @LargeTest + public void testDEFAULT_BLACKLIST_DENIED() { + checkInstallMMAC(R.raw.mmac_default_black_deny, R.raw.signed_platform, + "null", false); + } + + /* + * No matching entry in policy. + */ + @LargeTest + public void testNO_MATCHING_POLICY() { + checkInstallMMAC(R.raw.mmac_no_match, R.raw.signed_platform, + "null", false); + } + + /* + * Signature catches yet there is a package stanza inside that allows + * based on allow-all. + */ + @LargeTest + public void testPACKAGE_INSIDE_SIG_ALLOW_ALL() { + checkInstallMMAC(R.raw.mmac_inside_pkg_allow_all, R.raw.signed_platform, + "insidepackage", true); + } + + /* + * Signature catches yet there is a package stanza inside that allows + * based on whitelist. + */ + @LargeTest + public void testPACKAGE_INSIDE_SIG_ALLOW_WHITE() { + checkInstallMMAC(R.raw.mmac_inside_pkg_allow_white, R.raw.signed_platform, + "insidepackage", true); + } + + /* + * Signature catches yet there is a package stanza inside that allows + * based on blacklist. + */ + @LargeTest + public void testPACKAGE_INSIDE_SIG_ALLOW_BLACK() { + checkInstallMMAC(R.raw.mmac_inside_pkg_allow_black, R.raw.signed_platform, + "insidepackage", true); + } + + /* + * Signature catches yet there is a package stanza inside that denies + * based on blacklist. Stand alone package stanza then allows. + */ + @LargeTest + public void testPACKAGE_INSIDE_SIG_DENY_PKG_OUT_ALLOWS() { + checkInstallMMAC(R.raw.mmac_inside_pkg_deny_pkg, R.raw.signed_platform, + "package", true); + } + + /* + * Signature catches yet there is a package stanza inside that denies + * based on whitelist. default stanza catches and allows. + */ + @LargeTest + public void testPACKAGE_INSIDE_SIG_DENY_DEFAULT_ALLOWS() { + checkInstallMMAC(R.raw.mmac_inside_pkg_deny_default, R.raw.signed_platform, + "default", true); + } + + /* + * Signature catches yet there is a package stanza inside that denies. + * No other policy catches. app is denied. + */ + @LargeTest + public void testPACKAGE_INSIDE_SIG_DENY_NOOTHER() { + checkInstallMMAC(R.raw.mmac_inside_pkg_deny_noother, R.raw.signed_platform, + "null", false); + } + + /* + * Signature catches yet there is a package stanza inside that allows. + * However, the seingo tag is null. + */ + @LargeTest + public void testPACKAGE_INSIDE_SIG_ALLOWS_NULL_SEINFO() { + checkInstallMMAC(R.raw.mmac_inside_pkg_allow_null_seinfo, R.raw.signed_platform, + "null", true); + } + + /* + * Signature stanza has inner package stanza. Outer sig stanza + * has no rules. Check app signed with same key, diff pkg name, doesn't + * catch on outer signer stanza. Catches on default though. + */ + @LargeTest + public void testPACKAGE_SAME_CERT_DIFF_NAME_SKIPS_OUTER() { + checkInstallMMAC(R.raw.mmac_diff_name_skip_outer, R.raw.signed_platform_2, + "default", true); + } + + /* + * Signature stanza has inner package stanza. Outer sig stanza + * has no rules. Check app catches on inner. + */ + @LargeTest + public void testPACKAGE_INNER_HITS_NO_OUTER_RULES() { + checkInstallMMAC(R.raw.mmac_outer_no_rule_catch_inner, R.raw.signed_platform, + "insidepackage", true); + } + + /* + * Signature stanza has inner package stanza with no seinfo tag. + * Outer sig stanza has no rules but seinfo tag. Check app labeled null. + */ + @LargeTest + public void testPACKAGE_INSIDE_SIG_ALLOWS_NULL_SEINFO_OUTER_SEINFO_MISSED() { + checkInstallMMAC(R.raw.mmac_inner_seinfo_null_outer_seinfo, R.raw.signed_platform, + "null", true); + } + + /* + * Signature stanza has inner package stanza. Outer sig stanza + * has blacklist. Check app signed with same key, diff pkg name, + * denied on outer signer stanza. Catches on default though. + */ + @LargeTest + public void testPACKAGE_SAME_CERT_DIFF_NAME_DENIED_OUTER() { + checkInstallMMAC(R.raw.mmac_diff_name_deny_outer, R.raw.signed_platform_2, + "default", true); + } + + /* + * Signature stanza has inner package stanza. Check that app + * with same package name, diff key, catches on another cert. + */ + @LargeTest + public void testPACKAGE_DIFF_CERT_SAME_NAME() { + checkInstallMMAC(R.raw.mmac_same_name_diff_cert, R.raw.signed_media, + "media", true); + } + + /* + * Default stanza with inner package that hits. Outer not empty. + */ + @LargeTest + public void testPACKAGE_INNER_DEFAULT() { + checkInstallMMAC(R.raw.mmac_default_inner_pkg, R.raw.signed_media, + "insidedefault", true); + } + + /* + * Default stanza with inner package that hits. Outer empty. + */ + @LargeTest + public void testPACKAGE_INNER_DEFAULT_OUTER_EMPTY() { + checkInstallMMAC(R.raw.mmac_default_inner_pkg_out_empty, R.raw.signed_media, + "insidedefault", true); + } + + /* + * Default stanza with inner package that denies. + */ + @LargeTest + public void testPACKAGE_INNER_DEFAULT_DENY() { + checkInstallMMAC(R.raw.mmac_default_inner_pkg_deny, R.raw.signed_media, + "null", false); + } +} -- cgit v1.1