diff options
author | Geremy Condra <gcondra@google.com> | 2013-04-06 14:01:40 -0700 |
---|---|---|
committer | repo sync <gcondra@google.com> | 2013-04-15 14:56:58 -0700 |
commit | f33575b05b1e14e448c7496f3da1ac68193068c0 (patch) | |
tree | dfbeda8554e3abb7d2327cdad554b918427ef9ca /services | |
parent | 30c990c361291ad578ef4ffe4a4dd0fd6080797b (diff) | |
download | frameworks_base-f33575b05b1e14e448c7496f3da1ac68193068c0.zip frameworks_base-f33575b05b1e14e448c7496f3da1ac68193068c0.tar.gz frameworks_base-f33575b05b1e14e448c7496f3da1ac68193068c0.tar.bz2 |
Add logic to handle changes to file_contexts during update.
Bug: 8116902
(cherry picked from commit a2dffda3b3bc4f0bccb175ef4569e45a221d0eb2)
Change-Id: I57c21681d5f94e00d0214fb520ea62af4ea5b025
Diffstat (limited to 'services')
-rw-r--r-- | services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java | 8 | ||||
-rw-r--r-- | services/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java | 113 |
2 files changed, 110 insertions, 11 deletions
diff --git a/services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java b/services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java index c94f7c1..9601e9a 100644 --- a/services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java +++ b/services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java @@ -56,9 +56,9 @@ public class ConfigUpdateInstallReceiver extends BroadcastReceiver { private static final String UPDATE_CERTIFICATE_KEY = "config_update_certificate"; - private final File updateDir; - private final File updateContent; - private final File updateVersion; + protected final File updateDir; + protected final File updateContent; + protected final File updateVersion; public ConfigUpdateInstallReceiver(String updateDir, String updateContentPath, String updateMetadataPath, String updateVersionPath) { @@ -222,7 +222,7 @@ public class ConfigUpdateInstallReceiver extends BroadcastReceiver { return signer.verify(Base64.decode(signature.getBytes(), Base64.DEFAULT)); } - private void writeUpdate(File dir, File file, byte[] content) throws IOException { + protected void writeUpdate(File dir, File file, byte[] content) throws IOException { FileOutputStream out = null; File tmp = null; try { diff --git a/services/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java b/services/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java index 748849e..e8337f6 100644 --- a/services/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java +++ b/services/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java @@ -18,28 +18,127 @@ package com.android.server.updates; import android.content.Context; import android.content.Intent; +import android.os.FileUtils; import android.os.SELinux; +import android.os.SystemProperties; import android.provider.Settings; import android.util.Base64; import android.util.Slog; +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; import java.io.IOException; +import libcore.io.ErrnoException; +import libcore.io.IoUtils; +import libcore.io.Libcore; + public class SELinuxPolicyInstallReceiver extends ConfigUpdateInstallReceiver { + private static final String TAG = "SELinuxPolicyInstallReceiver"; + + private static final String sepolicyPath = "sepolicy"; + private static final String fileContextsPath = "file_contexts"; + private static final String propertyContextsPath = "property_contexts"; + private static final String seappContextsPath = "seapp_contexts"; + public SELinuxPolicyInstallReceiver() { - super("/data/security/", "sepolicy", "metadata/", "version"); + super("/data/security/bundle", "sepolicy_bundle", "metadata/", "version"); } - @Override - protected void install(byte[] encodedContent, int version) throws IOException { - super.install(Base64.decode(encodedContent, Base64.DEFAULT), version); + private void backupContexts(File contexts) { + new File(contexts, seappContextsPath).renameTo( + new File(contexts, seappContextsPath + "_backup")); + + new File(contexts, propertyContextsPath).renameTo( + new File(contexts, propertyContextsPath + "_backup")); + + new File(contexts, fileContextsPath).renameTo( + new File(contexts, fileContextsPath + "_backup")); + + new File(contexts, sepolicyPath).renameTo( + new File(contexts, sepolicyPath + "_backup")); + } + + private void copyUpdate(File contexts) { + new File(updateDir, seappContextsPath).renameTo(new File(contexts, seappContextsPath)); + new File(updateDir, propertyContextsPath).renameTo(new File(contexts, propertyContextsPath)); + new File(updateDir, fileContextsPath).renameTo(new File(contexts, fileContextsPath)); + new File(updateDir, sepolicyPath).renameTo(new File(contexts, sepolicyPath)); + } + + private int readInt(BufferedInputStream reader) throws IOException { + int value = 0; + for (int i=0; i < 4; i++) { + value = (value << 8) | reader.read(); + } + return value; + } + + private int[] readChunkLengths(BufferedInputStream bundle) throws IOException { + int[] chunks = new int[4]; + chunks[0] = readInt(bundle); + chunks[1] = readInt(bundle); + chunks[2] = readInt(bundle); + chunks[3] = readInt(bundle); + return chunks; + } + + private void installFile(File destination, BufferedInputStream stream, int length) + throws IOException { + byte[] chunk = new byte[length]; + stream.read(chunk, 0, length); + writeUpdate(updateDir, destination, Base64.decode(chunk, Base64.DEFAULT)); + } + + private void unpackBundle() throws IOException { + BufferedInputStream stream = new BufferedInputStream(new FileInputStream(updateContent)); + int[] chunkLengths = readChunkLengths(stream); + installFile(new File(updateDir, seappContextsPath), stream, chunkLengths[0]); + installFile(new File(updateDir, propertyContextsPath), stream, chunkLengths[1]); + installFile(new File(updateDir, fileContextsPath), stream, chunkLengths[2]); + installFile(new File(updateDir, sepolicyPath), stream, chunkLengths[3]); + } + + private void applyUpdate() throws IOException, ErrnoException { + Slog.i(TAG, "Applying SELinux policy"); + File contexts = new File(updateDir.getParentFile(), "contexts"); + File current = new File(updateDir.getParentFile(), "current"); + File update = new File(updateDir.getParentFile(), "update"); + File tmp = new File(updateDir.getParentFile(), "tmp"); + if (current.exists()) { + Libcore.os.symlink(updateDir.getPath(), update.getPath()); + Libcore.os.rename(update.getPath(), current.getPath()); + } else { + Libcore.os.symlink(updateDir.getPath(), current.getPath()); + } + contexts.mkdirs(); + backupContexts(contexts); + copyUpdate(contexts); + Libcore.os.symlink(contexts.getPath(), tmp.getPath()); + Libcore.os.rename(tmp.getPath(), current.getPath()); + SystemProperties.set("selinux.reload_policy", "1"); + } + + private void setEnforcingMode(Context context) { + boolean mode = Settings.Global.getInt(context.getContentResolver(), + Settings.Global.SELINUX_STATUS, 0) == 1; + SELinux.setSELinuxEnforce(mode); } @Override protected void postInstall(Context context, Intent intent) { - boolean mode = Settings.Global.getInt(context.getContentResolver(), - Settings.Global.SELINUX_STATUS, 0) == 1; - SELinux.setSELinuxEnforce(mode); + try { + unpackBundle(); + applyUpdate(); + setEnforcingMode(context); + } catch (IllegalArgumentException e) { + Slog.e(TAG, "SELinux policy update malformed: ", e); + } catch (IOException e) { + Slog.e(TAG, "Could not update selinux policy: ", e); + } catch (ErrnoException e) { + Slog.e(TAG, "Could not update selinux policy: ", e); + } } } |