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

* commit '5c8e1a6ed4b7e12632c7c82b94e1909ae82b0706':
  Allow PMS to restorecon directories under /data.
This commit is contained in:
Nick Kralevich
2014-03-19 13:20:37 -07:00
committed by Android Git Automerger
3 changed files with 108 additions and 0 deletions

View File

@@ -396,4 +396,8 @@ public final class Installer {
return execute(builder.toString());
}
public boolean restoreconData() {
return (execute("restorecondata") == 0);
}
}

View File

@@ -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());

View File

@@ -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
}
}
}