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