diff options
| -rw-r--r-- | services/core/java/com/android/server/appop/AppOpsService.java | 88 |
1 files changed, 63 insertions, 25 deletions
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index b891aeeb527d..2e48b24eb25c 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -699,7 +699,7 @@ public class AppOpsService extends IAppOpsService.Stub { } } - /** Returned from {@link #verifyAndGetBypass(int, String, String, String, boolean)}. */ + /** Returned from {@link #verifyAndGetBypass(int, String, String, int, String, boolean)}. */ private static final class PackageVerificationResult { final RestrictionBypass bypass; @@ -3336,7 +3336,7 @@ public class AppOpsService extends IAppOpsService.Stub { verifyAndGetBypass(uid, packageName, null); // When the caller is the system, it's possible that the packageName is the special // one (e.g., "root") which isn't actually existed. - if (resolveUid(packageName) == uid + if (resolveNonAppUid(packageName) == uid || (isPackageExisted(packageName) && !filterAppAccessUnlocked(packageName))) { return AppOpsManager.MODE_ALLOWED; } @@ -3460,7 +3460,7 @@ public class AppOpsService extends IAppOpsService.Stub { boolean shouldCollectMessage) { PackageVerificationResult pvr; try { - pvr = verifyAndGetBypass(uid, packageName, attributionTag, proxyPackageName); + pvr = verifyAndGetBypass(uid, packageName, attributionTag, proxyUid, proxyPackageName); boolean wasNull = attributionTag == null; if (!pvr.isAttributionTagValid) { attributionTag = null; @@ -3979,7 +3979,7 @@ public class AppOpsService extends IAppOpsService.Stub { int attributionChainId, boolean dryRun) { PackageVerificationResult pvr; try { - pvr = verifyAndGetBypass(uid, packageName, attributionTag, proxyPackageName); + pvr = verifyAndGetBypass(uid, packageName, attributionTag, proxyUid, proxyPackageName); if (!pvr.isAttributionTagValid) { attributionTag = null; } @@ -4442,7 +4442,11 @@ public class AppOpsService extends IAppOpsService.Stub { private boolean isCallerAndAttributionTrusted(@NonNull AttributionSource attributionSource) { if (attributionSource.getUid() != Binder.getCallingUid() && attributionSource.isTrusted(mContext)) { - return true; + // if there is a next attribution source, it must be trusted, as well. + if (attributionSource.getNext() == null + || attributionSource.getNext().isTrusted(mContext)) { + return true; + } } return mContext.checkPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS, Binder.getCallingPid(), Binder.getCallingUid(), null) @@ -4580,11 +4584,20 @@ public class AppOpsService extends IAppOpsService.Stub { } /** - * @see #verifyAndGetBypass(int, String, String, String) + * @see #verifyAndGetBypass(int, String, String, int, String, boolean) */ private @NonNull PackageVerificationResult verifyAndGetBypass(int uid, String packageName, @Nullable String attributionTag) { - return verifyAndGetBypass(uid, packageName, attributionTag, null); + return verifyAndGetBypass(uid, packageName, attributionTag, Process.INVALID_UID, null); + } + + /** + * @see #verifyAndGetBypass(int, String, String, int, String, boolean) + */ + private @NonNull PackageVerificationResult verifyAndGetBypass(int uid, String packageName, + @Nullable String attributionTag, int proxyUid, @Nullable String proxyPackageName) { + return verifyAndGetBypass(uid, packageName, attributionTag, proxyUid, proxyPackageName, + false); } /** @@ -4595,13 +4608,16 @@ 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 + * @param proxyUid The proxy uid, from which the attribution tag is to be pulled + * @param proxyPackageName The proxy package, from which the attribution tag may be pulled + * @param suppressErrorLogs Whether to print to logcat about nonmatching parameters * * @return PackageVerificationResult containing {@link RestrictionBypass} and whether the * attribution tag is valid */ private @NonNull PackageVerificationResult verifyAndGetBypass(int uid, String packageName, - @Nullable String attributionTag, @Nullable String proxyPackageName) { + @Nullable String attributionTag, int proxyUid, @Nullable String proxyPackageName, + boolean suppressErrorLogs) { if (uid == Process.ROOT_UID) { // For backwards compatibility, don't check package name for root UID. return new PackageVerificationResult(null, @@ -4645,31 +4661,47 @@ public class AppOpsService extends IAppOpsService.Stub { int callingUid = Binder.getCallingUid(); - // Allow any attribution tag for resolvable uids - int pkgUid; + // Allow any attribution tag for resolvable, non-app uids + int nonAppUid; if (Objects.equals(packageName, "com.android.shell")) { // Special case for the shell which is a package but should be able // to bypass app attribution tag restrictions. - pkgUid = Process.SHELL_UID; + nonAppUid = Process.SHELL_UID; } else { - pkgUid = resolveUid(packageName); - } - if (pkgUid != Process.INVALID_UID) { - if (pkgUid != UserHandle.getAppId(uid)) { - Slog.e(TAG, "Bad call made by uid " + callingUid + ". " - + "Package \"" + packageName + "\" does not belong to uid " + uid + "."); - String otherUidMessage = DEBUG ? " but it is really " + pkgUid : " but it is not"; - throw new SecurityException("Specified package \"" + packageName + "\" under uid " - + UserHandle.getAppId(uid) + otherUidMessage); + nonAppUid = resolveNonAppUid(packageName); + } + if (nonAppUid != Process.INVALID_UID) { + if (nonAppUid != UserHandle.getAppId(uid)) { + if (!suppressErrorLogs) { + Slog.e(TAG, "Bad call made by uid " + callingUid + ". " + + "Package \"" + packageName + "\" does not belong to uid " + uid + + "."); + } + String otherUidMessage = + DEBUG ? " but it is really " + nonAppUid : " but it is not"; + throw new SecurityException("Specified package \"" + packageName + + "\" under uid " + UserHandle.getAppId(uid) + otherUidMessage); + } + // We only allow bypassing the attribution tag verification if the proxy is a + // system app (or is null), in order to prevent abusive apps clogging the appops + // system with unlimited attribution tags via proxy calls. + boolean proxyIsSystemAppOrNull = true; + if (proxyPackageName != null) { + int proxyAppId = UserHandle.getAppId(proxyUid); + if (proxyAppId >= Process.FIRST_APPLICATION_UID) { + proxyIsSystemAppOrNull = + mPackageManagerInternal.isSystemPackage(proxyPackageName); + } } return new PackageVerificationResult(RestrictionBypass.UNRESTRICTED, - /* isAttributionTagValid */ true); + /* isAttributionTagValid */ proxyIsSystemAppOrNull); } int userId = UserHandle.getUserId(uid); RestrictionBypass bypass = null; boolean isAttributionTagValid = false; + int pkgUid = nonAppUid; final long ident = Binder.clearCallingIdentity(); try { PackageManagerInternal pmInt = LocalServices.getService(PackageManagerInternal.class); @@ -5536,7 +5568,7 @@ public class AppOpsService extends IAppOpsService.Stub { if (nonpackageUid != -1) { packageName = null; } else { - packageUid = resolveUid(packageName); + packageUid = resolveNonAppUid(packageName); if (packageUid < 0) { packageUid = AppGlobals.getPackageManager().getPackageUid(packageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, userId); @@ -6720,7 +6752,13 @@ public class AppOpsService extends IAppOpsService.Stub { if (restricted && attrOp.isRunning()) { attrOp.pause(); } else if (attrOp.isPaused()) { - attrOp.resume(); + RestrictionBypass bypass = verifyAndGetBypass(uid, ops.packageName, attrOp.tag) + .bypass; + if (!isOpRestrictedLocked(uid, code, ops.packageName, attrOp.tag, + bypass, false)) { + // Only resume if there are no other restrictions remaining on this op + attrOp.resume(); + } } } } @@ -7165,7 +7203,7 @@ public class AppOpsService extends IAppOpsService.Stub { } } - private static int resolveUid(String packageName) { + private static int resolveNonAppUid(String packageName) { if (packageName == null) { return -1; } |