DO NOT MERGE. Check provider access for content changes.
am: 91add43ae7
Change-Id: I158a5dab0643fb5d2c07393f0df030e93b3c006a
This commit is contained in:
@@ -22,6 +22,11 @@ package android.app;
|
|||||||
* @hide Only for use within the system server.
|
* @hide Only for use within the system server.
|
||||||
*/
|
*/
|
||||||
public abstract class ActivityManagerInternal {
|
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.
|
// Called by the power manager.
|
||||||
public abstract void onWakefulnessChanged(int wakefulness);
|
public abstract void onWakefulnessChanged(int wakefulness);
|
||||||
|
|
||||||
|
|||||||
@@ -8998,6 +8998,44 @@ public final class ActivityManagerService extends ActivityManagerNative
|
|||||||
return providers;
|
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
|
* Check if {@link ProcessRecord} has a possible chance at accessing the
|
||||||
* given {@link ProviderInfo}. Final permission checking is always done
|
* given {@link ProviderInfo}. Final permission checking is always done
|
||||||
@@ -19660,6 +19698,11 @@ public final class ActivityManagerService extends ActivityManagerNative
|
|||||||
}
|
}
|
||||||
|
|
||||||
private final class LocalService extends ActivityManagerInternal {
|
private final class LocalService extends ActivityManagerInternal {
|
||||||
|
@Override
|
||||||
|
public String checkContentProviderAccess(String authority, int userId) {
|
||||||
|
return ActivityManagerService.this.checkContentProviderAccess(authority, userId);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onWakefulnessChanged(int wakefulness) {
|
public void onWakefulnessChanged(int wakefulness) {
|
||||||
ActivityManagerService.this.onWakefulnessChanged(wakefulness);
|
ActivityManagerService.this.onWakefulnessChanged(wakefulness);
|
||||||
|
|||||||
@@ -19,11 +19,14 @@ package com.android.server.content;
|
|||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.accounts.Account;
|
import android.accounts.Account;
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
|
import android.app.ActivityManagerInternal;
|
||||||
|
import android.app.ActivityManagerNative;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.IContentService;
|
import android.content.IContentService;
|
||||||
import android.content.ISyncStatusObserver;
|
import android.content.ISyncStatusObserver;
|
||||||
|
import android.content.Intent;
|
||||||
import android.content.PeriodicSync;
|
import android.content.PeriodicSync;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.SyncAdapterType;
|
import android.content.SyncAdapterType;
|
||||||
@@ -46,6 +49,8 @@ import android.util.Log;
|
|||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
import android.util.SparseIntArray;
|
import android.util.SparseIntArray;
|
||||||
|
|
||||||
|
import com.android.server.LocalServices;
|
||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.security.InvalidParameterException;
|
import java.security.InvalidParameterException;
|
||||||
@@ -172,16 +177,17 @@ public final class ContentService extends IContentService.Stub {
|
|||||||
throw new IllegalArgumentException("You must pass a valid uri and observer");
|
throw new IllegalArgumentException("You must pass a valid uri and observer");
|
||||||
}
|
}
|
||||||
|
|
||||||
enforceCrossUserPermission(userHandle,
|
final int uid = Binder.getCallingUid();
|
||||||
"no permission to observe other users' provider view");
|
final int pid = Binder.getCallingPid();
|
||||||
|
|
||||||
if (userHandle < 0) {
|
userHandle = handleIncomingUser(uri, pid, uid,
|
||||||
if (userHandle == UserHandle.USER_CURRENT) {
|
Intent.FLAG_GRANT_READ_URI_PERMISSION, userHandle);
|
||||||
userHandle = ActivityManager.getCurrentUser();
|
|
||||||
} else if (userHandle != UserHandle.USER_ALL) {
|
final String msg = LocalServices.getService(ActivityManagerInternal.class)
|
||||||
throw new InvalidParameterException("Bad user handle for registerContentObserver: "
|
.checkContentProviderAccess(uri.getAuthority(), userHandle);
|
||||||
+ userHandle);
|
if (msg != null) {
|
||||||
}
|
Log.w(TAG, "Ignoring content changes for " + uri + " from " + uid + ": " + msg);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized (mRootNode) {
|
synchronized (mRootNode) {
|
||||||
@@ -224,24 +230,20 @@ public final class ContentService extends IContentService.Stub {
|
|||||||
+ " from observer " + observer + ", syncToNetwork " + syncToNetwork);
|
+ " from observer " + observer + ", syncToNetwork " + syncToNetwork);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify for any user other than the caller's own requires permission.
|
|
||||||
final int callingUserHandle = UserHandle.getCallingUserId();
|
|
||||||
if (userHandle != callingUserHandle) {
|
|
||||||
mContext.enforceCallingOrSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS,
|
|
||||||
"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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final int uid = Binder.getCallingUid();
|
final int uid = Binder.getCallingUid();
|
||||||
|
final int pid = Binder.getCallingPid();
|
||||||
|
final int callingUserHandle = UserHandle.getCallingUserId();
|
||||||
|
|
||||||
|
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
|
// This makes it so that future permission checks will be in the context of this
|
||||||
// process rather than the caller's process. We will restore this before returning.
|
// process rather than the caller's process. We will restore this before returning.
|
||||||
long identityToken = clearCallingIdentity();
|
long identityToken = clearCallingIdentity();
|
||||||
@@ -881,6 +883,24 @@ public final class ContentService extends IContentService.Stub {
|
|||||||
return service;
|
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()) {
|
||||||
|
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
|
* 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.
|
* permission, if the userHandle is not for the caller.
|
||||||
|
|||||||
Reference in New Issue
Block a user