• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.server.updates;
18 
19 import android.content.Context;
20 import android.content.Intent;
21 import android.os.SystemProperties;
22 import android.system.ErrnoException;
23 import android.system.Os;
24 import android.util.Base64;
25 import android.util.Slog;
26 
27 import java.io.BufferedInputStream;
28 import java.io.File;
29 import java.io.FileInputStream;
30 import java.io.IOException;
31 
32 import libcore.io.IoUtils;
33 
34 public class SELinuxPolicyInstallReceiver extends ConfigUpdateInstallReceiver {
35 
36     private static final String TAG = "SELinuxPolicyInstallReceiver";
37 
38     private static final String sepolicyPath = "sepolicy";
39     private static final String fileContextsPath = "file_contexts.bin";
40     private static final String propertyContextsPath = "property_contexts";
41     private static final String seappContextsPath = "seapp_contexts";
42     private static final String versionPath = "selinux_version";
43     private static final String macPermissionsPath = "mac_permissions.xml";
44     private static final String serviceContextsPath = "service_contexts";
45 
SELinuxPolicyInstallReceiver()46     public SELinuxPolicyInstallReceiver() {
47         super("/data/security/bundle", "sepolicy_bundle", "metadata/", "version");
48     }
49 
readInt(BufferedInputStream reader)50     private int readInt(BufferedInputStream reader) throws IOException {
51         int value = 0;
52         for (int i=0; i < 4; i++) {
53             value = (value << 8) | reader.read();
54         }
55         return value;
56     }
57 
readChunkLengths(BufferedInputStream bundle)58     private int[] readChunkLengths(BufferedInputStream bundle) throws IOException {
59         int[] chunks = new int[7];
60         chunks[0] = readInt(bundle);
61         chunks[1] = readInt(bundle);
62         chunks[2] = readInt(bundle);
63         chunks[3] = readInt(bundle);
64         chunks[4] = readInt(bundle);
65         chunks[5] = readInt(bundle);
66         chunks[6] = readInt(bundle);
67         return chunks;
68     }
69 
installFile(File destination, BufferedInputStream stream, int length)70     private void installFile(File destination, BufferedInputStream stream, int length)
71             throws IOException {
72         byte[] chunk = new byte[length];
73         stream.read(chunk, 0, length);
74         writeUpdate(updateDir, destination, Base64.decode(chunk, Base64.DEFAULT));
75     }
76 
deleteRecursive(File fileOrDirectory)77     private void deleteRecursive(File fileOrDirectory) {
78         if (fileOrDirectory.isDirectory())
79             for (File child : fileOrDirectory.listFiles())
80                 deleteRecursive(child);
81         fileOrDirectory.delete();
82     }
83 
unpackBundle()84     private void unpackBundle() throws IOException {
85         BufferedInputStream stream = new BufferedInputStream(new FileInputStream(updateContent));
86         File tmp = new File(updateDir.getParentFile(), "tmp");
87         try {
88             int[] chunkLengths = readChunkLengths(stream);
89             deleteRecursive(tmp);
90             tmp.mkdirs();
91             installFile(new File(tmp, versionPath), stream, chunkLengths[0]);
92             installFile(new File(tmp, macPermissionsPath), stream, chunkLengths[1]);
93             installFile(new File(tmp, seappContextsPath), stream, chunkLengths[2]);
94             installFile(new File(tmp, propertyContextsPath), stream, chunkLengths[3]);
95             installFile(new File(tmp, fileContextsPath), stream, chunkLengths[4]);
96             installFile(new File(tmp, sepolicyPath), stream, chunkLengths[5]);
97             installFile(new File(tmp, serviceContextsPath), stream, chunkLengths[6]);
98         } finally {
99             IoUtils.closeQuietly(stream);
100         }
101     }
102 
applyUpdate()103     private void applyUpdate() throws IOException, ErrnoException {
104         Slog.i(TAG, "Applying SELinux policy");
105         File backup = new File(updateDir.getParentFile(), "backup");
106         File current = new File(updateDir.getParentFile(), "current");
107         File tmp = new File(updateDir.getParentFile(), "tmp");
108         if (current.exists()) {
109             deleteRecursive(backup);
110             Os.rename(current.getPath(), backup.getPath());
111         }
112         try {
113             Os.rename(tmp.getPath(), current.getPath());
114             SystemProperties.set("selinux.reload_policy", "1");
115         } catch (ErrnoException e) {
116             Slog.e(TAG, "Could not update selinux policy: ", e);
117             if (backup.exists()) {
118                 Os.rename(backup.getPath(), current.getPath());
119             }
120         }
121     }
122 
123     @Override
postInstall(Context context, Intent intent)124     protected void postInstall(Context context, Intent intent) {
125         try {
126             unpackBundle();
127             applyUpdate();
128         } catch (IllegalArgumentException e) {
129             Slog.e(TAG, "SELinux policy update malformed: ", e);
130         } catch (IOException e) {
131             Slog.e(TAG, "Could not update selinux policy: ", e);
132         } catch (ErrnoException e) {
133             Slog.e(TAG, "Could not update selinux policy: ", e);
134         }
135     }
136 }
137