DO NOT MERGE: Check provider access for content changes.
am: ff2fede0dd
Change-Id: I7de766d1acc1f20e83f07953dedfe3810f906db8
This commit is contained in:
@@ -25,6 +25,11 @@ import android.content.ComponentName;
|
||||
* @hide Only for use within the system server.
|
||||
*/
|
||||
public abstract class ActivityManagerInternal {
|
||||
/**
|
||||
* Verify that calling app has access to the given provider.
|
||||
*/
|
||||
public abstract String checkContentProviderAccess(String authority, int userId);
|
||||
|
||||
// Called by the power manager.
|
||||
public abstract void onWakefulnessChanged(int wakefulness);
|
||||
|
||||
|
||||
@@ -9309,6 +9309,43 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
return providers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the calling UID has a possible chance at accessing the provider
|
||||
* at the given authority and user.
|
||||
*/
|
||||
public String checkContentProviderAccess(String authority, int userId) {
|
||||
if (userId == UserHandle.USER_ALL) {
|
||||
mContext.enforceCallingOrSelfPermission(
|
||||
Manifest.permission.INTERACT_ACROSS_USERS_FULL, TAG);
|
||||
userId = UserHandle.getCallingUserId();
|
||||
}
|
||||
|
||||
ProviderInfo cpi = null;
|
||||
try {
|
||||
cpi = AppGlobals.getPackageManager().resolveContentProvider(authority,
|
||||
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
|
||||
} catch (RemoteException ignored) {
|
||||
}
|
||||
if (cpi == null) {
|
||||
// TODO: make this an outright failure in a future platform release;
|
||||
// until then anonymous content notifications are unprotected
|
||||
//return "Failed to find provider " + authority + " for user " + userId;
|
||||
return null;
|
||||
}
|
||||
|
||||
ProcessRecord r = null;
|
||||
synchronized (mPidsSelfLocked) {
|
||||
r = mPidsSelfLocked.get(Binder.getCallingPid());
|
||||
}
|
||||
if (r == null) {
|
||||
return "Failed to find PID " + Binder.getCallingPid();
|
||||
}
|
||||
|
||||
synchronized (this) {
|
||||
return checkContentProviderPermissionLocked(cpi, r, userId, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if {@link ProcessRecord} has a possible chance at accessing the
|
||||
* given {@link ProviderInfo}. Final permission checking is always done
|
||||
@@ -20630,6 +20667,11 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
}
|
||||
|
||||
private final class LocalService extends ActivityManagerInternal {
|
||||
@Override
|
||||
public String checkContentProviderAccess(String authority, int userId) {
|
||||
return ActivityManagerService.this.checkContentProviderAccess(authority, userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWakefulnessChanged(int wakefulness) {
|
||||
ActivityManagerService.this.onWakefulnessChanged(wakefulness);
|
||||
|
||||
@@ -19,6 +19,8 @@ package com.android.server.content;
|
||||
import android.Manifest;
|
||||
import android.accounts.Account;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityManagerInternal;
|
||||
import android.app.ActivityManagerNative;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
@@ -51,7 +53,6 @@ import com.android.server.LocalServices;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.security.InvalidParameterException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
@@ -190,23 +191,15 @@ public final class ContentService extends IContentService.Stub {
|
||||
|
||||
final int uid = Binder.getCallingUid();
|
||||
final int pid = Binder.getCallingPid();
|
||||
final int callingUserHandle = UserHandle.getCallingUserId();
|
||||
// Registering an observer for any user other than the calling user requires uri grant or
|
||||
// cross user permission
|
||||
if (callingUserHandle != userHandle &&
|
||||
mContext.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
enforceCrossUserPermission(userHandle,
|
||||
"no permission to observe other users' provider view");
|
||||
}
|
||||
|
||||
if (userHandle < 0) {
|
||||
if (userHandle == UserHandle.USER_CURRENT) {
|
||||
userHandle = ActivityManager.getCurrentUser();
|
||||
} else if (userHandle != UserHandle.USER_ALL) {
|
||||
throw new InvalidParameterException("Bad user handle for registerContentObserver: "
|
||||
+ userHandle);
|
||||
}
|
||||
userHandle = handleIncomingUser(uri, pid, uid,
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION, userHandle);
|
||||
|
||||
final String msg = LocalServices.getService(ActivityManagerInternal.class)
|
||||
.checkContentProviderAccess(uri.getAuthority(), userHandle);
|
||||
if (msg != null) {
|
||||
Log.w(TAG, "Ignoring content changes for " + uri + " from " + uid + ": " + msg);
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (mRootNode) {
|
||||
@@ -253,21 +246,15 @@ public final class ContentService extends IContentService.Stub {
|
||||
final int uid = Binder.getCallingUid();
|
||||
final int pid = Binder.getCallingPid();
|
||||
final int callingUserHandle = UserHandle.getCallingUserId();
|
||||
// Notify for any user other than the caller requires uri grant or cross user permission
|
||||
if (callingUserHandle != userHandle &&
|
||||
mContext.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
enforceCrossUserPermission(userHandle, "no permission to notify other users");
|
||||
}
|
||||
|
||||
// We passed the permission check; resolve pseudouser targets as appropriate
|
||||
if (userHandle < 0) {
|
||||
if (userHandle == UserHandle.USER_CURRENT) {
|
||||
userHandle = ActivityManager.getCurrentUser();
|
||||
} else if (userHandle != UserHandle.USER_ALL) {
|
||||
throw new InvalidParameterException("Bad user handle for notifyChange: "
|
||||
+ userHandle);
|
||||
}
|
||||
userHandle = handleIncomingUser(uri, pid, uid,
|
||||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION, userHandle);
|
||||
|
||||
final String msg = LocalServices.getService(ActivityManagerInternal.class)
|
||||
.checkContentProviderAccess(uri.getAuthority(), userHandle);
|
||||
if (msg != null) {
|
||||
Log.w(TAG, "Ignoring notify for " + uri + " from " + uid + ": " + msg);
|
||||
return;
|
||||
}
|
||||
|
||||
// This makes it so that future permission checks will be in the context of this
|
||||
@@ -317,6 +304,15 @@ public final class ContentService extends IContentService.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
private int checkUriPermission(Uri uri, int pid, int uid, int modeFlags, int userHandle) {
|
||||
try {
|
||||
return ActivityManagerNative.getDefault().checkUriPermission(
|
||||
uri, pid, uid, modeFlags, userHandle, null);
|
||||
} catch (RemoteException e) {
|
||||
return PackageManager.PERMISSION_DENIED;
|
||||
}
|
||||
}
|
||||
|
||||
public void notifyChange(Uri uri, IContentObserver observer,
|
||||
boolean observerWantsSelfNotifications, boolean syncToNetwork) {
|
||||
notifyChange(uri, observer, observerWantsSelfNotifications, syncToNetwork,
|
||||
@@ -924,6 +920,27 @@ public final class ContentService extends IContentService.Stub {
|
||||
return service;
|
||||
}
|
||||
|
||||
private int handleIncomingUser(Uri uri, int pid, int uid, int modeFlags, int userId) {
|
||||
if (userId == UserHandle.USER_CURRENT) {
|
||||
userId = ActivityManager.getCurrentUser();
|
||||
}
|
||||
|
||||
if (userId == UserHandle.USER_ALL) {
|
||||
mContext.enforceCallingOrSelfPermission(
|
||||
Manifest.permission.INTERACT_ACROSS_USERS_FULL, TAG);
|
||||
} else if (userId < 0) {
|
||||
throw new IllegalArgumentException("Invalid user: " + userId);
|
||||
} else if (userId != UserHandle.getCallingUserId()) {
|
||||
if (checkUriPermission(uri, pid, uid, modeFlags,
|
||||
userId) != PackageManager.PERMISSION_GRANTED) {
|
||||
mContext.enforceCallingOrSelfPermission(
|
||||
Manifest.permission.INTERACT_ACROSS_USERS_FULL, TAG);
|
||||
}
|
||||
}
|
||||
|
||||
return userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the request is from the system or an app that has INTERACT_ACROSS_USERS_FULL
|
||||
* permission, if the userHandle is not for the caller.
|
||||
|
||||
Reference in New Issue
Block a user