summaryrefslogtreecommitdiffstats
path: root/services/java/com
diff options
context:
space:
mode:
authorRobert Craig <rpcraig@tycho.ncsc.mil>2013-12-02 10:24:23 -0500
committerRobert Craig <rpcraig@tycho.ncsc.mil>2013-12-06 08:51:20 -0500
commit99a626c2719e1965364fad543101799f527e28ca (patch)
tree1371ff27a0b08401d7f844d837589f16447205ed /services/java/com
parent6e2d0c1d91f644ab50e0c0b7cae4306262a4ca41 (diff)
downloadframeworks_base-99a626c2719e1965364fad543101799f527e28ca.zip
frameworks_base-99a626c2719e1965364fad543101799f527e28ca.tar.gz
frameworks_base-99a626c2719e1965364fad543101799f527e28ca.tar.bz2
Augment SELinuxMMAC functionality.
* No longer support a package name stanza outside of a signature tag. Package names, by themselves, have no security associated with them in Android and thus we should not be allowing or encouraging this type of policy. * Allow for nested package name stanzas inside signature stanzas. There are cases where a finer distinction needs to be made among apps signed with the same cert. New code allows a different seinfo tag to be assigned to the listed package names signed by the parent cert. When a determination needs to be made concerning seinfo assignments, the inner seinfo tag takes precedence over the outer seinfo labels which are assigned to just the signature. * Temp structures are now used to parse new policy files until the entire xml file is parsed and deemed correct, at which time the temp structures are copied over to the permanent class structures. This ensures that any structural errors with the policy will not result in partial loads. * Valid stanzas look like the following with the inner package piece being optional. <signer signature=""> <seinfo value=""/> <package name=""> <seinfo value=""/> </package> <signer> <default> <seinfo value=""/> </default> Change-Id: Ia204d71211776dcf9b2dcc86ad6d77c4ad39dc25
Diffstat (limited to 'services/java/com')
-rw-r--r--services/java/com/android/server/pm/SELinuxMMAC.java248
1 files changed, 174 insertions, 74 deletions
diff --git a/services/java/com/android/server/pm/SELinuxMMAC.java b/services/java/com/android/server/pm/SELinuxMMAC.java
index 04f43d9..1d68afa 100644
--- a/services/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/java/com/android/server/pm/SELinuxMMAC.java
@@ -48,12 +48,11 @@ public final class SELinuxMMAC {
private static final boolean DEBUG_POLICY_INSTALL = DEBUG_POLICY || false;
// Signature seinfo values read from policy.
- private static final HashMap<Signature, String> sSigSeinfo =
- new HashMap<Signature, String>();
+ private static HashMap<Signature, Policy> sSigSeinfo =
+ new HashMap<Signature, Policy>();
- // Package name seinfo values read from policy.
- private static final HashMap<String, String> sPackageSeinfo =
- new HashMap<String, String>();
+ // Default seinfo read from policy.
+ private static String sDefaultSeinfo = null;
// Locations of potential install policy files.
private static final File[] INSTALL_POLICY_FILE = {
@@ -61,9 +60,45 @@ public final class SELinuxMMAC {
new File(Environment.getRootDirectory(), "etc/security/mac_permissions.xml"),
null};
+ // Signature policy stanzas
+ static class Policy {
+ private String seinfo;
+ private final HashMap<String, String> pkgMap;
+
+ Policy() {
+ seinfo = null;
+ pkgMap = new HashMap<String, String>();
+ }
+
+ void putSeinfo(String seinfoValue) {
+ seinfo = seinfoValue;
+ }
+
+ void putPkg(String pkg, String seinfoValue) {
+ pkgMap.put(pkg, seinfoValue);
+ }
+
+ // Valid policy stanza means there exists a global
+ // seinfo value or at least one package policy.
+ boolean isValid() {
+ return (seinfo != null) || (!pkgMap.isEmpty());
+ }
+
+ String checkPolicy(String pkgName) {
+ // Check for package name seinfo value first.
+ String seinfoValue = pkgMap.get(pkgName);
+ if (seinfoValue != null) {
+ return seinfoValue;
+ }
+
+ // Return the global seinfo value.
+ return seinfo;
+ }
+ }
+
private static void flushInstallPolicy() {
sSigSeinfo.clear();
- sPackageSeinfo.clear();
+ sDefaultSeinfo = null;
}
/**
@@ -87,6 +122,10 @@ public final class SELinuxMMAC {
}
private static boolean readInstallPolicy(File[] policyFiles) {
+ // Temp structures to hold the rules while we parse the xml file.
+ // We add all the rules together once we know there's no structural problems.
+ HashMap<Signature, Policy> sigSeinfo = new HashMap<Signature, Policy>();
+ String defaultSeinfo = null;
FileReader policyFile = null;
int i = 0;
@@ -107,8 +146,6 @@ public final class SELinuxMMAC {
Slog.d(TAG, "Using install policy file " + policyFiles[i].getPath());
- flushInstallPolicy();
-
try {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(policyFile);
@@ -138,63 +175,49 @@ public final class SELinuxMMAC {
XmlUtils.skipCurrentTag(parser);
continue;
}
- String seinfo = readSeinfoTag(parser);
- if (seinfo != null) {
- if (DEBUG_POLICY_INSTALL)
- Slog.i(TAG, "<signer> tag: (" + cert + ") assigned seinfo="
- + seinfo);
-
- sSigSeinfo.put(signature, seinfo);
+ Policy policy = readPolicyTags(parser);
+ if (policy.isValid()) {
+ sigSeinfo.put(signature, policy);
}
} else if ("default".equals(tagName)) {
- String seinfo = readSeinfoTag(parser);
- if (seinfo != null) {
- if (DEBUG_POLICY_INSTALL)
- Slog.i(TAG, "<default> tag assigned seinfo=" + seinfo);
-
- // The 'null' signature is the default seinfo value
- sSigSeinfo.put(null, seinfo);
- }
- } 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;
- }
- String seinfo = readSeinfoTag(parser);
- if (seinfo != null) {
- if (DEBUG_POLICY_INSTALL)
- Slog.i(TAG, "<package> tag: (" + pkgName +
- ") assigned seinfo=" + seinfo);
+ // Value is null if default tag is absent or seinfo tag is malformed.
+ defaultSeinfo = readSeinfoTag(parser);
+ if (DEBUG_POLICY_INSTALL)
+ Slog.i(TAG, "<default> tag assigned seinfo=" + defaultSeinfo);
- sPackageSeinfo.put(pkgName, seinfo);
- }
} 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();
+ // An error outside of a stanza means a structural problem
+ // with the xml file. So ignore it.
+ Slog.w(TAG, "Got exception parsing ", e);
+ return false;
} catch (IOException e) {
- //omit
+ Slog.w(TAG, "Got exception parsing ", e);
+ return false;
+ } finally {
+ try {
+ policyFile.close();
+ } catch (IOException e) {
+ //omit
+ }
}
+
+ flushInstallPolicy();
+ sSigSeinfo = sigSeinfo;
+ sDefaultSeinfo = defaultSeinfo;
+
return true;
}
- private static String readSeinfoTag(XmlPullParser parser) throws
+ private static Policy readPolicyTags(XmlPullParser parser) throws
IOException, XmlPullParserException {
int type;
int outerDepth = parser.getDepth();
- String seinfo = null;
+ Policy policy = new Policy();
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG
|| parser.getDepth() > outerDepth)) {
@@ -205,19 +228,98 @@ public final class SELinuxMMAC {
String tagName = parser.getName();
if ("seinfo".equals(tagName)) {
- String seinfoValue = parser.getAttributeValue(null, "value");
- if (validateValue(seinfoValue)) {
- seinfo = seinfoValue;
- } else {
- Slog.w(TAG, "<seinfo> without valid value at "
+ String seinfo = parseSeinfo(parser);
+ if (seinfo != null) {
+ policy.putSeinfo(seinfo);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ } else if ("package".equals(tagName)) {
+ String pkg = parser.getAttributeValue(null, "name");
+ if (!validatePackageName(pkg)) {
+ Slog.w(TAG, "<package> without valid name at "
+ parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+
+ String seinfo = readSeinfoTag(parser);
+ if (seinfo != null) {
+ policy.putPkg(pkg, seinfo);
}
+ } else {
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ return policy;
+ }
+
+ private static String readSeinfoTag(XmlPullParser parser) throws
+ IOException, XmlPullParserException {
+
+ int type;
+ int outerDepth = parser.getDepth();
+ 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)) {
+ seinfo = parseSeinfo(parser);
}
XmlUtils.skipCurrentTag(parser);
}
return seinfo;
}
+ private static String parseSeinfo(XmlPullParser parser) {
+
+ String seinfoValue = parser.getAttributeValue(null, "value");
+ if (!validateValue(seinfoValue)) {
+ Slog.w(TAG, "<seinfo> without valid value at "
+ + parser.getPositionDescription());
+ seinfoValue = null;
+ }
+ return seinfoValue;
+ }
+
+ /**
+ * General validation routine for package names.
+ * Returns a boolean indicating if the passed string
+ * is a valid android package name.
+ */
+ private static boolean validatePackageName(String name) {
+ if (name == null)
+ return false;
+
+ final int N = name.length();
+ boolean hasSep = false;
+ boolean front = true;
+ for (int i=0; i<N; i++) {
+ final char c = name.charAt(i);
+ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
+ front = false;
+ continue;
+ }
+ if (!front) {
+ if ((c >= '0' && c <= '9') || c == '_') {
+ continue;
+ }
+ }
+ if (c == '.') {
+ hasSep = true;
+ front = true;
+ continue;
+ }
+ return false;
+ }
+ return hasSep;
+ }
+
/**
* General validation routine for tag values.
* Returns a boolean indicating if the passed string
@@ -245,10 +347,11 @@ public final class SELinuxMMAC {
* The label is attached to the ApplicationInfo instance of the package.
* @param PackageParser.Package object representing the package
* to labeled.
- * @return String holding the value of the seinfo label that was assigned.
- * Value may be null which indicates no seinfo label was assigned.
+ * @return boolean which determines whether a non null seinfo label
+ * was assigned to the package. A null value simply meaning that
+ * no policy matched.
*/
- public static void assignSeinfoValue(PackageParser.Package pkg) {
+ public static boolean assignSeinfoValue(PackageParser.Package pkg) {
/*
* Non system installed apps should be treated the same. This
@@ -264,31 +367,28 @@ public final class SELinuxMMAC {
if (s == null)
continue;
- if (sSigSeinfo.containsKey(s)) {
- String seinfo = pkg.applicationInfo.seinfo = sSigSeinfo.get(s);
- if (DEBUG_POLICY_INSTALL)
- Slog.i(TAG, "package (" + pkg.packageName +
- ") labeled with seinfo=" + seinfo);
+ Policy policy = sSigSeinfo.get(s);
+ if (policy != null) {
+ String seinfo = policy.checkPolicy(pkg.packageName);
+ if (seinfo != null) {
+ pkg.applicationInfo.seinfo = seinfo;
+ if (DEBUG_POLICY_INSTALL)
+ Slog.i(TAG, "package (" + pkg.packageName +
+ ") labeled with seinfo=" + seinfo);
- return;
+ return true;
+ }
}
}
-
- // Check for seinfo labeled by package.
- if (sPackageSeinfo.containsKey(pkg.packageName)) {
- String seinfo = pkg.applicationInfo.seinfo = sPackageSeinfo.get(pkg.packageName);
- if (DEBUG_POLICY_INSTALL)
- Slog.i(TAG, "package (" + pkg.packageName +
- ") labeled with seinfo=" + seinfo);
- return;
- }
}
// If we have a default seinfo value then great, otherwise
// we set a null object and that is what we started with.
- String seinfo = pkg.applicationInfo.seinfo = sSigSeinfo.get(null);
+ pkg.applicationInfo.seinfo = sDefaultSeinfo;
if (DEBUG_POLICY_INSTALL)
- Slog.i(TAG, "package (" + pkg.packageName +
- ") labeled with seinfo=" + (seinfo == null ? "null" : seinfo));
+ Slog.i(TAG, "package (" + pkg.packageName + ") labeled with seinfo="
+ + (sDefaultSeinfo == null ? "null" : sDefaultSeinfo));
+
+ return (sDefaultSeinfo != null);
}
}