Merge "Validate that the authority of incoming uris matches." into lmp-dev
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 5f6fb6e..5b722e2 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -97,6 +97,11 @@
private Context mContext = null;
private int mMyUid;
+
+ // Since most Providers have only one authority, we keep both a String and a String[] to improve
+ // performance.
+ private String mAuthority;
+ private String[] mAuthorities;
private String mReadPermission;
private String mWritePermission;
private PathPermission[] mPathPermissions;
@@ -193,7 +198,7 @@
public Cursor query(String callingPkg, Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder,
ICancellationSignal cancellationSignal) {
- getAndEnforceUserId(uri);
+ validateIncomingUri(uri);
uri = getUriWithoutUserId(uri);
if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return rejectQuery(uri, projection, selection, selectionArgs, sortOrder,
@@ -211,14 +216,15 @@
@Override
public String getType(Uri uri) {
- getAndEnforceUserId(uri);
+ validateIncomingUri(uri);
uri = getUriWithoutUserId(uri);
return ContentProvider.this.getType(uri);
}
@Override
public Uri insert(String callingPkg, Uri uri, ContentValues initialValues) {
- int userId = getAndEnforceUserId(uri);
+ validateIncomingUri(uri);
+ int userId = getUserIdFromUri(uri);
uri = getUriWithoutUserId(uri);
if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return rejectInsert(uri, initialValues);
@@ -233,7 +239,7 @@
@Override
public int bulkInsert(String callingPkg, Uri uri, ContentValues[] initialValues) {
- getAndEnforceUserId(uri);
+ validateIncomingUri(uri);
uri = getUriWithoutUserId(uri);
if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return 0;
@@ -254,20 +260,22 @@
final int[] userIds = new int[numOperations];
for (int i = 0; i < numOperations; i++) {
ContentProviderOperation operation = operations.get(i);
- userIds[i] = getAndEnforceUserId(operation.getUri());
+ Uri uri = operation.getUri();
+ validateIncomingUri(uri);
+ userIds[i] = getUserIdFromUri(uri);
if (userIds[i] != UserHandle.USER_CURRENT) {
// Removing the user id from the uri.
operation = new ContentProviderOperation(operation, true);
operations.set(i, operation);
}
if (operation.isReadOperation()) {
- if (enforceReadPermission(callingPkg, operation.getUri())
+ if (enforceReadPermission(callingPkg, uri)
!= AppOpsManager.MODE_ALLOWED) {
throw new OperationApplicationException("App op not allowed", 0);
}
}
if (operation.isWriteOperation()) {
- if (enforceWritePermission(callingPkg, operation.getUri())
+ if (enforceWritePermission(callingPkg, uri)
!= AppOpsManager.MODE_ALLOWED) {
throw new OperationApplicationException("App op not allowed", 0);
}
@@ -290,7 +298,7 @@
@Override
public int delete(String callingPkg, Uri uri, String selection, String[] selectionArgs) {
- getAndEnforceUserId(uri);
+ validateIncomingUri(uri);
uri = getUriWithoutUserId(uri);
if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return 0;
@@ -306,7 +314,7 @@
@Override
public int update(String callingPkg, Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
- getAndEnforceUserId(uri);
+ validateIncomingUri(uri);
uri = getUriWithoutUserId(uri);
if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return 0;
@@ -323,7 +331,7 @@
public ParcelFileDescriptor openFile(
String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal)
throws FileNotFoundException {
- getAndEnforceUserId(uri);
+ validateIncomingUri(uri);
uri = getUriWithoutUserId(uri);
enforceFilePermission(callingPkg, uri, mode);
final String original = setCallingPackage(callingPkg);
@@ -339,7 +347,7 @@
public AssetFileDescriptor openAssetFile(
String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal)
throws FileNotFoundException {
- getAndEnforceUserId(uri);
+ validateIncomingUri(uri);
uri = getUriWithoutUserId(uri);
enforceFilePermission(callingPkg, uri, mode);
final String original = setCallingPackage(callingPkg);
@@ -363,7 +371,7 @@
@Override
public String[] getStreamTypes(Uri uri, String mimeTypeFilter) {
- getAndEnforceUserId(uri);
+ validateIncomingUri(uri);
uri = getUriWithoutUserId(uri);
return ContentProvider.this.getStreamTypes(uri, mimeTypeFilter);
}
@@ -371,7 +379,7 @@
@Override
public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri uri, String mimeType,
Bundle opts, ICancellationSignal cancellationSignal) throws FileNotFoundException {
- getAndEnforceUserId(uri);
+ validateIncomingUri(uri);
uri = getUriWithoutUserId(uri);
enforceFilePermission(callingPkg, uri, "r");
final String original = setCallingPackage(callingPkg);
@@ -390,7 +398,8 @@
@Override
public Uri canonicalize(String callingPkg, Uri uri) {
- int userId = getAndEnforceUserId(uri);
+ validateIncomingUri(uri);
+ int userId = getUserIdFromUri(uri);
uri = getUriWithoutUserId(uri);
if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return null;
@@ -405,7 +414,8 @@
@Override
public Uri uncanonicalize(String callingPkg, Uri uri) {
- int userId = getAndEnforceUserId(uri);
+ validateIncomingUri(uri);
+ int userId = getUserIdFromUri(uri);
uri = getUriWithoutUserId(uri);
if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return null;
@@ -620,6 +630,36 @@
}
/**
+ * Change the authorities of the ContentProvider.
+ * This is normally set for you from its manifest information when the provider is first
+ * created.
+ * @hide
+ * @param authorities the semi-colon separated authorities of the ContentProvider.
+ */
+ protected final void setAuthorities(String authorities) {
+ if (authorities.indexOf(';') == -1) {
+ mAuthority = authorities;
+ mAuthorities = null;
+ } else {
+ mAuthority = null;
+ mAuthorities = authorities.split(";");
+ }
+ }
+
+ /** @hide */
+ protected final boolean matchesOurAuthorities(String authority) {
+ if (mAuthority != null) {
+ return mAuthority.equals(authority);
+ }
+ int length = mAuthorities.length;
+ for (int i = 0; i < length; i++) {
+ if (mAuthorities[i].equals(authority)) return true;
+ }
+ return false;
+ }
+
+
+ /**
* Change the permission required to read data from the content
* provider. This is normally set for you from its manifest information
* when the provider is first created.
@@ -1634,6 +1674,7 @@
setWritePermission(info.writePermission);
setPathPermissions(info.pathPermissions);
mExported = info.exported;
+ setAuthorities(info.authority);
}
ContentProvider.this.onCreate();
}
@@ -1727,14 +1768,25 @@
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
writer.println("nothing to dump");
}
+
/** @hide */
- private int getAndEnforceUserId(Uri uri) {
- int userId = getUserIdFromUri(uri, UserHandle.USER_CURRENT);
+ private void validateIncomingUri(Uri uri) throws SecurityException {
+ String auth = uri.getAuthority();
+ int userId = getUserIdFromAuthority(auth, UserHandle.USER_CURRENT);
if (userId != UserHandle.USER_CURRENT && userId != mContext.getUserId()) {
throw new SecurityException("trying to query a ContentProvider in user "
- + mContext.getUserId() + "with a uri belonging to user " + userId);
+ + mContext.getUserId() + " with a uri belonging to user " + userId);
}
- return userId;
+ if (!matchesOurAuthorities(getAuthorityWithoutUserId(auth))) {
+ String message = "The authority of the uri " + uri + " does not match the one of the "
+ + "contentProvider: ";
+ if (mAuthority != null) {
+ message += mAuthority;
+ } else {
+ message += mAuthorities;
+ }
+ throw new SecurityException(message);
+ }
}
/** @hide */