* commit '6b8a3a52acf1c2722551f1ea1ce47831f87939cd': Augment SELinuxMMAC functionality.
This commit is contained in:
@@ -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,57 +175,84 @@ 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);
|
||||
// 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);
|
||||
|
||||
// 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 {
|
||||
XmlUtils.skipCurrentTag(parser);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} 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) {
|
||||
Slog.w(TAG, "Got execption parsing ", e);
|
||||
}
|
||||
try {
|
||||
policyFile.close();
|
||||
} 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 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
|
||||
IOException, XmlPullParserException {
|
||||
|
||||
@@ -205,19 +269,57 @@ 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 "
|
||||
+ parser.getPositionDescription());
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user