Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8fb7520a authored by Jeff Sharkey's avatar Jeff Sharkey Committed by android-build-merger
Browse files

Recursively restorecon when SELinux label changes.

am: 7e2bb3e6

Change-Id: I964b2173f556077f2718abd5b30e156e1a9e6639
parents 4c9be8f7 7e2bb3e6
Loading
Loading
Loading
Loading
+9 −37
Original line number Diff line number Diff line
@@ -19781,8 +19781,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) {
@@ -19793,8 +19791,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();
@@ -19812,8 +19808,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();
@@ -19848,29 +19842,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 (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");
    }
    /**
@@ -19905,9 +19889,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);
            }
        }
    }
@@ -19920,24 +19903,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;
@@ -19967,15 +19948,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
+0 −81
Original line number Diff line number Diff line
@@ -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,66 +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 = new byte[20];
            final int len = Os.getxattr(file.getAbsolutePath(), XATTR_SEAPP_HASH, buf);
            if ((len == 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);
        }
    }
}

/**