Prevent root from getting unverified attributions from non system apps

Similar to shell, system server, and other packages, the root UID
bypasses attribution tag registration requirements. This can be
exploited by a malicious proxy app.

Also fixes a bug which caused an unverified proxy app's attribution tag
to be erroneously called "valid" if "finishProxyOp" was called for a
non-system proxy app, and one of the special proxied apps

Bug: 416491779
Test: atest AppOpsMemoryUsageTest
Flag: EXEMPT see bug
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:ab99cde450cf900767a641ddcf71f4a42e771334)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:03012467103fb5eb0e375173934a35c1a053ff35)
Merged-In: I9b44465554e10b803bc9b4ab76130aaf9933f605
Change-Id: I9b44465554e10b803bc9b4ab76130aaf9933f605
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 1dd864d..04bd896 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -4100,30 +4100,40 @@
             return null;
         }
 
-        finishOperationUnchecked(clientId, code, proxiedUid, resolvedProxiedPackageName,
-                proxiedAttributionTag, proxyVirtualDeviceId);
+        finishOperationUnchecked(clientId, code, proxyUid, resolvedProxyPackageName,
+                proxiedUid, resolvedProxiedPackageName, proxiedAttributionTag,
+                proxyVirtualDeviceId);
 
         return null;
     }
+    private void finishOperationUnchecked(IBinder clientId, int code, int uid,
+            String packageName, String attributionTag, int virtualDeviceId) {
+        finishOperationUnchecked(clientId, code, -1, null, uid, packageName, attributionTag,
+                virtualDeviceId);
+    }
 
-    private void finishOperationUnchecked(IBinder clientId, int code, int uid, String packageName,
-            String attributionTag, int virtualDeviceId) {
+    private void finishOperationUnchecked(IBinder clientId, int code, int proxyUid,
+            String proxyPackageName, int proxiedUid,
+            String proxiedPackageName, String attributionTag,
+            int virtualDeviceId) {
         PackageVerificationResult pvr;
         try {
-            pvr = verifyAndGetBypass(uid, packageName, attributionTag);
+            pvr = verifyAndGetBypass(proxiedUid, proxiedPackageName, attributionTag,
+                    proxyUid, proxyPackageName);
             if (!pvr.isAttributionTagValid) {
                 attributionTag = null;
             }
         } catch (SecurityException e) {
-            logVerifyAndGetBypassFailure(uid, e, "finishOperation");
+            logVerifyAndGetBypassFailure(proxiedUid, e, "finishOperation");
             return;
         }
 
         synchronized (this) {
-            Op op = getOpLocked(code, uid, packageName, attributionTag, pvr.isAttributionTagValid,
-                    pvr.bypass, /* edit */ true);
+            Op op = getOpLocked(code, proxiedUid, proxiedPackageName, attributionTag,
+                    pvr.isAttributionTagValid, pvr.bypass, /* edit */ true);
             if (op == null) {
-                Slog.e(TAG, "Operation not found: uid=" + uid + " pkg=" + packageName + "("
+                Slog.e(TAG, "Operation not found: uid=" + proxiedUid + " pkg=" + proxiedPackageName
+                        + "("
                         + attributionTag + ") op=" + AppOpsManager.opToName(code));
                 return;
             }
@@ -4131,7 +4141,8 @@
                     op.mDeviceAttributedOps.getOrDefault(getPersistentId(virtualDeviceId),
                             new ArrayMap<>()).get(attributionTag);
             if (attributedOp == null) {
-                Slog.e(TAG, "Attribution not found: uid=" + uid + " pkg=" + packageName + "("
+                Slog.e(TAG, "Attribution not found: uid=" + proxiedUid
+                        + " pkg=" + proxiedPackageName + "("
                         + attributionTag + ") op=" + AppOpsManager.opToName(code));
                 return;
             }
@@ -4139,7 +4150,8 @@
             if (attributedOp.isRunning() || attributedOp.isPaused()) {
                 attributedOp.finished(clientId);
             } else {
-                Slog.e(TAG, "Operation not started: uid=" + uid + " pkg=" + packageName + "("
+                Slog.e(TAG, "Operation not started: uid=" + proxiedUid
+                        + " pkg=" + proxiedPackageName + "("
                         + attributionTag + ") op=" + AppOpsManager.opToName(code));
             }
         }
@@ -4576,9 +4588,13 @@
             @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.
+            // For backwards compatibility, don't check package name for root UID, unless someone
+            // is claiming to be a proxy for root, which should never happen in normal usage.
+            // 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.
             return new PackageVerificationResult(null,
-                    /* isAttributionTagValid */ true);
+                    /* isAttributionTagValid */ isPackageNullOrSystem(proxyPackageName, proxyUid));
         }
         if (Process.isSdkSandboxUid(uid)) {
             // SDK sandbox processes run in their own UID range, but their associated
@@ -4641,16 +4657,8 @@
             // 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 */ proxyIsSystemAppOrNull);
+                    /* isAttributionTagValid */ isPackageNullOrSystem(proxyPackageName, proxyUid));
         }
 
         int userId = UserHandle.getUserId(uid);
@@ -4715,6 +4723,17 @@
         return new PackageVerificationResult(bypass, isAttributionTagValid);
     }
 
+    private boolean isPackageNullOrSystem(String packageName, int uid) {
+        if (packageName == null) {
+            return true;
+        }
+        int appId = UserHandle.getAppId(uid);
+        if (appId > 0 && appId < Process.FIRST_APPLICATION_UID) {
+            return true;
+        }
+        return mPackageManagerInternal.isSystemPackage(packageName);
+    }
+
     private boolean isAttributionInPackage(@Nullable AndroidPackage pkg,
             @Nullable String attributionTag) {
         if (pkg == null) {