Fields Summary |
---|
private static final String | TAG |
private static final boolean | DEBUG_POLICY |
private static final boolean | DEBUG_POLICY_INSTALL |
private static HashMap | sSigSeinfo |
private static String | sDefaultSeinfo |
private static final String | DATA_VERSION_FILE |
private static final String | BASE_VERSION_FILE |
private static final boolean | USE_OVERRIDE_POLICY |
private static final String | DATA_MAC_PERMISSIONS |
private static final String | BASE_MAC_PERMISSIONS |
private static final String | MAC_PERMISSIONS |
private static final String | DATA_SEAPP_CONTEXTS |
private static final String | BASE_SEAPP_CONTEXTS |
private static final String | SEAPP_CONTEXTS |
private static final String | SEAPP_HASH_FILE |
Methods Summary |
---|
public static boolean | assignSeinfoValue(PackageParser.Package pkg)Labels a package based on an seinfo tag from install policy.
The label is attached to the ApplicationInfo instance of the package.
// We just want one of the signatures to match.
for (Signature s : pkg.mSignatures) {
if (s == null)
continue;
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 true;
}
}
}
// If we have a default seinfo value then great, otherwise
// we set a null object and that is what we started with.
pkg.applicationInfo.seinfo = sDefaultSeinfo;
if (DEBUG_POLICY_INSTALL)
Slog.i(TAG, "package (" + pkg.packageName + ") labeled with seinfo="
+ (sDefaultSeinfo == null ? "null" : sDefaultSeinfo));
return (sDefaultSeinfo != null);
|
private static void | dumpHash(java.io.File file, byte[] content)Dump the contents of a byte array to a specified file.
FileOutputStream fos = null;
File tmp = null;
try {
tmp = File.createTempFile("seapp_hash", ".journal", file.getParentFile());
tmp.setReadable(true);
fos = new FileOutputStream(tmp);
fos.write(content);
fos.getFD().sync();
if (!tmp.renameTo(file)) {
throw new IOException("Failure renaming " + file.getCanonicalPath());
}
} finally {
if (tmp != null) {
tmp.delete();
}
IoUtils.closeQuietly(fos);
}
|
private static void | flushInstallPolicy()
sSigSeinfo.clear();
sDefaultSeinfo = null;
|
private static java.lang.String | parseSeinfo(org.xmlpull.v1.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;
|
public static boolean | readInstallPolicy()
// 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;
try {
policyFile = new FileReader(MAC_PERMISSIONS);
Slog.d(TAG, "Using policy file " + MAC_PERMISSIONS);
XmlPullParser parser = Xml.newPullParser();
parser.setInput(policyFile);
XmlUtils.beginDocument(parser, "policy");
while (true) {
XmlUtils.nextElement(parser);
if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
break;
}
String tagName = parser.getName();
if ("signer".equals(tagName)) {
String cert = parser.getAttributeValue(null, "signature");
if (cert == null) {
Slog.w(TAG, "<signer> without signature at "
+ parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
continue;
}
Signature signature;
try {
signature = new Signature(cert);
} catch (IllegalArgumentException e) {
Slog.w(TAG, "<signer> with bad signature at "
+ parser.getPositionDescription(), e);
XmlUtils.skipCurrentTag(parser);
continue;
}
Policy policy = readPolicyTags(parser);
if (policy.isValid()) {
sigSeinfo.put(signature, policy);
}
} else if ("default".equals(tagName)) {
// 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);
} else {
XmlUtils.skipCurrentTag(parser);
}
}
} catch (XmlPullParserException xpe) {
Slog.w(TAG, "Got exception parsing " + MAC_PERMISSIONS, xpe);
return false;
} catch (IOException ioe) {
Slog.w(TAG, "Got exception parsing " + MAC_PERMISSIONS, ioe);
return false;
} finally {
IoUtils.closeQuietly(policyFile);
}
flushInstallPolicy();
sSigSeinfo = sigSeinfo;
sDefaultSeinfo = defaultSeinfo;
return true;
|
private static com.android.server.pm.SELinuxMMAC$Policy | readPolicyTags(org.xmlpull.v1.XmlPullParser parser)
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 java.lang.String | readSeinfoTag(org.xmlpull.v1.XmlPullParser parser)
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 byte[] | returnHash(java.lang.String file)Return the SHA-1 of a file.
try {
final byte[] contents = IoUtils.readFileAsByteArray(file);
return MessageDigest.getInstance("SHA-1").digest(contents);
} catch (NoSuchAlgorithmException nsae) {
throw new RuntimeException(nsae); // impossible
}
|
public static void | setRestoreconDone()Stores the SHA-1 of the seapp_contexts to /data/system/seapp_hash.
try {
final byte[] currentHash = returnHash(SEAPP_CONTEXTS);
dumpHash(new File(SEAPP_HASH_FILE), currentHash);
} catch (IOException ioe) {
Slog.e(TAG, "Error with saving hash to " + SEAPP_HASH_FILE, ioe);
}
|
public static boolean | shouldRestorecon()Determines if a recursive restorecon on /data/data and /data/user is needed.
It does this by comparing the SHA-1 of the seapp_contexts file against the
stored hash at /data/system/seapp_hash.
// Any error with the seapp_contexts file should be fatal
byte[] currentHash = null;
try {
currentHash = returnHash(SEAPP_CONTEXTS);
} catch (IOException ioe) {
Slog.e(TAG, "Error with hashing seapp_contexts.", ioe);
return false;
}
// Push past any error with the stored hash file
byte[] storedHash = null;
try {
storedHash = IoUtils.readFileAsByteArray(SEAPP_HASH_FILE);
} catch (IOException ioe) {
Slog.w(TAG, "Error opening " + SEAPP_HASH_FILE + ". Assuming first boot.");
}
return (storedHash == null || !MessageDigest.isEqual(storedHash, currentHash));
|
private static boolean | useOverridePolicy()
try {
final String overrideVersion = IoUtils.readFileAsString(DATA_VERSION_FILE);
final String baseVersion = IoUtils.readFileAsString(BASE_VERSION_FILE);
if (overrideVersion.equals(baseVersion)) {
return true;
}
Slog.e(TAG, "Override policy version '" + overrideVersion + "' doesn't match " +
"base version '" + baseVersion + "'. Skipping override policy files.");
} catch (FileNotFoundException fnfe) {
// Override version file doesn't have to exist so silently ignore.
} catch (IOException ioe) {
Slog.w(TAG, "Skipping override policy files.", ioe);
}
return false;
|
private static boolean | validatePackageName(java.lang.String name)General validation routine for package names.
Returns a boolean indicating if the passed string
is a valid android package 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;
|
private static boolean | validateValue(java.lang.String name)General validation routine for tag values.
Returns a boolean indicating if the passed string
contains only letters or underscores.
if (name == null)
return false;
final int N = name.length();
if (N == 0)
return false;
for (int i = 0; i < N; i++) {
final char c = name.charAt(i);
if ((c < 'a" || c > 'z") && (c < 'A" || c > 'Z") && (c != '_")) {
return false;
}
}
return true;
|