From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Austin Borger 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 b4e2e2b9cac9..2953c71d5a26 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 AndroidPackage 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.getPackageName(), /*flags*/0, Process.SYSTEM_UID, + UserHandle.USER_SYSTEM); + if (!appInfo.isVendor() && !appInfo.isSystemApp() && !appInfo.isSystemExt() + && !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 + "'");