diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 50515882271a3..a23b5eb50b159 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -3294,7 +3294,7 @@ public class AppOpsService extends IAppOpsService.Stub { boolean shouldCollectMessage) { RestrictionBypass bypass; try { - bypass = verifyAndGetBypass(uid, packageName, attributionTag); + bypass = verifyAndGetBypass(uid, packageName, attributionTag, proxyPackageName); } catch (SecurityException e) { Slog.e(TAG, "noteOperation", e); return new SyncNotedAppOp(AppOpsManager.MODE_ERRORED, code, attributionTag, @@ -3786,7 +3786,7 @@ public class AppOpsService extends IAppOpsService.Stub { boolean shouldCollectMessage, boolean dryRun) { RestrictionBypass bypass; try { - bypass = verifyAndGetBypass(uid, packageName, attributionTag); + bypass = verifyAndGetBypass(uid, packageName, attributionTag, proxyPackageName); } catch (SecurityException e) { Slog.e(TAG, "startOperation", e); return new SyncNotedAppOp(AppOpsManager.MODE_ERRORED, code, attributionTag, @@ -4317,6 +4317,14 @@ public class AppOpsService extends IAppOpsService.Stub { == PackageManager.PERMISSION_GRANTED); } + /** + * @see verifyAndGetBypass(int, String, String, String) + */ + private @Nullable RestrictionBypass verifyAndGetBypass(int uid, String packageName, + @Nullable String attributionTag) { + return verifyAndGetBypass(uid, packageName, attributionTag, null); + } + /** * Verify that package belongs to uid and return the {@link RestrictionBypass bypass * description} for the package. @@ -4324,11 +4332,12 @@ public class AppOpsService extends IAppOpsService.Stub { * @param uid The uid the package belongs to * @param packageName The package the might belong to the uid * @param attributionTag attribution tag or {@code null} if no need to verify + * @param proxyPackageName The proxy package, from which the attribution tag is to be pulled * * @return {@code true} iff the package is privileged */ private @Nullable RestrictionBypass verifyAndGetBypass(int uid, String packageName, - @Nullable String attributionTag) { + @Nullable String attributionTag, @Nullable String proxyPackageName) { if (uid == Process.ROOT_UID) { // For backwards compatibility, don't check package name for root UID. return null; @@ -4366,34 +4375,36 @@ public class AppOpsService extends IAppOpsService.Stub { final long ident = Binder.clearCallingIdentity(); try { boolean isAttributionTagValid = false; - AndroidPackage pkg = LocalServices.getService(PackageManagerInternal.class) - .getPackage(packageName); + PackageManagerInternal pmInt = LocalServices.getService(PackageManagerInternal.class); + AndroidPackage pkg = pmInt.getPackage(packageName); if (pkg != null) { - if (attributionTag == null) { - isAttributionTagValid = true; - } else { - if (pkg.getAttributions() != null) { - int numAttributions = pkg.getAttributions().size(); - for (int i = 0; i < numAttributions; i++) { - if (pkg.getAttributions().get(i).tag.equals(attributionTag)) { - isAttributionTagValid = true; - } - } - } - } + isAttributionTagValid = isAttributionInPackage(pkg, attributionTag); pkgUid = UserHandle.getUid(userId, UserHandle.getAppId(pkg.getUid())); bypass = getBypassforPackage(pkg); } if (!isAttributionTagValid) { - String msg = "attributionTag " + attributionTag + " not declared in" - + " manifest of " + packageName; + AndroidPackage proxyPkg = proxyPackageName != null + ? pmInt.getPackage(proxyPackageName) : null; + boolean foundInProxy = isAttributionInPackage(proxyPkg, attributionTag); + String msg; + if (pkg != null && foundInProxy) { + msg = "attributionTag " + attributionTag + " declared in manifest of the proxy" + + " package " + proxyPackageName + ", this is not advised"; + } else if (pkg != null) { + msg = "attributionTag " + attributionTag + " not declared in manifest of " + + packageName; + } else { + msg = "package " + packageName + " not found, can't check for " + + "attributionTag " + attributionTag; + } + try { if (mPlatformCompat.isChangeEnabledByPackageName( SECURITY_EXCEPTION_ON_INVALID_ATTRIBUTION_TAG_CHANGE, packageName, userId) && mPlatformCompat.isChangeEnabledByUid( SECURITY_EXCEPTION_ON_INVALID_ATTRIBUTION_TAG_CHANGE, - callingUid)) { + callingUid) && !foundInProxy) { throw new SecurityException(msg); } else { Slog.e(TAG, msg); @@ -4413,6 +4424,25 @@ public class AppOpsService extends IAppOpsService.Stub { return bypass; } + private boolean isAttributionInPackage(@Nullable AndroidPackage pkg, + @Nullable String attributionTag) { + if (pkg == null) { + return false; + } else if (attributionTag == null) { + return true; + } + if (pkg.getAttributions() != null) { + int numAttributions = pkg.getAttributions().size(); + for (int i = 0; i < numAttributions; i++) { + if (pkg.getAttributions().get(i).tag.equals(attributionTag)) { + return true; + } + } + } + + return false; + } + /** * Get (and potentially create) ops. *