SELinuxPolicyInstallReceiver.java revision 332f35813e9860b8469b0f804f2b576daa0c823f
1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server.updates; 18 19import android.content.Context; 20import android.content.Intent; 21import android.os.SystemProperties; 22import android.provider.Settings; 23import android.system.ErrnoException; 24import android.system.Os; 25import android.util.Base64; 26import android.util.Slog; 27 28import java.io.BufferedInputStream; 29import java.io.File; 30import java.io.FileInputStream; 31import java.io.IOException; 32 33import libcore.io.IoUtils; 34 35public class SELinuxPolicyInstallReceiver extends ConfigUpdateInstallReceiver { 36 37 private static final String TAG = "SELinuxPolicyInstallReceiver"; 38 39 private static final String sepolicyPath = "sepolicy"; 40 private static final String fileContextsPath = "file_contexts"; 41 private static final String propertyContextsPath = "property_contexts"; 42 private static final String seappContextsPath = "seapp_contexts"; 43 private static final String versionPath = "selinux_version"; 44 private static final String macPermissionsPath = "mac_permissions.xml"; 45 46 public SELinuxPolicyInstallReceiver() { 47 super("/data/security/bundle", "sepolicy_bundle", "metadata/", "version"); 48 } 49 50 private void backupContexts(File contexts) { 51 new File(contexts, versionPath).renameTo( 52 new File(contexts, versionPath + "_backup")); 53 54 new File(contexts, macPermissionsPath).renameTo( 55 new File(contexts, macPermissionsPath + "_backup")); 56 57 new File(contexts, seappContextsPath).renameTo( 58 new File(contexts, seappContextsPath + "_backup")); 59 60 new File(contexts, propertyContextsPath).renameTo( 61 new File(contexts, propertyContextsPath + "_backup")); 62 63 new File(contexts, fileContextsPath).renameTo( 64 new File(contexts, fileContextsPath + "_backup")); 65 66 new File(contexts, sepolicyPath).renameTo( 67 new File(contexts, sepolicyPath + "_backup")); 68 } 69 70 private void copyUpdate(File contexts) { 71 new File(updateDir, versionPath).renameTo(new File(contexts, versionPath)); 72 new File(updateDir, macPermissionsPath).renameTo(new File(contexts, macPermissionsPath)); 73 new File(updateDir, seappContextsPath).renameTo(new File(contexts, seappContextsPath)); 74 new File(updateDir, propertyContextsPath).renameTo(new File(contexts, propertyContextsPath)); 75 new File(updateDir, fileContextsPath).renameTo(new File(contexts, fileContextsPath)); 76 new File(updateDir, sepolicyPath).renameTo(new File(contexts, sepolicyPath)); 77 } 78 79 private int readInt(BufferedInputStream reader) throws IOException { 80 int value = 0; 81 for (int i=0; i < 4; i++) { 82 value = (value << 8) | reader.read(); 83 } 84 return value; 85 } 86 87 private int[] readChunkLengths(BufferedInputStream bundle) throws IOException { 88 int[] chunks = new int[6]; 89 chunks[0] = readInt(bundle); 90 chunks[1] = readInt(bundle); 91 chunks[2] = readInt(bundle); 92 chunks[3] = readInt(bundle); 93 chunks[4] = readInt(bundle); 94 chunks[5] = readInt(bundle); 95 return chunks; 96 } 97 98 private void installFile(File destination, BufferedInputStream stream, int length) 99 throws IOException { 100 byte[] chunk = new byte[length]; 101 stream.read(chunk, 0, length); 102 writeUpdate(updateDir, destination, Base64.decode(chunk, Base64.DEFAULT)); 103 } 104 105 private void unpackBundle() throws IOException { 106 BufferedInputStream stream = new BufferedInputStream(new FileInputStream(updateContent)); 107 try { 108 int[] chunkLengths = readChunkLengths(stream); 109 installFile(new File(updateDir, versionPath), stream, chunkLengths[0]); 110 installFile(new File(updateDir, macPermissionsPath), stream, chunkLengths[1]); 111 installFile(new File(updateDir, seappContextsPath), stream, chunkLengths[2]); 112 installFile(new File(updateDir, propertyContextsPath), stream, chunkLengths[3]); 113 installFile(new File(updateDir, fileContextsPath), stream, chunkLengths[4]); 114 installFile(new File(updateDir, sepolicyPath), stream, chunkLengths[5]); 115 } finally { 116 IoUtils.closeQuietly(stream); 117 } 118 } 119 120 private void applyUpdate() throws IOException, ErrnoException { 121 Slog.i(TAG, "Applying SELinux policy"); 122 File contexts = new File(updateDir.getParentFile(), "contexts"); 123 File current = new File(updateDir.getParentFile(), "current"); 124 File update = new File(updateDir.getParentFile(), "update"); 125 File tmp = new File(updateDir.getParentFile(), "tmp"); 126 if (current.exists()) { 127 Os.symlink(updateDir.getPath(), update.getPath()); 128 Os.rename(update.getPath(), current.getPath()); 129 } else { 130 Os.symlink(updateDir.getPath(), current.getPath()); 131 } 132 contexts.mkdirs(); 133 backupContexts(contexts); 134 copyUpdate(contexts); 135 Os.symlink(contexts.getPath(), tmp.getPath()); 136 Os.rename(tmp.getPath(), current.getPath()); 137 SystemProperties.set("selinux.reload_policy", "1"); 138 } 139 140 @Override 141 protected void postInstall(Context context, Intent intent) { 142 try { 143 unpackBundle(); 144 applyUpdate(); 145 } catch (IllegalArgumentException e) { 146 Slog.e(TAG, "SELinux policy update malformed: ", e); 147 } catch (IOException e) { 148 Slog.e(TAG, "Could not update selinux policy: ", e); 149 } catch (ErrnoException e) { 150 Slog.e(TAG, "Could not update selinux policy: ", e); 151 } 152 } 153} 154