diff options
Diffstat (limited to 'core/java/android/content/ContentProvider.java')
-rw-r--r-- | core/java/android/content/ContentProvider.java | 144 |
1 files changed, 117 insertions, 27 deletions
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index 4c7a9d3..5b29b97 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -17,6 +17,7 @@ package android.content; import android.content.pm.PackageManager; +import android.content.pm.PathPermission; import android.content.pm.ProviderInfo; import android.content.res.AssetFileDescriptor; import android.content.res.Configuration; @@ -29,6 +30,7 @@ import android.database.SQLException; import android.net.Uri; import android.os.Binder; import android.os.ParcelFileDescriptor; +import android.os.Process; import java.io.File; import java.io.FileNotFoundException; @@ -66,8 +68,10 @@ import java.util.ArrayList; */ public abstract class ContentProvider implements ComponentCallbacks { private Context mContext = null; + private int mMyUid; private String mReadPermission; private String mWritePermission; + private PathPermission[] mPathPermissions; private Transport mTransport = new Transport(); @@ -109,31 +113,27 @@ public abstract class ContentProvider implements ComponentCallbacks { public IBulkCursor bulkQuery(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder, IContentObserver observer, CursorWindow window) { - checkReadPermission(uri); + enforceReadPermission(uri); Cursor cursor = ContentProvider.this.query(uri, projection, selection, selectionArgs, sortOrder); if (cursor == null) { return null; } - String wperm = getWritePermission(); return new CursorToBulkCursorAdaptor(cursor, observer, ContentProvider.this.getClass().getName(), - wperm == null || - getContext().checkCallingOrSelfPermission(getWritePermission()) - == PackageManager.PERMISSION_GRANTED, - window); + hasWritePermission(uri), window); } public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { - checkReadPermission(uri); + enforceReadPermission(uri); return ContentProvider.this.query(uri, projection, selection, selectionArgs, sortOrder); } public EntityIterator queryEntities(Uri uri, String selection, String[] selectionArgs, String sortOrder) { - checkReadPermission(uri); + enforceReadPermission(uri); return ContentProvider.this.queryEntities(uri, selection, selectionArgs, sortOrder); } @@ -143,17 +143,17 @@ public abstract class ContentProvider implements ComponentCallbacks { public Uri insert(Uri uri, ContentValues initialValues) { - checkWritePermission(uri); + enforceWritePermission(uri); return ContentProvider.this.insert(uri, initialValues); } public int bulkInsert(Uri uri, ContentValues[] initialValues) { - checkWritePermission(uri); + enforceWritePermission(uri); return ContentProvider.this.bulkInsert(uri, initialValues); } public Uri insertEntity(Uri uri, Entity entities) { - checkWritePermission(uri); + enforceWritePermission(uri); return ContentProvider.this.insertEntity(uri, entities); } @@ -161,55 +161,84 @@ public abstract class ContentProvider implements ComponentCallbacks { throws OperationApplicationException { for (ContentProviderOperation operation : operations) { if (operation.isReadOperation()) { - checkReadPermission(operation.getUri()); + enforceReadPermission(operation.getUri()); } if (operation.isWriteOperation()) { - checkWritePermission(operation.getUri()); + enforceWritePermission(operation.getUri()); } } return ContentProvider.this.applyBatch(operations); } public int delete(Uri uri, String selection, String[] selectionArgs) { - checkWritePermission(uri); + enforceWritePermission(uri); return ContentProvider.this.delete(uri, selection, selectionArgs); } public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - checkWritePermission(uri); + enforceWritePermission(uri); return ContentProvider.this.update(uri, values, selection, selectionArgs); } public int updateEntity(Uri uri, Entity entity) { - checkWritePermission(uri); + enforceWritePermission(uri); return ContentProvider.this.updateEntity(uri, entity); } public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { - if (mode != null && mode.startsWith("rw")) checkWritePermission(uri); - else checkReadPermission(uri); + if (mode != null && mode.startsWith("rw")) enforceWritePermission(uri); + else enforceReadPermission(uri); return ContentProvider.this.openFile(uri, mode); } public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException { - if (mode != null && mode.startsWith("rw")) checkWritePermission(uri); - else checkReadPermission(uri); + if (mode != null && mode.startsWith("rw")) enforceWritePermission(uri); + else enforceReadPermission(uri); return ContentProvider.this.openAssetFile(uri, mode); } - private void checkReadPermission(Uri uri) { + private void enforceReadPermission(Uri uri) { + final int uid = Binder.getCallingUid(); + if (uid == mMyUid) { + return; + } + + final Context context = getContext(); final String rperm = getReadPermission(); final int pid = Binder.getCallingPid(); - final int uid = Binder.getCallingUid(); - if (getContext().checkUriPermission(uri, rperm, null, pid, uid, + if (rperm == null + || context.checkPermission(rperm, pid, uid) + == PackageManager.PERMISSION_GRANTED) { + return; + } + + PathPermission[] pps = getPathPermissions(); + if (pps != null) { + final String path = uri.getPath(); + int i = pps.length; + while (i > 0) { + i--; + final PathPermission pp = pps[i]; + final String pprperm = pp.getReadPermission(); + if (pprperm != null && pp.match(path)) { + if (context.checkPermission(pprperm, pid, uid) + == PackageManager.PERMISSION_GRANTED) { + return; + } + } + } + } + + if (context.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION) == PackageManager.PERMISSION_GRANTED) { return; } + String msg = "Permission Denial: reading " + ContentProvider.this.getClass().getName() + " uri " + uri + " from pid=" + Binder.getCallingPid() @@ -218,20 +247,57 @@ public abstract class ContentProvider implements ComponentCallbacks { throw new SecurityException(msg); } - private void checkWritePermission(Uri uri) { + private boolean hasWritePermission(Uri uri) { + final int uid = Binder.getCallingUid(); + if (uid == mMyUid) { + return true; + } + + final Context context = getContext(); final String wperm = getWritePermission(); final int pid = Binder.getCallingPid(); - final int uid = Binder.getCallingUid(); - if (getContext().checkUriPermission(uri, null, wperm, pid, uid, + if (wperm == null + || context.checkPermission(wperm, pid, uid) + == PackageManager.PERMISSION_GRANTED) { + return true; + } + + PathPermission[] pps = getPathPermissions(); + if (pps != null) { + final String path = uri.getPath(); + int i = pps.length; + while (i > 0) { + i--; + final PathPermission pp = pps[i]; + final String ppwperm = pp.getWritePermission(); + if (ppwperm != null && pp.match(path)) { + if (context.checkPermission(ppwperm, pid, uid) + == PackageManager.PERMISSION_GRANTED) { + return true; + } + } + } + } + + if (context.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == PackageManager.PERMISSION_GRANTED) { + return true; + } + + return false; + } + + private void enforceWritePermission(Uri uri) { + if (hasWritePermission(uri)) { return; } + String msg = "Permission Denial: writing " + ContentProvider.this.getClass().getName() + " uri " + uri + " from pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() - + " requires " + wperm; + + " requires " + getWritePermission(); throw new SecurityException(msg); } } @@ -291,6 +357,28 @@ public abstract class ContentProvider implements ComponentCallbacks { } /** + * Change the path-based permission required to read and/or write data in + * the content provider. This is normally set for you from its manifest + * information when the provider is first created. + * + * @param permissions Array of path permission descriptions. + */ + protected final void setPathPermissions(PathPermission[] permissions) { + mPathPermissions = permissions; + } + + /** + * Return the path-based permissions required for read and/or write access to + * this content provider. This method can be called from multiple + * threads, as described in + * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals: + * Processes and Threads</a>. + */ + public final PathPermission[] getPathPermissions() { + return mPathPermissions; + } + + /** * Called when the provider is being started. * * @return true if the provider was successfully loaded, false otherwise @@ -625,9 +713,11 @@ public abstract class ContentProvider implements ComponentCallbacks { */ if (mContext == null) { mContext = context; + mMyUid = Process.myUid(); if (info != null) { setReadPermission(info.readPermission); setWritePermission(info.writePermission); + setPathPermissions(info.pathPermissions); } ContentProvider.this.onCreate(); } |