• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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.om;
18 
19 import static com.android.server.om.OverlayManagerService.DEBUG;
20 import static com.android.server.om.OverlayManagerService.TAG;
21 
22 import android.annotation.IntDef;
23 import android.annotation.NonNull;
24 import android.annotation.UserIdInt;
25 import android.content.om.OverlayConstraint;
26 import android.content.om.OverlayInfo;
27 import android.content.om.OverlayableInfo;
28 import android.os.Build.VERSION_CODES;
29 import android.os.FabricatedOverlayInfo;
30 import android.os.FabricatedOverlayInternal;
31 import android.os.OverlayablePolicy;
32 import android.os.SystemProperties;
33 import android.text.TextUtils;
34 import android.util.Slog;
35 
36 import com.android.server.pm.pkg.AndroidPackage;
37 import com.android.server.pm.pkg.PackageState;
38 
39 import java.io.IOException;
40 import java.lang.annotation.Retention;
41 import java.lang.annotation.RetentionPolicy;
42 import java.util.List;
43 
44 /**
45  * Handle the creation and deletion of idmap files.
46  *
47  * The actual work is performed by idmap2d.
48  * @see IdmapDaemon
49  */
50 final class IdmapManager {
51     private static final boolean VENDOR_IS_Q_OR_LATER;
52     static {
53         final String value = SystemProperties.get("ro.vndk.version", "29");
54         boolean isQOrLater;
55         try {
56             isQOrLater = Integer.parseInt(value) >= 29;
57         } catch (NumberFormatException e) {
58             // The version is not a number, therefore it is a development codename.
59             isQOrLater = true;
60         }
61 
62         VENDOR_IS_Q_OR_LATER = isQOrLater;
63     }
64 
65     static final int IDMAP_NOT_EXIST = 0;
66     static final int IDMAP_IS_VERIFIED = 1;
67     static final int IDMAP_IS_MODIFIED = 1 << 1;
68 
69     @IntDef(flag = true, prefix = { "IDMAP_" }, value = {
70             IDMAP_NOT_EXIST,
71             IDMAP_IS_VERIFIED,
72             IDMAP_IS_MODIFIED,
73     })
74     @Retention(RetentionPolicy.SOURCE)
75     public @interface IdmapStatus {}
76 
77     private final IdmapDaemon mIdmapDaemon;
78     private final PackageManagerHelper mPackageManager;
79 
80     /**
81      * Package name of the reference package defined in 'overlay-config-signature' tag of
82      * SystemConfig or empty String if tag not defined. This package is vetted on scan by
83      * PackageManagerService that it's a system package and is used to check if overlay matches
84      * its signature in order to fulfill the config_signature policy.
85      */
86     private final String mConfigSignaturePackage;
87 
IdmapManager(final IdmapDaemon idmapDaemon, final PackageManagerHelper packageManager)88     IdmapManager(final IdmapDaemon idmapDaemon, final PackageManagerHelper packageManager) {
89         mPackageManager = packageManager;
90         mIdmapDaemon = idmapDaemon;
91         mConfigSignaturePackage = packageManager.getConfigSignaturePackage();
92     }
93 
94     /**
95      * Creates the idmap for the target/overlay combination and returns whether the idmap file was
96      * modified.
97      * @return the status of the specific idmap file. It's one of the following.<ul>
98      *     <li>{@link #IDMAP_NOT_EXIST} means the idmap file is not existed.</li>
99      *     <li>{@link #IDMAP_IS_VERIFIED} means the idmap file is verified by Idmap2d.</li>
100      *     <li>{@link #IDMAP_IS_MODIFIED | IDMAP_IS_VERIFIED } means the idmap file is modified and
101      *     verified by Idmap2d.</li>
102      * </ul>.
103      */
createIdmap(@onNull final AndroidPackage targetPackage, @NonNull PackageState overlayPackageState, @NonNull final AndroidPackage overlayPackage, String overlayBasePath, String overlayName, @UserIdInt int userId, @NonNull final List<OverlayConstraint> constraints)104     @IdmapStatus int createIdmap(@NonNull final AndroidPackage targetPackage,
105             @NonNull PackageState overlayPackageState, @NonNull final AndroidPackage overlayPackage,
106             String overlayBasePath, String overlayName, @UserIdInt int userId,
107             @NonNull final List<OverlayConstraint> constraints) {
108         if (DEBUG) {
109             Slog.d(TAG, "create idmap for " + targetPackage.getPackageName() + " and "
110                     + overlayPackage.getPackageName());
111         }
112         final String targetPath = targetPackage.getSplits().get(0).getPath();
113         try {
114             int policies = calculateFulfilledPolicies(targetPackage, overlayPackageState,
115                     overlayPackage, userId);
116             boolean enforce = enforceOverlayable(overlayPackageState, overlayPackage);
117             android.os.OverlayConstraint[] idmapConstraints = toIdmapConstraints(constraints);
118             if (mIdmapDaemon.verifyIdmap(targetPath, overlayBasePath, overlayName, policies,
119                     enforce, userId, idmapConstraints)) {
120                 return IDMAP_IS_VERIFIED;
121             }
122             final boolean idmapCreated = mIdmapDaemon.createIdmap(targetPath, overlayBasePath,
123                     overlayName, policies, enforce, userId, idmapConstraints) != null;
124             return (idmapCreated) ? IDMAP_IS_MODIFIED | IDMAP_IS_VERIFIED : IDMAP_NOT_EXIST;
125         } catch (Exception e) {
126             Slog.w(TAG, "failed to generate idmap for " + targetPath + " and "
127                     + overlayBasePath, e);
128             return IDMAP_NOT_EXIST;
129         }
130     }
131 
removeIdmap(@onNull final OverlayInfo oi, final int userId)132     boolean removeIdmap(@NonNull final OverlayInfo oi, final int userId) {
133         if (DEBUG) {
134             Slog.d(TAG, "remove idmap for " + oi.baseCodePath);
135         }
136         try {
137             return mIdmapDaemon.removeIdmap(oi.baseCodePath, userId);
138         } catch (Exception e) {
139             Slog.w(TAG, "failed to remove idmap for " + oi.baseCodePath, e);
140             return false;
141         }
142     }
143 
idmapExists(@onNull final OverlayInfo oi)144     boolean idmapExists(@NonNull final OverlayInfo oi) {
145         return mIdmapDaemon.idmapExists(oi.baseCodePath, oi.userId);
146     }
147 
148     /**
149      * @return the list of all fabricated overlays
150      */
getFabricatedOverlayInfos()151     List<FabricatedOverlayInfo> getFabricatedOverlayInfos() {
152         return mIdmapDaemon.getFabricatedOverlayInfos();
153     }
154 
155     /**
156      * Creates a fabricated overlay and persists it to disk.
157      * @return the path to the fabricated overlay
158      */
createFabricatedOverlay(@onNull FabricatedOverlayInternal overlay)159     FabricatedOverlayInfo createFabricatedOverlay(@NonNull FabricatedOverlayInternal overlay) {
160         return mIdmapDaemon.createFabricatedOverlay(overlay);
161     }
162 
163     /**
164      * Deletes the fabricated overlay file on disk.
165      * @return whether the path was deleted
166      */
deleteFabricatedOverlay(@onNull String path)167     boolean deleteFabricatedOverlay(@NonNull String path) {
168         return mIdmapDaemon.deleteFabricatedOverlay(path);
169     }
170 
171     /**
172      * Gets the idmap data associated with an overlay, in dump format.
173      * Only indented for debugging.
174      */
dumpIdmap(@onNull String overlayPath)175     String dumpIdmap(@NonNull String overlayPath) {
176         return mIdmapDaemon.dumpIdmap(overlayPath);
177     }
178 
179     /**
180      * Checks if overlayable and policies should be enforced on the specified overlay for backwards
181      * compatibility with pre-Q overlays.
182      */
enforceOverlayable(@onNull PackageState overlayPackageState, @NonNull final AndroidPackage overlayPackage)183     private boolean enforceOverlayable(@NonNull PackageState overlayPackageState,
184             @NonNull final AndroidPackage overlayPackage) {
185         if (overlayPackage.getTargetSdkVersion() >= VERSION_CODES.Q) {
186             // Always enforce policies for overlays targeting Q+.
187             return true;
188         }
189 
190         if (overlayPackageState.isVendor()) {
191             // If the overlay is on a pre-Q vendor partition, do not enforce overlayable
192             // restrictions on this overlay because the pre-Q platform has no understanding of
193             // overlayable.
194             return VENDOR_IS_Q_OR_LATER;
195         }
196 
197         // Do not enforce overlayable restrictions on pre-Q overlays that are signed with the
198         // platform signature or that are preinstalled.
199         return !(overlayPackageState.isSystem() || overlayPackage.isSignedWithPlatformKey());
200     }
201 
202     /**
203      * Retrieves a bitmask for idmap2 that represents the policies the overlay fulfills.
204      */
calculateFulfilledPolicies(@onNull final AndroidPackage targetPackage, @NonNull PackageState overlayPackageState, @NonNull final AndroidPackage overlayPackage, @UserIdInt int userId)205     private int calculateFulfilledPolicies(@NonNull final AndroidPackage targetPackage,
206             @NonNull PackageState overlayPackageState, @NonNull final AndroidPackage overlayPackage,
207             @UserIdInt int userId)  {
208         int fulfilledPolicies = OverlayablePolicy.PUBLIC;
209 
210         // Overlay matches target signature
211         if (mPackageManager.signaturesMatching(targetPackage.getPackageName(),
212                 overlayPackage.getPackageName(), userId)) {
213             fulfilledPolicies |= OverlayablePolicy.SIGNATURE;
214         }
215 
216         // Overlay matches actor signature
217         if (matchesActorSignature(targetPackage, overlayPackage, userId)) {
218             fulfilledPolicies |= OverlayablePolicy.ACTOR_SIGNATURE;
219         }
220 
221         // If SystemConfig defines 'overlay-config-signature' package, given that
222         // this package is vetted by OverlayManagerService that it's a
223         // preinstalled package, check if overlay matches its signature.
224         if (!TextUtils.isEmpty(mConfigSignaturePackage)
225                 && mPackageManager.signaturesMatching(mConfigSignaturePackage,
226                                                            overlayPackage.getPackageName(),
227                                                            userId)) {
228             fulfilledPolicies |= OverlayablePolicy.CONFIG_SIGNATURE;
229         }
230 
231         // Vendor partition (/vendor)
232         if (overlayPackageState.isVendor()) {
233             return fulfilledPolicies | OverlayablePolicy.VENDOR_PARTITION;
234         }
235 
236         // Product partition (/product)
237         if (overlayPackageState.isProduct()) {
238             return fulfilledPolicies | OverlayablePolicy.PRODUCT_PARTITION;
239         }
240 
241         // Odm partition (/odm)
242         if (overlayPackageState.isOdm()) {
243             return fulfilledPolicies | OverlayablePolicy.ODM_PARTITION;
244         }
245 
246         // Oem partition (/oem)
247         if (overlayPackageState.isOem()) {
248             return fulfilledPolicies | OverlayablePolicy.OEM_PARTITION;
249         }
250 
251         // System_ext partition (/system_ext) is considered as system
252         // Check this last since every partition except for data is scanned as system in the PMS.
253         if (overlayPackageState.isSystem() || overlayPackageState.isSystemExt()) {
254             return fulfilledPolicies | OverlayablePolicy.SYSTEM_PARTITION;
255         }
256 
257         return fulfilledPolicies;
258     }
259 
matchesActorSignature(@onNull AndroidPackage targetPackage, @NonNull AndroidPackage overlayPackage, int userId)260     private boolean matchesActorSignature(@NonNull AndroidPackage targetPackage,
261             @NonNull AndroidPackage overlayPackage, int userId) {
262         String targetOverlayableName = overlayPackage.getOverlayTargetOverlayableName();
263         if (targetOverlayableName != null && !mPackageManager.getNamedActors().isEmpty()) {
264             try {
265                 OverlayableInfo overlayableInfo = mPackageManager.getOverlayableForTarget(
266                         targetPackage.getPackageName(), targetOverlayableName, userId);
267                 if (overlayableInfo != null && overlayableInfo.actor != null) {
268                     String actorPackageName = OverlayActorEnforcer.getPackageNameForActor(
269                             overlayableInfo.actor, mPackageManager.getNamedActors()).first;
270                     if (mPackageManager.signaturesMatching(actorPackageName,
271                             overlayPackage.getPackageName(), userId)) {
272                         return true;
273                     }
274                 }
275             } catch (IOException ignored) {
276             }
277         }
278 
279         return false;
280     }
281 
282     @NonNull
toIdmapConstraints( @onNull final List<OverlayConstraint> constraints)283     private static android.os.OverlayConstraint[] toIdmapConstraints(
284             @NonNull final List<OverlayConstraint> constraints) {
285         android.os.OverlayConstraint[] idmapConstraints =
286                 new android.os.OverlayConstraint[constraints.size()];
287         int index = 0;
288         for (OverlayConstraint constraint : constraints) {
289             android.os.OverlayConstraint idmapConstraint = new android.os.OverlayConstraint();
290             idmapConstraint.type = constraint.getType();
291             idmapConstraint.value = constraint.getValue();
292             idmapConstraints[index++] = idmapConstraint;
293         }
294         return idmapConstraints;
295     }
296 }
297