From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Austin Borger <borgera@google.com>
Date: Sat, 18 Mar 2023 12:56:12 -0700
Subject: [PATCH] ActivityManagerService: Allow openContentUri from
 vendor/system/product.

Apps should not have direct access to this entry point. Check that the
caller is a vendor, system, or product package.

Test: Ran PoC app and CtsMediaPlayerTestCases.
Bug: 236688380
(cherry picked from commit d0ba7467c2cb2815f94f6651cbb1c2f405e8e9c7)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:821f4c0d8ba06be32ce9b46c7a7c09d1cacd7b0e)
Merged-In: I0335496d28fa5fc3bfe1fecd4be90040b0b3687f
Change-Id: I0335496d28fa5fc3bfe1fecd4be90040b0b3687f
---
 .../server/am/ActivityManagerService.java     | 59 ++++++++++++++++++-
 1 file changed, 58 insertions(+), 1 deletion(-)

diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 9bf5898102d4..ec8841debb7a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -160,6 +160,7 @@ import android.app.AppOpsManager;
 import android.app.AppOpsManagerInternal.CheckOpsDelegate;
 import android.app.ApplicationErrorReport;
 import android.app.ApplicationThreadConstants;
+import android.app.AppOpsManager;
 import android.app.BroadcastOptions;
 import android.app.ContentProviderHolder;
 import android.app.Dialog;
@@ -7865,7 +7866,54 @@ public class ActivityManagerService extends IActivityManager.Stub
             Binder token = new Binder();
             sCallerIdentity.set(new Identity(
                     token, Binder.getCallingPid(), Binder.getCallingUid()));
+            boolean handlingSecurityViolation = false;
             try {
+                // This method is exposed to the VNDK and to avoid changing its
+                // signature we just use the first package in the UID. For shared
+                // UIDs we may blame the wrong app but that is Okay as they are
+                // in the same security/privacy sandbox.
+                final int uid = Binder.getCallingUid();
+                // Here we handle some of the special UIDs (mediaserver, systemserver, etc)
+                // Note: This is moved to AppOpsManager.resolvePackageName in future versions.
+                final String packageName;
+                if (uid == Process.ROOT_UID) {
+                    packageName = "root";
+                } else if (uid == Process.SHELL_UID) {
+                    packageName = "com.android.shell";
+                } else if (uid == Process.MEDIA_UID) {
+                    packageName = "media";
+                } else if (uid == Process.AUDIOSERVER_UID) {
+                    packageName = "audioserver";
+                } else if (uid == Process.CAMERASERVER_UID) {
+                    packageName = "cameraserver";
+                } else if (uid == Process.SYSTEM_UID) {
+                    packageName = "android";
+                } else {
+                    packageName = null;
+                }
+
+                final PackageParser.Package androidPackage;
+                if (packageName != null) {
+                    androidPackage = mPackageManagerInt.getPackage(packageName);
+                } else {
+                    androidPackage = mPackageManagerInt.getPackage(uid);
+                }
+                if (androidPackage == null) {
+                    Log.e(TAG, "Cannot find package for uid: " + uid);
+                    handlingSecurityViolation = true;
+                    return null;
+                }
+
+                final ApplicationInfo appInfo = mPackageManagerInt.getApplicationInfo(
+                        androidPackage.packageName, /*flags*/0, Process.SYSTEM_UID,
+                        UserHandle.USER_SYSTEM);
+                if (!appInfo.isVendor() && !appInfo.isSystemApp()
+                        && !appInfo.isProduct()) {
+                    Log.e(TAG, "openContentUri may only be used by vendor/system/product.");
+                    handlingSecurityViolation = true;
+                    return null;
+                }
+
                 pfd = cph.provider.openFile(null, uri, "r", null, token);
             } catch (FileNotFoundException e) {
                 // do nothing; pfd will be returned null
@@ -7873,7 +7921,16 @@ public class ActivityManagerService extends IActivityManager.Stub
                 // Ensure that whatever happens, we clean up the identity state
                 sCallerIdentity.remove();
                 // Ensure we're done with the provider.
-                removeContentProviderExternalUnchecked(name, null, userId);
+                try {
+                    removeContentProviderExternalUnchecked(name, null, userId);
+                } catch (SecurityException e) {
+                    // A SecurityException may be thrown from computeOomAdjLocked if the calling
+                    // UID is that of a malicious app accessing this hidden API. In that case
+                    // we're already handling that by returning null, so tolerate this.
+                    if (!handlingSecurityViolation) {
+                        throw e;
+                    }
+                }
             }
         } else {
             Slog.d(TAG, "Failed to get provider for authority '" + name + "'");
