diff options
| author | 2014-03-19 13:20:37 -0700 | |
|---|---|---|
| committer | 2014-03-19 13:20:37 -0700 | |
| commit | e75d340ae5919942d19f57856ae9e3f8bc62e098 (patch) | |
| tree | 45fd9a517bf9ebabd1947f14b11c24ab2db431dc | |
| parent | 9a09a5236529962afbaba9893e5eaf72bd6621b4 (diff) | |
| parent | 5c8e1a6ed4b7e12632c7c82b94e1909ae82b0706 (diff) | |
am 5c8e1a6e: Merge "Allow PMS to restorecon directories under /data."
* commit '5c8e1a6ed4b7e12632c7c82b94e1909ae82b0706':
Allow PMS to restorecon directories under /data.
3 files changed, 108 insertions, 0 deletions
diff --git a/services/java/com/android/server/pm/Installer.java b/services/java/com/android/server/pm/Installer.java index 54acda2a7dba..4b087ccdd8b3 100644 --- a/services/java/com/android/server/pm/Installer.java +++ b/services/java/com/android/server/pm/Installer.java @@ -396,4 +396,8 @@ public final class Installer { return execute(builder.toString()); } + + public boolean restoreconData() { + return (execute("restorecondata") == 0); + } } diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index 1bac1db4bd7b..5dded5773067 100755 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -1486,6 +1486,13 @@ public class PackageManagerService extends IPackageManager.Stub { // can downgrade to reader mSettings.writeLPr(); + if (SELinuxMMAC.shouldRestorecon()) { + Slog.i(TAG, "Relabeling of /data/data and /data/user issued."); + if (mInstaller.restoreconData()) { + SELinuxMMAC.setRestoreconDone(); + } + } + EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY, SystemClock.uptimeMillis()); diff --git a/services/java/com/android/server/pm/SELinuxMMAC.java b/services/java/com/android/server/pm/SELinuxMMAC.java index 1d68afa546e8..91de6d80ca8b 100644 --- a/services/java/com/android/server/pm/SELinuxMMAC.java +++ b/services/java/com/android/server/pm/SELinuxMMAC.java @@ -25,11 +25,16 @@ import android.util.Xml; import com.android.internal.util.XmlUtils; +import libcore.io.IoUtils; + import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.HashMap; @@ -60,6 +65,13 @@ public final class SELinuxMMAC { new File(Environment.getRootDirectory(), "etc/security/mac_permissions.xml"), null}; + // Location of seapp_contexts policy file. + private static final String SEAPP_CONTEXTS_FILE = "/seapp_contexts"; + + // Stores the hash of the last used seapp_contexts file. + private static final String SEAPP_HASH_FILE = + Environment.getDataDirectory().toString() + "/system/seapp_hash"; + // Signature policy stanzas static class Policy { private String seinfo; @@ -391,4 +403,89 @@ public final class SELinuxMMAC { return (sDefaultSeinfo != null); } + + /** + * 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. + * + * @return Returns true if the restorecon should occur or false otherwise. + */ + public static boolean shouldRestorecon() { + // Any error with the seapp_contexts file should be fatal + byte[] currentHash = null; + try { + currentHash = returnHash(SEAPP_CONTEXTS_FILE); + } 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.e(TAG, "Error opening " + SEAPP_HASH_FILE + ". Assuming first boot.", ioe); + } + + return (storedHash == null || !MessageDigest.isEqual(storedHash, currentHash)); + } + + /** + * Stores the SHA-1 of the seapp_contexts to /data/system/seapp_hash. + */ + public static void setRestoreconDone() { + try { + final byte[] currentHash = returnHash(SEAPP_CONTEXTS_FILE); + dumpHash(new File(SEAPP_HASH_FILE), currentHash); + } catch (IOException ioe) { + Slog.e(TAG, "Error with saving hash to " + SEAPP_HASH_FILE, ioe); + } + } + + /** + * Dump the contents of a byte array to a specified file. + * + * @param file The file that receives the byte array content. + * @param content A byte array that will be written to the specified file. + * @throws IOException if any failed I/O operation occured. + * Included is the failure to atomically rename the tmp + * file used in the process. + */ + private static void dumpHash(File file, byte[] content) throws IOException { + 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); + } + } + + /** + * Return the SHA-1 of a file. + * + * @param file The path to the file given as a string. + * @return Returns the SHA-1 of the file as a byte array. + * @throws IOException if any failed I/O operations occured. + */ + private static byte[] returnHash(String file) throws IOException { + try { + final byte[] contents = IoUtils.readFileAsByteArray(file); + return MessageDigest.getInstance("SHA-1").digest(contents); + } catch (NoSuchAlgorithmException nsae) { + throw new RuntimeException(nsae); // impossible + } + } } |