From 1a49146508c82f719a8f500b1b7d50d90d1f57cb Mon Sep 17 00:00:00 2001 From: Arc Wang Date: Mon, 12 Dec 2022 14:44:16 +0800 Subject: [PATCH] Allow 2-pane deep link to access unexported Activity If an Activity is not exported, the Activity still can be launched by components of the same application, applications with the same user ID, or privileged system components. Bug: 261678674 Bug: 250589026 Test: manual visual Launcher -> context menu -> Wallpaper & style Change-Id: I662df6cb287361b135e2c596abe946ddeb03bda4 --- .../homepage/SettingsHomepageActivity.java | 65 +++++++++++++++---- 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/src/com/android/settings/homepage/SettingsHomepageActivity.java b/src/com/android/settings/homepage/SettingsHomepageActivity.java index fc0c68ea91a..bef07cde89e 100644 --- a/src/com/android/settings/homepage/SettingsHomepageActivity.java +++ b/src/com/android/settings/homepage/SettingsHomepageActivity.java @@ -32,6 +32,8 @@ import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.content.res.Configuration; import android.os.Bundle; +import android.os.Process; +import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.text.TextUtils; @@ -465,20 +467,19 @@ public class SettingsHomepageActivity extends FragmentActivity implements return; } - if (!TextUtils.equals(PasswordUtils.getCallingAppPackageName(getActivityToken()), - getPackageName())) { - ActivityInfo targetActivityInfo = null; - try { - targetActivityInfo = getPackageManager().getActivityInfo(targetComponentName, - /* flags= */ 0); - } catch (PackageManager.NameNotFoundException e) { - Log.e(TAG, "Failed to get target ActivityInfo: " + e); - finish(); - return; - } + ActivityInfo targetActivityInfo = null; + try { + targetActivityInfo = getPackageManager().getActivityInfo(targetComponentName, + /* flags= */ 0); + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "Failed to get target ActivityInfo: " + e); + finish(); + return; + } + if (!hasPrivilegedAccess(targetActivityInfo)) { if (!targetActivityInfo.exported) { - Log.e(TAG, "Must not launch an unexported Actvity for deep link"); + Log.e(TAG, "Target Activity is not exported"); finish(); return; } @@ -527,6 +528,46 @@ public class SettingsHomepageActivity extends FragmentActivity implements } } + // Check if calling app has privileged access to launch Activity of activityInfo. + private boolean hasPrivilegedAccess(ActivityInfo activityInfo) { + if (TextUtils.equals(PasswordUtils.getCallingAppPackageName(getActivityToken()), + getPackageName())) { + return true; + } + + int callingUid = -1; + try { + callingUid = ActivityManager.getService().getLaunchedFromUid(getActivityToken()); + } catch (RemoteException re) { + Log.e(TAG, "Not able to get callingUid: " + re); + return false; + } + + int targetUid = -1; + try { + targetUid = getPackageManager().getApplicationInfo(activityInfo.packageName, + /* flags= */ 0).uid; + } catch (PackageManager.NameNotFoundException nnfe) { + Log.e(TAG, "Not able to get targetUid: " + nnfe); + return false; + } + + // When activityInfo.exported is false, Activity still can be launched if applications have + // the same user ID. + if (UserHandle.isSameApp(callingUid, targetUid)) { + return true; + } + + // When activityInfo.exported is false, Activity still can be launched if calling app has + // root or system privilege. + int callingAppId = UserHandle.getAppId(callingUid); + if (callingAppId == Process.ROOT_UID || callingAppId == Process.SYSTEM_UID) { + return true; + } + + return false; + } + @VisibleForTesting boolean isCallingAppPermitted(String permission) { return TextUtils.isEmpty(permission) || PasswordUtils.isCallingAppPermitted(