SELinuxPolicyInstallReceiver.java revision 9a492393dfb69050b2a4a8b5205e8d2fc24fcd43
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.util.Base64; 24import android.util.Slog; 25 26import java.io.BufferedInputStream; 27import java.io.File; 28import java.io.FileInputStream; 29import java.io.IOException; 30 31import libcore.io.ErrnoException; 32import libcore.io.IoUtils; 33import libcore.io.Libcore; 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 44 public SELinuxPolicyInstallReceiver() { 45 super("/data/security/bundle", "sepolicy_bundle", "metadata/", "version"); 46 } 47 48 private void backupContexts(File contexts) { 49 new File(contexts, seappContextsPath).renameTo( 50 new File(contexts, seappContextsPath + "_backup")); 51 52 new File(contexts, propertyContextsPath).renameTo( 53 new File(contexts, propertyContextsPath + "_backup")); 54 55 new File(contexts, fileContextsPath).renameTo( 56 new File(contexts, fileContextsPath + "_backup")); 57 58 new File(contexts, sepolicyPath).renameTo( 59 new File(contexts, sepolicyPath + "_backup")); 60 } 61 62 private void copyUpdate(File contexts) { 63 new File(updateDir, seappContextsPath).renameTo(new File(contexts, seappContextsPath)); 64 new File(updateDir, propertyContextsPath).renameTo(new File(contexts, propertyContextsPath)); 65 new File(updateDir, fileContextsPath).renameTo(new File(contexts, fileContextsPath)); 66 new File(updateDir, sepolicyPath).renameTo(new File(contexts, sepolicyPath)); 67 } 68 69 private int readInt(BufferedInputStream reader) throws IOException { 70 int value = 0; 71 for (int i=0; i < 4; i++) { 72 value = (value << 8) | reader.read(); 73 } 74 return value; 75 } 76 77 private int[] readChunkLengths(BufferedInputStream bundle) throws IOException { 78 int[] chunks = new int[4]; 79 chunks[0] = readInt(bundle); 80 chunks[1] = readInt(bundle); 81 chunks[2] = readInt(bundle); 82 chunks[3] = readInt(bundle); 83 return chunks; 84 } 85 86 private void installFile(File destination, BufferedInputStream stream, int length) 87 throws IOException { 88 byte[] chunk = new byte[length]; 89 stream.read(chunk, 0, length); 90 writeUpdate(updateDir, destination, Base64.decode(chunk, Base64.DEFAULT)); 91 } 92 93 private void unpackBundle() throws IOException { 94 BufferedInputStream stream = new BufferedInputStream(new FileInputStream(updateContent)); 95 try { 96 int[] chunkLengths = readChunkLengths(stream); 97 installFile(new File(updateDir, seappContextsPath), stream, chunkLengths[0]); 98 installFile(new File(updateDir, propertyContextsPath), stream, chunkLengths[1]); 99 installFile(new File(updateDir, fileContextsPath), stream, chunkLengths[2]); 100 installFile(new File(updateDir, sepolicyPath), stream, chunkLengths[3]); 101 } finally { 102 IoUtils.closeQuietly(stream); 103 } 104 } 105 106 private void applyUpdate() throws IOException, ErrnoException { 107 Slog.i(TAG, "Applying SELinux policy"); 108 File contexts = new File(updateDir.getParentFile(), "contexts"); 109 File current = new File(updateDir.getParentFile(), "current"); 110 File update = new File(updateDir.getParentFile(), "update"); 111 File tmp = new File(updateDir.getParentFile(), "tmp"); 112 if (current.exists()) { 113 Libcore.os.symlink(updateDir.getPath(), update.getPath()); 114 Libcore.os.rename(update.getPath(), current.getPath()); 115 } else { 116 Libcore.os.symlink(updateDir.getPath(), current.getPath()); 117 } 118 contexts.mkdirs(); 119 backupContexts(contexts); 120 copyUpdate(contexts); 121 Libcore.os.symlink(contexts.getPath(), tmp.getPath()); 122 Libcore.os.rename(tmp.getPath(), current.getPath()); 123 SystemProperties.set("selinux.reload_policy", "1"); 124 } 125 126 @Override 127 protected void postInstall(Context context, Intent intent) { 128 try { 129 unpackBundle(); 130 applyUpdate(); 131 } catch (IllegalArgumentException e) { 132 Slog.e(TAG, "SELinux policy update malformed: ", e); 133 } catch (IOException e) { 134 Slog.e(TAG, "Could not update selinux policy: ", e); 135 } catch (ErrnoException e) { 136 Slog.e(TAG, "Could not update selinux policy: ", e); 137 } 138 } 139} 140