DO NOT MERGE: Check provider access for content changes.

am: c813f5dae2

Change-Id: I939bca8887198e2578916356d49b0f2f0a2bf3d2
This commit is contained in:
Jeff Sharkey
2016-12-02 18:19:46 +00:00
committed by android-build-merger
3 changed files with 88 additions and 34 deletions

View File

@@ -60,6 +60,11 @@ public abstract class ActivityManagerInternal {
*/
public static final int APP_TRANSITION_TIMEOUT = 3;
/**
* 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);

View File

@@ -10400,6 +10400,46 @@ 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
| PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
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
@@ -21855,6 +21895,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);

View File

@@ -20,12 +20,12 @@ import android.Manifest;
import android.accounts.Account;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.ActivityManagerNative;
import android.app.AppOpsManager;
import android.app.job.JobInfo;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.Context;
import android.content.IContentService;
@@ -66,7 +66,6 @@ import com.android.server.SystemService;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -296,24 +295,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) {
if (checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION, userHandle)
!= 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) {
@@ -363,22 +353,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) {
if (checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
userHandle) != 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
@@ -1143,6 +1126,27 @@ public final class ContentService extends IContentService.Stub {
}
}
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.