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

Commit 2d84aff4 authored by Nick Kralevich's avatar Nick Kralevich Committed by Android Git Automerger
Browse files

am e75d340a: am 5c8e1a6e: Merge "Allow PMS to restorecon directories under /data."

* commit 'e75d340a':
  Allow PMS to restorecon directories under /data.
parents 1c394559 e75d340a
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -396,4 +396,8 @@ public final class Installer {

        return execute(builder.toString());
    }

    public boolean restoreconData() {
        return (execute("restorecondata") == 0);
    }
}
+7 −0
Original line number Diff line number Diff line
@@ -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());

+97 −0
Original line number Diff line number Diff line
@@ -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
        }
    }
}