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