summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jeff Sharkey <jsharkey@android.com> 2016-09-22 11:35:31 -0600
committer Jeff Sharkey <jsharkey@android.com> 2016-09-22 11:35:48 -0600
commit141594b5ee928f99a9dc08b38f70301ef1e08a0b (patch)
tree7926851f89c53be8bb6caabc6bb1629505f90605
parent0676aa18ab81e8d356c5ee14b89dc26a5205ada8 (diff)
Recursively restorecon when SELinux label changes.
PackageManager has been pretty aggressive about asking installd to restorecon over app data when it thinks something might have changed. However, in the vast majority of cases these are no-op requests, and we waste a bunch of time recursively walking all private data, easily costing 60+ seconds on dogfooder devices. This change relies on new installd "create_app_data" behavior that kicks off a recursive restorecon if it detects that the top-level SELinux label on the app private data directory changes. This means that PackageManager no longer needs to track restoreconNeeded state. Test: booted, verified that a label change triggered restorecon Bug: 30768146 Change-Id: I0c8d4018cf8ff888d0ae07a82adc3d61a6002aad
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java46
-rw-r--r--services/core/java/com/android/server/pm/SELinuxMMAC.java80
2 files changed, 9 insertions, 117 deletions
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 51978f22ca5e..2d7b70dda5e2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -19845,8 +19845,6 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
final File ceDir = Environment.getDataUserCeDirectory(volumeUuid, userId);
final File deDir = Environment.getDataUserDeDirectory(volumeUuid, userId);
- boolean restoreconNeeded = false;
-
// First look for stale data that doesn't belong, and check if things
// have changed since we did our last restorecon
if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
@@ -19857,8 +19855,6 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
+ " was still locked; this would have caused massive data loss!");
}
- restoreconNeeded |= SELinuxMMAC.isRestoreconNeeded(ceDir);
-
final File[] files = FileUtils.listFilesOrEmpty(ceDir);
for (File file : files) {
final String packageName = file.getName();
@@ -19876,8 +19872,6 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
}
}
if ((flags & StorageManager.FLAG_STORAGE_DE) != 0) {
- restoreconNeeded |= SELinuxMMAC.isRestoreconNeeded(deDir);
-
final File[] files = FileUtils.listFilesOrEmpty(deDir);
for (File file : files) {
final String packageName = file.getName();
@@ -19912,29 +19906,19 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
}
if (ps.getInstalled(userId)) {
- prepareAppDataLIF(ps.pkg, userId, flags, restoreconNeeded);
+ prepareAppDataLIF(ps.pkg, userId, flags);
if (migrateAppData && maybeMigrateAppDataLIF(ps.pkg, userId)) {
// We may have just shuffled around app data directories, so
// prepare them one more time
- prepareAppDataLIF(ps.pkg, userId, flags, restoreconNeeded);
+ prepareAppDataLIF(ps.pkg, userId, flags);
}
preparedCount++;
}
}
- if (restoreconNeeded) {
- if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
- SELinuxMMAC.setRestoreconDone(ceDir);
- }
- if ((flags & StorageManager.FLAG_STORAGE_DE) != 0) {
- SELinuxMMAC.setRestoreconDone(deDir);
- }
- }
-
- Slog.v(TAG, "reconcileAppsData finished " + preparedCount
- + " packages; restoreconNeeded was " + restoreconNeeded);
+ Slog.v(TAG, "reconcileAppsData finished " + preparedCount + " packages");
}
/**
@@ -19969,9 +19953,8 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
}
if (ps.getInstalled(user.id)) {
- // Whenever an app changes, force a restorecon of its data
// TODO: when user data is locked, mark that we're still dirty
- prepareAppDataLIF(pkg, user.id, flags, true);
+ prepareAppDataLIF(pkg, user.id, flags);
}
}
}
@@ -19984,24 +19967,22 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
* will try recovering system apps by wiping data; third-party app data is
* left intact.
*/
- private void prepareAppDataLIF(PackageParser.Package pkg, int userId, int flags,
- boolean restoreconNeeded) {
+ private void prepareAppDataLIF(PackageParser.Package pkg, int userId, int flags) {
if (pkg == null) {
Slog.wtf(TAG, "Package was null!", new Throwable());
return;
}
- prepareAppDataLeafLIF(pkg, userId, flags, restoreconNeeded);
+ prepareAppDataLeafLIF(pkg, userId, flags);
final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
for (int i = 0; i < childCount; i++) {
- prepareAppDataLeafLIF(pkg.childPackages.get(i), userId, flags, restoreconNeeded);
+ prepareAppDataLeafLIF(pkg.childPackages.get(i), userId, flags);
}
}
- private void prepareAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags,
- boolean restoreconNeeded) {
+ private void prepareAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) {
if (DEBUG_APP_DATA) {
Slog.v(TAG, "prepareAppData for " + pkg.packageName + " u" + userId + " 0x"
- + Integer.toHexString(flags) + (restoreconNeeded ? " restoreconNeeded" : ""));
+ + Integer.toHexString(flags));
}
final String volumeUuid = pkg.volumeUuid;
@@ -20031,15 +20012,6 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
}
}
- if (restoreconNeeded) {
- try {
- mInstaller.restoreconAppData(volumeUuid, packageName, userId, flags, appId,
- app.seinfo);
- } catch (InstallerException e) {
- Slog.e(TAG, "Failed to restorecon for " + packageName + ": " + e);
- }
- }
-
if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
try {
// CE storage is unlocked right now, so read out the inode and
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index 7d4532f18ddd..2176eb164b51 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -19,10 +19,6 @@ package com.android.server.pm;
import android.content.pm.PackageParser;
import android.content.pm.Signature;
import android.os.Environment;
-import android.os.SystemProperties;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.OsConstants;
import android.util.Slog;
import android.util.Xml;
@@ -34,10 +30,7 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
@@ -65,24 +58,10 @@ public final class SELinuxMMAC {
// to synchronize access during policy load and access attempts.
private static List<Policy> sPolicies = new ArrayList<>();
- private static final String PROP_FORCE_RESTORECON = "sys.force_restorecon";
-
- /** Path to version on rootfs */
- private static final File VERSION_FILE = new File("/selinux_version");
-
/** Path to MAC permissions on system image */
private static final File MAC_PERMISSIONS = new File(Environment.getRootDirectory(),
"/etc/security/mac_permissions.xml");
- /** Path to app contexts on rootfs */
- private static final File SEAPP_CONTEXTS = new File("/seapp_contexts");
-
- /** Calculated hash of {@link #SEAPP_CONTEXTS} */
- private static final byte[] SEAPP_CONTEXTS_HASH = returnHash(SEAPP_CONTEXTS);
-
- /** Attribute where {@link #SEAPP_CONTEXTS_HASH} is stored */
- private static final String XATTR_SEAPP_HASH = "user.seapp_hash";
-
// Append privapp to existing seinfo label
private static final String PRIVILEGED_APP_STR = ":privapp";
@@ -313,65 +292,6 @@ public final class SELinuxMMAC {
"seinfo=" + pkg.applicationInfo.seinfo);
}
}
-
- /**
- * Determines if a recursive restorecon on the given package data directory
- * is needed. It does this by comparing the SHA-1 of the seapp_contexts file
- * against the stored hash in an xattr.
- * <p>
- * Note that the xattr isn't in the 'security' namespace, so this should
- * only be run on directories owned by the system.
- *
- * @return Returns true if the restorecon should occur or false otherwise.
- */
- public static boolean isRestoreconNeeded(File file) {
- // To investigate boot timing, allow a property to always force restorecon
- if (SystemProperties.getBoolean(PROP_FORCE_RESTORECON, false)) {
- return true;
- }
-
- try {
- final byte[] buf = Os.getxattr(file.getAbsolutePath(), XATTR_SEAPP_HASH);
- if ((buf.length == 20) && Arrays.equals(SEAPP_CONTEXTS_HASH, buf)) {
- return false;
- }
- } catch (ErrnoException e) {
- if (e.errno != OsConstants.ENODATA) {
- Slog.e(TAG, "Failed to read seapp hash for " + file, e);
- }
- }
-
- return true;
- }
-
- /**
- * Stores the SHA-1 of the seapp_contexts into an xattr.
- * <p>
- * Note that the xattr isn't in the 'security' namespace, so this should
- * only be run on directories owned by the system.
- */
- public static void setRestoreconDone(File file) {
- try {
- Os.setxattr(file.getAbsolutePath(), XATTR_SEAPP_HASH, SEAPP_CONTEXTS_HASH, 0);
- } catch (ErrnoException e) {
- Slog.e(TAG, "Failed to persist seapp hash in " + file, e);
- }
- }
-
- /**
- * 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.
- */
- private static byte[] returnHash(File file) {
- try {
- final byte[] contents = IoUtils.readFileAsByteArray(file.getAbsolutePath());
- return MessageDigest.getInstance("SHA-1").digest(contents);
- } catch (IOException | NoSuchAlgorithmException e) {
- throw new RuntimeException(e);
- }
- }
}
/**