am 8be305dd: Merge "Also check app-ops on path-permissions." into mnc-dev
* commit '8be305dd6582f154c5a5894034a35fc8ec225b71': Also check app-ops on path-permissions.
This commit is contained in:
@@ -16,8 +16,11 @@
|
|||||||
|
|
||||||
package android.content;
|
package android.content;
|
||||||
|
|
||||||
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
|
||||||
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
|
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
|
||||||
|
import static android.app.AppOpsManager.MODE_ALLOWED;
|
||||||
|
import static android.app.AppOpsManager.MODE_ERRORED;
|
||||||
|
import static android.app.AppOpsManager.MODE_IGNORED;
|
||||||
|
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
@@ -40,8 +43,8 @@ import android.os.OperationCanceledException;
|
|||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.util.Log;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
@@ -474,14 +477,9 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
|
|||||||
|
|
||||||
private int enforceReadPermission(String callingPkg, Uri uri, IBinder callerToken)
|
private int enforceReadPermission(String callingPkg, Uri uri, IBinder callerToken)
|
||||||
throws SecurityException {
|
throws SecurityException {
|
||||||
enforceReadPermissionInner(uri, callerToken);
|
final int mode = enforceReadPermissionInner(uri, callingPkg, callerToken);
|
||||||
|
if (mode != MODE_ALLOWED) {
|
||||||
final int permOp = AppOpsManager.permissionToOpCode(mReadPermission);
|
return mode;
|
||||||
if (permOp != AppOpsManager.OP_NONE) {
|
|
||||||
final int mode = mAppOpsManager.noteProxyOp(permOp, callingPkg);
|
|
||||||
if (mode != AppOpsManager.MODE_ALLOWED) {
|
|
||||||
return mode;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mReadOp != AppOpsManager.OP_NONE) {
|
if (mReadOp != AppOpsManager.OP_NONE) {
|
||||||
@@ -493,14 +491,9 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
|
|||||||
|
|
||||||
private int enforceWritePermission(String callingPkg, Uri uri, IBinder callerToken)
|
private int enforceWritePermission(String callingPkg, Uri uri, IBinder callerToken)
|
||||||
throws SecurityException {
|
throws SecurityException {
|
||||||
enforceWritePermissionInner(uri, callerToken);
|
final int mode = enforceWritePermissionInner(uri, callingPkg, callerToken);
|
||||||
|
if (mode != MODE_ALLOWED) {
|
||||||
final int permOp = AppOpsManager.permissionToOpCode(mWritePermission);
|
return mode;
|
||||||
if (permOp != AppOpsManager.OP_NONE) {
|
|
||||||
final int mode = mAppOpsManager.noteProxyOp(permOp, callingPkg);
|
|
||||||
if (mode != AppOpsManager.MODE_ALLOWED) {
|
|
||||||
return mode;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mWriteOp != AppOpsManager.OP_NONE) {
|
if (mWriteOp != AppOpsManager.OP_NONE) {
|
||||||
@@ -518,26 +511,47 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
|
|||||||
== PERMISSION_GRANTED;
|
== PERMISSION_GRANTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that calling app holds both the given permission and any app-op
|
||||||
|
* associated with that permission.
|
||||||
|
*/
|
||||||
|
private int checkPermissionAndAppOp(String permission, String callingPkg,
|
||||||
|
IBinder callerToken) {
|
||||||
|
if (getContext().checkPermission(permission, Binder.getCallingPid(), Binder.getCallingUid(),
|
||||||
|
callerToken) != PERMISSION_GRANTED) {
|
||||||
|
return MODE_ERRORED;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int permOp = AppOpsManager.permissionToOpCode(permission);
|
||||||
|
if (permOp != AppOpsManager.OP_NONE) {
|
||||||
|
return mTransport.mAppOpsManager.noteProxyOp(permOp, callingPkg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return MODE_ALLOWED;
|
||||||
|
}
|
||||||
|
|
||||||
/** {@hide} */
|
/** {@hide} */
|
||||||
protected void enforceReadPermissionInner(Uri uri, IBinder callerToken)
|
protected int enforceReadPermissionInner(Uri uri, String callingPkg, IBinder callerToken)
|
||||||
throws SecurityException {
|
throws SecurityException {
|
||||||
final Context context = getContext();
|
final Context context = getContext();
|
||||||
final int pid = Binder.getCallingPid();
|
final int pid = Binder.getCallingPid();
|
||||||
final int uid = Binder.getCallingUid();
|
final int uid = Binder.getCallingUid();
|
||||||
String missingPerm = null;
|
String missingPerm = null;
|
||||||
|
int strongestMode = MODE_ALLOWED;
|
||||||
|
|
||||||
if (UserHandle.isSameApp(uid, mMyUid)) {
|
if (UserHandle.isSameApp(uid, mMyUid)) {
|
||||||
return;
|
return MODE_ALLOWED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mExported && checkUser(pid, uid, context)) {
|
if (mExported && checkUser(pid, uid, context)) {
|
||||||
final String componentPerm = getReadPermission();
|
final String componentPerm = getReadPermission();
|
||||||
if (componentPerm != null) {
|
if (componentPerm != null) {
|
||||||
if (context.checkPermission(componentPerm, pid, uid, callerToken)
|
final int mode = checkPermissionAndAppOp(componentPerm, callingPkg, callerToken);
|
||||||
== PERMISSION_GRANTED) {
|
if (mode == MODE_ALLOWED) {
|
||||||
return;
|
return MODE_ALLOWED;
|
||||||
} else {
|
} else {
|
||||||
missingPerm = componentPerm;
|
missingPerm = componentPerm;
|
||||||
|
strongestMode = Math.max(strongestMode, mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -551,14 +565,15 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
|
|||||||
for (PathPermission pp : pps) {
|
for (PathPermission pp : pps) {
|
||||||
final String pathPerm = pp.getReadPermission();
|
final String pathPerm = pp.getReadPermission();
|
||||||
if (pathPerm != null && pp.match(path)) {
|
if (pathPerm != null && pp.match(path)) {
|
||||||
if (context.checkPermission(pathPerm, pid, uid, callerToken)
|
final int mode = checkPermissionAndAppOp(pathPerm, callingPkg, callerToken);
|
||||||
== PERMISSION_GRANTED) {
|
if (mode == MODE_ALLOWED) {
|
||||||
return;
|
return MODE_ALLOWED;
|
||||||
} else {
|
} else {
|
||||||
// any denied <path-permission> means we lose
|
// any denied <path-permission> means we lose
|
||||||
// default <provider> access.
|
// default <provider> access.
|
||||||
allowDefaultRead = false;
|
allowDefaultRead = false;
|
||||||
missingPerm = pathPerm;
|
missingPerm = pathPerm;
|
||||||
|
strongestMode = Math.max(strongestMode, mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -566,7 +581,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
|
|||||||
|
|
||||||
// if we passed <path-permission> checks above, and no default
|
// if we passed <path-permission> checks above, and no default
|
||||||
// <provider> permission, then allow access.
|
// <provider> permission, then allow access.
|
||||||
if (allowDefaultRead) return;
|
if (allowDefaultRead) return MODE_ALLOWED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// last chance, check against any uri grants
|
// last chance, check against any uri grants
|
||||||
@@ -575,7 +590,13 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
|
|||||||
? maybeAddUserId(uri, callingUserId) : uri;
|
? maybeAddUserId(uri, callingUserId) : uri;
|
||||||
if (context.checkUriPermission(userUri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION,
|
if (context.checkUriPermission(userUri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION,
|
||||||
callerToken) == PERMISSION_GRANTED) {
|
callerToken) == PERMISSION_GRANTED) {
|
||||||
return;
|
return MODE_ALLOWED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the worst denial we found above was ignored, then pass that
|
||||||
|
// ignored through; otherwise we assume it should be a real error below.
|
||||||
|
if (strongestMode == MODE_IGNORED) {
|
||||||
|
return MODE_IGNORED;
|
||||||
}
|
}
|
||||||
|
|
||||||
final String failReason = mExported
|
final String failReason = mExported
|
||||||
@@ -587,25 +608,27 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** {@hide} */
|
/** {@hide} */
|
||||||
protected void enforceWritePermissionInner(Uri uri, IBinder callerToken)
|
protected int enforceWritePermissionInner(Uri uri, String callingPkg, IBinder callerToken)
|
||||||
throws SecurityException {
|
throws SecurityException {
|
||||||
final Context context = getContext();
|
final Context context = getContext();
|
||||||
final int pid = Binder.getCallingPid();
|
final int pid = Binder.getCallingPid();
|
||||||
final int uid = Binder.getCallingUid();
|
final int uid = Binder.getCallingUid();
|
||||||
String missingPerm = null;
|
String missingPerm = null;
|
||||||
|
int strongestMode = MODE_ALLOWED;
|
||||||
|
|
||||||
if (UserHandle.isSameApp(uid, mMyUid)) {
|
if (UserHandle.isSameApp(uid, mMyUid)) {
|
||||||
return;
|
return MODE_ALLOWED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mExported && checkUser(pid, uid, context)) {
|
if (mExported && checkUser(pid, uid, context)) {
|
||||||
final String componentPerm = getWritePermission();
|
final String componentPerm = getWritePermission();
|
||||||
if (componentPerm != null) {
|
if (componentPerm != null) {
|
||||||
if (context.checkPermission(componentPerm, pid, uid, callerToken)
|
final int mode = checkPermissionAndAppOp(componentPerm, callingPkg, callerToken);
|
||||||
== PERMISSION_GRANTED) {
|
if (mode == MODE_ALLOWED) {
|
||||||
return;
|
return MODE_ALLOWED;
|
||||||
} else {
|
} else {
|
||||||
missingPerm = componentPerm;
|
missingPerm = componentPerm;
|
||||||
|
strongestMode = Math.max(strongestMode, mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -619,14 +642,15 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
|
|||||||
for (PathPermission pp : pps) {
|
for (PathPermission pp : pps) {
|
||||||
final String pathPerm = pp.getWritePermission();
|
final String pathPerm = pp.getWritePermission();
|
||||||
if (pathPerm != null && pp.match(path)) {
|
if (pathPerm != null && pp.match(path)) {
|
||||||
if (context.checkPermission(pathPerm, pid, uid, callerToken)
|
final int mode = checkPermissionAndAppOp(pathPerm, callingPkg, callerToken);
|
||||||
== PERMISSION_GRANTED) {
|
if (mode == MODE_ALLOWED) {
|
||||||
return;
|
return MODE_ALLOWED;
|
||||||
} else {
|
} else {
|
||||||
// any denied <path-permission> means we lose
|
// any denied <path-permission> means we lose
|
||||||
// default <provider> access.
|
// default <provider> access.
|
||||||
allowDefaultWrite = false;
|
allowDefaultWrite = false;
|
||||||
missingPerm = pathPerm;
|
missingPerm = pathPerm;
|
||||||
|
strongestMode = Math.max(strongestMode, mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -634,13 +658,19 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
|
|||||||
|
|
||||||
// if we passed <path-permission> checks above, and no default
|
// if we passed <path-permission> checks above, and no default
|
||||||
// <provider> permission, then allow access.
|
// <provider> permission, then allow access.
|
||||||
if (allowDefaultWrite) return;
|
if (allowDefaultWrite) return MODE_ALLOWED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// last chance, check against any uri grants
|
// last chance, check against any uri grants
|
||||||
if (context.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
|
if (context.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
|
||||||
callerToken) == PERMISSION_GRANTED) {
|
callerToken) == PERMISSION_GRANTED) {
|
||||||
return;
|
return MODE_ALLOWED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the worst denial we found above was ignored, then pass that
|
||||||
|
// ignored through; otherwise we assume it should be a real error below.
|
||||||
|
if (strongestMode == MODE_IGNORED) {
|
||||||
|
return MODE_IGNORED;
|
||||||
}
|
}
|
||||||
|
|
||||||
final String failReason = mExported
|
final String failReason = mExported
|
||||||
|
|||||||
@@ -640,7 +640,7 @@ public abstract class DocumentsProvider extends ContentProvider {
|
|||||||
final Bundle out = new Bundle();
|
final Bundle out = new Bundle();
|
||||||
try {
|
try {
|
||||||
if (METHOD_CREATE_DOCUMENT.equals(method)) {
|
if (METHOD_CREATE_DOCUMENT.equals(method)) {
|
||||||
enforceWritePermissionInner(documentUri, null);
|
enforceWritePermissionInner(documentUri, getCallingPackage(), null);
|
||||||
|
|
||||||
final String mimeType = extras.getString(Document.COLUMN_MIME_TYPE);
|
final String mimeType = extras.getString(Document.COLUMN_MIME_TYPE);
|
||||||
final String displayName = extras.getString(Document.COLUMN_DISPLAY_NAME);
|
final String displayName = extras.getString(Document.COLUMN_DISPLAY_NAME);
|
||||||
@@ -654,7 +654,7 @@ public abstract class DocumentsProvider extends ContentProvider {
|
|||||||
out.putParcelable(DocumentsContract.EXTRA_URI, newDocumentUri);
|
out.putParcelable(DocumentsContract.EXTRA_URI, newDocumentUri);
|
||||||
|
|
||||||
} else if (METHOD_RENAME_DOCUMENT.equals(method)) {
|
} else if (METHOD_RENAME_DOCUMENT.equals(method)) {
|
||||||
enforceWritePermissionInner(documentUri, null);
|
enforceWritePermissionInner(documentUri, getCallingPackage(), null);
|
||||||
|
|
||||||
final String displayName = extras.getString(Document.COLUMN_DISPLAY_NAME);
|
final String displayName = extras.getString(Document.COLUMN_DISPLAY_NAME);
|
||||||
final String newDocumentId = renameDocument(documentId, displayName);
|
final String newDocumentId = renameDocument(documentId, displayName);
|
||||||
@@ -678,7 +678,7 @@ public abstract class DocumentsProvider extends ContentProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else if (METHOD_DELETE_DOCUMENT.equals(method)) {
|
} else if (METHOD_DELETE_DOCUMENT.equals(method)) {
|
||||||
enforceWritePermissionInner(documentUri, null);
|
enforceWritePermissionInner(documentUri, getCallingPackage(), null);
|
||||||
deleteDocument(documentId);
|
deleteDocument(documentId);
|
||||||
|
|
||||||
// Document no longer exists, clean up any grants
|
// Document no longer exists, clean up any grants
|
||||||
|
|||||||
Reference in New Issue
Block a user