Merge "Augment SELinuxMMAC functionality."

This commit is contained in:
Nick Kralevich
2013-12-06 16:13:58 +00:00
committed by Gerrit Code Review

View File

@@ -48,12 +48,11 @@ public final class SELinuxMMAC {
private static final boolean DEBUG_POLICY_INSTALL = DEBUG_POLICY || false; private static final boolean DEBUG_POLICY_INSTALL = DEBUG_POLICY || false;
// Signature seinfo values read from policy. // Signature seinfo values read from policy.
private static final HashMap<Signature, String> sSigSeinfo = private static HashMap<Signature, Policy> sSigSeinfo =
new HashMap<Signature, String>(); new HashMap<Signature, Policy>();
// Package name seinfo values read from policy. // Default seinfo read from policy.
private static final HashMap<String, String> sPackageSeinfo = private static String sDefaultSeinfo = null;
new HashMap<String, String>();
// Locations of potential install policy files. // Locations of potential install policy files.
private static final File[] INSTALL_POLICY_FILE = { private static final File[] INSTALL_POLICY_FILE = {
@@ -61,9 +60,45 @@ public final class SELinuxMMAC {
new File(Environment.getRootDirectory(), "etc/security/mac_permissions.xml"), new File(Environment.getRootDirectory(), "etc/security/mac_permissions.xml"),
null}; 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() { private static void flushInstallPolicy() {
sSigSeinfo.clear(); sSigSeinfo.clear();
sPackageSeinfo.clear(); sDefaultSeinfo = null;
} }
/** /**
@@ -87,6 +122,10 @@ public final class SELinuxMMAC {
} }
private static boolean readInstallPolicy(File[] policyFiles) { 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; FileReader policyFile = null;
int i = 0; int i = 0;
@@ -107,8 +146,6 @@ public final class SELinuxMMAC {
Slog.d(TAG, "Using install policy file " + policyFiles[i].getPath()); Slog.d(TAG, "Using install policy file " + policyFiles[i].getPath());
flushInstallPolicy();
try { try {
XmlPullParser parser = Xml.newPullParser(); XmlPullParser parser = Xml.newPullParser();
parser.setInput(policyFile); parser.setInput(policyFile);
@@ -138,57 +175,84 @@ public final class SELinuxMMAC {
XmlUtils.skipCurrentTag(parser); XmlUtils.skipCurrentTag(parser);
continue; continue;
} }
String seinfo = readSeinfoTag(parser); Policy policy = readPolicyTags(parser);
if (seinfo != null) { if (policy.isValid()) {
if (DEBUG_POLICY_INSTALL) sigSeinfo.put(signature, policy);
Slog.i(TAG, "<signer> tag: (" + cert + ") assigned seinfo="
+ seinfo);
sSigSeinfo.put(signature, seinfo);
} }
} else if ("default".equals(tagName)) { } else if ("default".equals(tagName)) {
String seinfo = readSeinfoTag(parser); // Value is null if default tag is absent or seinfo tag is malformed.
if (seinfo != null) { defaultSeinfo = readSeinfoTag(parser);
if (DEBUG_POLICY_INSTALL) if (DEBUG_POLICY_INSTALL)
Slog.i(TAG, "<default> tag assigned seinfo=" + seinfo); Slog.i(TAG, "<default> tag assigned seinfo=" + defaultSeinfo);
// 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);
sPackageSeinfo.put(pkgName, seinfo);
}
} else { } else {
XmlUtils.skipCurrentTag(parser); XmlUtils.skipCurrentTag(parser);
continue;
} }
} }
} catch (XmlPullParserException e) { } catch (XmlPullParserException e) {
Slog.w(TAG, "Got execption parsing ", e); // 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) { } catch (IOException e) {
Slog.w(TAG, "Got execption parsing ", e); Slog.w(TAG, "Got exception parsing ", e);
} return false;
} finally {
try { try {
policyFile.close(); policyFile.close();
} catch (IOException e) { } catch (IOException e) {
//omit //omit
} }
}
flushInstallPolicy();
sSigSeinfo = sigSeinfo;
sDefaultSeinfo = defaultSeinfo;
return true; return true;
} }
private static Policy readPolicyTags(XmlPullParser parser) throws
IOException, XmlPullParserException {
int type;
int outerDepth = parser.getDepth();
Policy policy = new Policy();
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 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 private static String readSeinfoTag(XmlPullParser parser) throws
IOException, XmlPullParserException { IOException, XmlPullParserException {
@@ -205,19 +269,57 @@ public final class SELinuxMMAC {
String tagName = parser.getName(); String tagName = parser.getName();
if ("seinfo".equals(tagName)) { if ("seinfo".equals(tagName)) {
String seinfoValue = parser.getAttributeValue(null, "value"); seinfo = parseSeinfo(parser);
if (validateValue(seinfoValue)) {
seinfo = seinfoValue;
} else {
Slog.w(TAG, "<seinfo> without valid value at "
+ parser.getPositionDescription());
}
} }
XmlUtils.skipCurrentTag(parser); XmlUtils.skipCurrentTag(parser);
} }
return seinfo; 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. * General validation routine for tag values.
* Returns a boolean indicating if the passed string * 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. * The label is attached to the ApplicationInfo instance of the package.
* @param PackageParser.Package object representing the package * @param PackageParser.Package object representing the package
* to labeled. * to labeled.
* @return String holding the value of the seinfo label that was assigned. * @return boolean which determines whether a non null seinfo label
* Value may be null which indicates no seinfo label was assigned. * 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 * Non system installed apps should be treated the same. This
@@ -264,31 +367,28 @@ public final class SELinuxMMAC {
if (s == null) if (s == null)
continue; continue;
if (sSigSeinfo.containsKey(s)) { Policy policy = sSigSeinfo.get(s);
String seinfo = pkg.applicationInfo.seinfo = sSigSeinfo.get(s); if (policy != null) {
String seinfo = policy.checkPolicy(pkg.packageName);
if (seinfo != null) {
pkg.applicationInfo.seinfo = seinfo;
if (DEBUG_POLICY_INSTALL) if (DEBUG_POLICY_INSTALL)
Slog.i(TAG, "package (" + pkg.packageName + Slog.i(TAG, "package (" + pkg.packageName +
") labeled with seinfo=" + seinfo); ") 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 // If we have a default seinfo value then great, otherwise
// we set a null object and that is what we started with. // 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) if (DEBUG_POLICY_INSTALL)
Slog.i(TAG, "package (" + pkg.packageName + Slog.i(TAG, "package (" + pkg.packageName + ") labeled with seinfo="
") labeled with seinfo=" + (seinfo == null ? "null" : seinfo)); + (sDefaultSeinfo == null ? "null" : sDefaultSeinfo));
return (sDefaultSeinfo != null);
} }
} }