Enforce permissions for calls with specified userId
Fix a couple of places where incorrect userIds were being passed in.
Change-Id: I398c676e0488ff7e584be96e96c8b32652134238
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 0f10c4f..91753aa 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -502,20 +502,28 @@
}
}
+ /**
+ * @hide
+ */
@Override
- public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags) {
+ public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags, int userId) {
try {
return mPM.queryIntentReceivers(
intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
flags,
- UserHandle.myUserId());
+ userId);
} catch (RemoteException e) {
throw new RuntimeException("Package manager has died", e);
}
}
@Override
+ public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags) {
+ return queryBroadcastReceivers(intent, flags, UserHandle.myUserId());
+ }
+
+ @Override
public ResolveInfo resolveService(Intent intent, int flags) {
try {
return mPM.resolveService(
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 0aa094f..2afeb7e 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1796,6 +1796,26 @@
int flags);
/**
+ * Retrieve all receivers that can handle a broadcast of the given intent, for a specific
+ * user.
+ *
+ * @param intent The desired intent as per resolveActivity().
+ * @param flags Additional option flags.
+ * @param userId The userId of the user being queried.
+ *
+ * @return A List<ResolveInfo> containing one entry for each matching
+ * Receiver. These are ordered from first to last in priority. If
+ * there are no matching receivers, an empty list is returned.
+ *
+ * @see #MATCH_DEFAULT_ONLY
+ * @see #GET_INTENT_FILTERS
+ * @see #GET_RESOLVED_FILTER
+ * @hide
+ */
+ public abstract List<ResolveInfo> queryBroadcastReceivers(Intent intent,
+ int flags, int userId);
+
+ /**
* Determine the best service to handle for a given Intent.
*
* @param intent An intent containing all of the desired specification
diff --git a/core/java/android/server/search/Searchables.java b/core/java/android/server/search/Searchables.java
index 4e00ef9..30ca340 100644
--- a/core/java/android/server/search/Searchables.java
+++ b/core/java/android/server/search/Searchables.java
@@ -27,6 +27,7 @@
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.os.Binder;
import android.os.Bundle;
import android.os.RemoteException;
import android.provider.Settings;
@@ -70,7 +71,7 @@
"com.google.android.providers.enhancedgooglesearch/.Launcher";
// Cache the package manager instance
- private IPackageManager mPm;
+ final private IPackageManager mPm;
// User for which this Searchables caches information
private int mUserId;
@@ -81,6 +82,7 @@
public Searchables (Context context, int userId) {
mContext = context;
mUserId = userId;
+ mPm = AppGlobals.getPackageManager();
}
/**
@@ -125,50 +127,50 @@
ActivityInfo ai = null;
try {
- ai = mContext.getPackageManager().
- getActivityInfo(activity, PackageManager.GET_META_DATA );
- String refActivityName = null;
+ ai = mPm.getActivityInfo(activity, PackageManager.GET_META_DATA, mUserId);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error getting activity info " + re);
+ return null;
+ }
+ String refActivityName = null;
- // First look for activity-specific reference
- Bundle md = ai.metaData;
+ // First look for activity-specific reference
+ Bundle md = ai.metaData;
+ if (md != null) {
+ refActivityName = md.getString(MD_LABEL_DEFAULT_SEARCHABLE);
+ }
+ // If not found, try for app-wide reference
+ if (refActivityName == null) {
+ md = ai.applicationInfo.metaData;
if (md != null) {
refActivityName = md.getString(MD_LABEL_DEFAULT_SEARCHABLE);
}
- // If not found, try for app-wide reference
- if (refActivityName == null) {
- md = ai.applicationInfo.metaData;
- if (md != null) {
- refActivityName = md.getString(MD_LABEL_DEFAULT_SEARCHABLE);
- }
+ }
+
+ // Irrespective of source, if a reference was found, follow it.
+ if (refActivityName != null)
+ {
+ // This value is deprecated, return null
+ if (refActivityName.equals(MD_SEARCHABLE_SYSTEM_SEARCH)) {
+ return null;
+ }
+ String pkg = activity.getPackageName();
+ ComponentName referredActivity;
+ if (refActivityName.charAt(0) == '.') {
+ referredActivity = new ComponentName(pkg, pkg + refActivityName);
+ } else {
+ referredActivity = new ComponentName(pkg, refActivityName);
}
- // Irrespective of source, if a reference was found, follow it.
- if (refActivityName != null)
- {
- // This value is deprecated, return null
- if (refActivityName.equals(MD_SEARCHABLE_SYSTEM_SEARCH)) {
- return null;
- }
- String pkg = activity.getPackageName();
- ComponentName referredActivity;
- if (refActivityName.charAt(0) == '.') {
- referredActivity = new ComponentName(pkg, pkg + refActivityName);
- } else {
- referredActivity = new ComponentName(pkg, refActivityName);
- }
-
- // Now try the referred activity, and if found, cache
- // it against the original name so we can skip the check
- synchronized (this) {
- result = mSearchablesMap.get(referredActivity);
- if (result != null) {
- mSearchablesMap.put(activity, result);
- return result;
- }
+ // Now try the referred activity, and if found, cache
+ // it against the original name so we can skip the check
+ synchronized (this) {
+ result = mSearchablesMap.get(referredActivity);
+ if (result != null) {
+ mSearchablesMap.put(activity, result);
+ return result;
}
}
- } catch (PackageManager.NameNotFoundException e) {
- // case 3: no metadata
}
// Step 3. None found. Return null.
@@ -208,6 +210,7 @@
// Use intent resolver to generate list of ACTION_SEARCH & ACTION_WEB_SEARCH receivers.
List<ResolveInfo> searchList;
final Intent intent = new Intent(Intent.ACTION_SEARCH);
+
searchList = queryIntentActivities(intent, PackageManager.GET_META_DATA);
List<ResolveInfo> webSearchInfoList;
@@ -219,6 +222,7 @@
int search_count = (searchList == null ? 0 : searchList.size());
int web_search_count = (webSearchInfoList == null ? 0 : webSearchInfoList.size());
int count = search_count + web_search_count;
+ long token = Binder.clearCallingIdentity();
for (int ii = 0; ii < count; ii++) {
// for each component, try to find metadata
ResolveInfo info = (ii < search_count)
@@ -237,6 +241,7 @@
}
}
}
+ Binder.restoreCallingIdentity(token);
}
List<ResolveInfo> newGlobalSearchActivities = findGlobalSearchActivities();
@@ -391,9 +396,6 @@
}
private List<ResolveInfo> queryIntentActivities(Intent intent, int flags) {
- if (mPm == null) {
- mPm = AppGlobals.getPackageManager();
- }
List<ResolveInfo> activities = null;
try {
activities =
diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java
index 539e561..79dabee 100644
--- a/services/java/com/android/server/AppWidgetServiceImpl.java
+++ b/services/java/com/android/server/AppWidgetServiceImpl.java
@@ -1514,11 +1514,12 @@
String pkg = parser.getAttributeValue(null, "pkg");
String cl = parser.getAttributeValue(null, "cl");
- final PackageManager packageManager = mContext.getPackageManager();
+ final IPackageManager packageManager = AppGlobals.getPackageManager();
try {
- packageManager.getReceiverInfo(new ComponentName(pkg, cl), 0);
- } catch (PackageManager.NameNotFoundException e) {
- String[] pkgs = packageManager
+ packageManager.getReceiverInfo(new ComponentName(pkg, cl), 0,
+ UserHandle.getCallingUserId());
+ } catch (RemoteException e) {
+ String[] pkgs = mContext.getPackageManager()
.currentToCanonicalPackageNames(new String[] { pkg });
pkg = pkgs[0];
}
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 9b61ec4..e45cee3 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -21,6 +21,7 @@
import static org.xmlpull.v1.XmlPullParser.START_TAG;
import android.app.ActivityManagerNative;
+import android.app.AppGlobals;
import android.app.IActivityManager;
import android.app.INotificationManager;
import android.app.ITransientNotification;
@@ -1313,14 +1314,14 @@
return;
}
try {
- ApplicationInfo ai = mContext.getPackageManager().getApplicationInfo(
- pkg, 0);
+ ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
+ pkg, 0, UserHandle.getCallingUserId());
if (!UserHandle.isSameApp(ai.uid, uid)) {
throw new SecurityException("Calling uid " + uid + " gave package"
+ pkg + " which is owned by uid " + ai.uid);
}
- } catch (PackageManager.NameNotFoundException e) {
- throw new SecurityException("Unknown package " + pkg);
+ } catch (RemoteException re) {
+ throw new SecurityException("Unknown package " + pkg + "\n" + re);
}
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index eee818b..6c87252 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -8193,7 +8193,7 @@
for (String pkg : process.pkgList) {
sb.append("Package: ").append(pkg);
try {
- PackageInfo pi = pm.getPackageInfo(pkg, 0, 0);
+ PackageInfo pi = pm.getPackageInfo(pkg, 0, UserHandle.getCallingUserId());
if (pi != null) {
sb.append(" v").append(pi.versionCode);
if (pi.versionName != null) {
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 48a4b74..5220a7d 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -1633,6 +1633,7 @@
@Override
public PackageInfo getPackageInfo(String packageName, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get package info");
// reader
synchronized (mPackages) {
PackageParser.Package p = mPackages.get(packageName);
@@ -1675,6 +1676,7 @@
@Override
public int getPackageUid(String packageName, int userId) {
if (!sUserManager.exists(userId)) return -1;
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get package uid");
// reader
synchronized (mPackages) {
PackageParser.Package p = mPackages.get(packageName);
@@ -1831,6 +1833,7 @@
@Override
public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get application info");
// writer
synchronized (mPackages) {
PackageParser.Package p = mPackages.get(packageName);
@@ -1910,6 +1913,7 @@
@Override
public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get activity info");
synchronized (mPackages) {
PackageParser.Activity a = mActivities.mActivities.get(component);
@@ -1930,6 +1934,7 @@
@Override
public ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get receiver info");
synchronized (mPackages) {
PackageParser.Activity a = mReceivers.mActivities.get(component);
if (DEBUG_PACKAGE_INFO) Log.v(
@@ -1947,6 +1952,7 @@
@Override
public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get service info");
synchronized (mPackages) {
PackageParser.Service s = mServices.mServices.get(component);
if (DEBUG_PACKAGE_INFO) Log.v(
@@ -1964,6 +1970,7 @@
@Override
public ProviderInfo getProviderInfo(ComponentName component, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get provider info");
synchronized (mPackages) {
PackageParser.Provider p = mProvidersByComponent.get(component);
if (DEBUG_PACKAGE_INFO) Log.v(
@@ -2065,6 +2072,34 @@
return PackageManager.PERMISSION_DENIED;
}
+ /**
+ * Checks if the request is from the system or an app that has INTERACT_ACROSS_USERS
+ * or INTERACT_ACROSS_USERS_FULL permissions, if the userid is not for the caller.
+ * @param message the message to log on security exception
+ * @return
+ */
+ private void enforceCrossUserPermission(int callingUid, int userId,
+ boolean requireFullPermission, String message) {
+ if (userId < 0) {
+ throw new IllegalArgumentException("Invalid userId " + userId);
+ }
+ if (userId == UserHandle.getUserId(callingUid)) return;
+ if (callingUid != Process.SYSTEM_UID && callingUid != 0) {
+ if (requireFullPermission) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
+ } else {
+ try {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
+ } catch (SecurityException se) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS, message);
+ }
+ }
+ }
+ }
+
private BasePermission findPermissionTreeLP(String permName) {
for(BasePermission bp : mSettings.mPermissionTrees.values()) {
if (permName.startsWith(bp.name) &&
@@ -2397,6 +2432,7 @@
public ResolveInfo resolveIntent(Intent intent, String resolvedType,
int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "resolve intent");
List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags, userId);
return chooseBestActivity(intent, resolvedType, flags, query, userId);
}
@@ -2538,6 +2574,7 @@
public List<ResolveInfo> queryIntentActivities(Intent intent,
String resolvedType, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "query intent activities");
ComponentName comp = intent.getComponent();
if (comp == null) {
if (intent.getSelector() != null) {
@@ -2577,6 +2614,8 @@
Intent[] specifics, String[] specificTypes, Intent intent,
String resolvedType, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, false,
+ "query intent activity options");
final String resultsAction = intent.getAction();
List<ResolveInfo> results = queryIntentActivities(intent, resolvedType, flags
@@ -8230,7 +8269,7 @@
final IPackageDataObserver observer, final int userId) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CLEAR_APP_USER_DATA, null);
- checkValidCaller(Binder.getCallingUid(), userId);
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "clear application data");
// Queue up an async operation since the package deletion may take a little while.
mHandler.post(new Runnable() {
public void run() {
@@ -8462,7 +8501,7 @@
ComponentName[] set, ComponentName activity, int userId) {
// writer
int callingUid = Binder.getCallingUid();
- checkValidCaller(callingUid, userId);
+ enforceCrossUserPermission(callingUid, userId, true, "add preferred activity");
synchronized (mPackages) {
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
@@ -8652,7 +8691,7 @@
final int uid = Binder.getCallingUid();
final int permission = mContext.checkCallingPermission(
android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);
- checkValidCaller(uid, userId);
+ enforceCrossUserPermission(uid, userId, false, "set enabled");
final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
boolean sendNow = false;
boolean isApp = (className == null);
@@ -8780,7 +8819,7 @@
final int permission = mContext.checkCallingOrSelfPermission(
android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);
final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
- checkValidCaller(uid, userId);
+ enforceCrossUserPermission(uid, userId, true, "stop package");
// writer
synchronized (mPackages) {
if (mSettings.setPackageStoppedStateLPw(packageName, stopped, allowedByPermission,
@@ -8801,7 +8840,7 @@
public int getApplicationEnabledSetting(String packageName, int userId) {
if (!sUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED;
int uid = Binder.getCallingUid();
- checkValidCaller(uid, userId);
+ enforceCrossUserPermission(uid, userId, false, "get enabled");
// reader
synchronized (mPackages) {
return mSettings.getApplicationEnabledSettingLPr(packageName, userId);
@@ -8812,7 +8851,7 @@
public int getComponentEnabledSetting(ComponentName componentName, int userId) {
if (!sUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED;
int uid = Binder.getCallingUid();
- checkValidCaller(uid, userId);
+ enforceCrossUserPermission(uid, userId, false, "get component enabled");
// reader
synchronized (mPackages) {
return mSettings.getComponentEnabledSettingLPr(componentName, userId);
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 562f286..19eb8d2 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -226,6 +226,12 @@
throw new UnsupportedOperationException();
}
+ /** @hide */
+ @Override
+ public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags, int userId) {
+ throw new UnsupportedOperationException();
+ }
+
@Override
public ResolveInfo resolveService(Intent intent, int flags) {
throw new UnsupportedOperationException();