summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Sharkey <jsharkey@android.com>2016-09-16 12:12:17 -0600
committerJessica Wagantall <jwagantall@cyngn.com>2016-11-16 15:19:44 -0700
commit53b9b1b1e105961b8c207ebe208f9d09a676ec48 (patch)
tree62c0a05b2884e9af8bfd5041afb46e5e201fdef0
parente2092b0fd4b706e3d575d6e225a1ecbc71dabb8f (diff)
downloadandroid_packages_providers_DownloadProvider-stable/cm-12.1-YOG7D.tar.gz
android_packages_providers_DownloadProvider-stable/cm-12.1-YOG7D.tar.bz2
android_packages_providers_DownloadProvider-stable/cm-12.1-YOG7D.zip
Enforce calling identity before clearing.stable/cm-12.1-YOG7D
When opening a downloaded file, enforce that the caller can actually see the requested download before clearing their identity to read internal columns. However, this means that we can no longer return the "my_downloads" paths: if those Uris were shared beyond the app that requested the download, access would be denied. Instead, we need to switch to using "all_downloads" Uris so that permission grants can be issued to third-party viewer apps. Since an app requesting a download doesn't normally have permission to "all_downloads" paths, we issue narrow grants toward the owner of each download, both at device boot and when new downloads are started. CYNGNOS-3303 Bug: 30537115, 30945409 Change-Id: If944aada020878a91c363963728d0da9f6fae3ea (cherry picked from commit 7c1af8c62c8bdf6e8de5a00c1927daf9fd9c03d1) (cherry picked from commit 2e51b3279a3b1e7cbd467c81bfe09b431b248cab)
-rw-r--r--src/com/android/providers/downloads/DownloadProvider.java44
1 files changed, 44 insertions, 0 deletions
diff --git a/src/com/android/providers/downloads/DownloadProvider.java b/src/com/android/providers/downloads/DownloadProvider.java
index 2d914c41..87084130 100644
--- a/src/com/android/providers/downloads/DownloadProvider.java
+++ b/src/com/android/providers/downloads/DownloadProvider.java
@@ -458,6 +458,19 @@ public final class DownloadProvider extends ContentProvider {
if (appInfo != null) {
mDefContainerUid = appInfo.uid;
}
+
+ // Grant access permissions for all known downloads to the owning apps
+ final SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+ final Cursor cursor = db.query(DB_TABLE, new String[] {
+ Downloads.Impl._ID, Constants.UID }, null, null, null, null, null);
+ try {
+ while (cursor.moveToNext()) {
+ grantAllDownloadsPermission(cursor.getLong(0), cursor.getInt(1));
+ }
+ } finally {
+ cursor.close();
+ }
+
// start the DownloadService class. don't wait for the 1st download to be issued.
// saves us by getting some initialization code in DownloadService out of the way.
Context context = getContext();
@@ -675,6 +688,7 @@ public final class DownloadProvider extends ContentProvider {
}
insertRequestHeaders(db, rowID, values);
+ grantAllDownloadsPermission(rowID, Binder.getCallingUid());
notifyContentChanged(uri, match);
// Always start service to handle notifications and/or scanning
@@ -1166,6 +1180,7 @@ public final class DownloadProvider extends ContentProvider {
try {
while (cursor.moveToNext()) {
final long id = cursor.getLong(0);
+ revokeAllDownloadsPermission(id);
DownloadStorageProvider.onDownloadProviderDelete(getContext(), id);
}
} finally {
@@ -1192,6 +1207,19 @@ public final class DownloadProvider extends ContentProvider {
logVerboseOpenFileInfo(uri, mode);
}
+ // Perform normal query to enforce caller identity access before
+ // clearing it to reach internal-only columns
+ final Cursor probeCursor = query(uri, new String[] {
+ Downloads.Impl._DATA }, null, null, null);
+ try {
+ if ((probeCursor == null) || (probeCursor.getCount() == 0)) {
+ throw new FileNotFoundException(
+ "No file found for " + uri + " as UID " + Binder.getCallingUid());
+ }
+ } finally {
+ IoUtils.closeQuietly(probeCursor);
+ }
+
final Cursor cursor = queryCleared(uri, new String[] {
Downloads.Impl._DATA, Downloads.Impl.COLUMN_STATUS,
Downloads.Impl.COLUMN_DESTINATION, Downloads.Impl.COLUMN_MEDIA_SCANNED }, null,
@@ -1373,4 +1401,20 @@ public final class DownloadProvider extends ContentProvider {
to.put(key, defaultValue);
}
}
+
+ private void grantAllDownloadsPermission(long id, int uid) {
+ final String[] packageNames = getContext().getPackageManager().getPackagesForUid(uid);
+ if (packageNames == null || packageNames.length == 0) return;
+
+ // We only need to grant to the first package, since the
+ // platform internally tracks based on UIDs
+ final Uri uri = ContentUris.withAppendedId(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, id);
+ getContext().grantUriPermission(packageNames[0], uri,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ }
+
+ private void revokeAllDownloadsPermission(long id) {
+ final Uri uri = ContentUris.withAppendedId(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, id);
+ getContext().revokeUriPermission(uri, ~0);
+ }
}