From 8ad60457381e6911199c692ce01916f56d2c07cc Mon Sep 17 00:00:00 2001 From: Suprabh Shukla Date: Mon, 27 Feb 2017 15:56:11 -0800 Subject: DO NOT MERGE Deleting downloads for removed uids on downloadprovider start After uninstalling an app, if the system was shutdown before the download provider received the broadcast for UID_REMOVED, another app installed later in the same uid might be able to gain access to the files downloaded by this app. Removing any such hanging downloads at the start up of the download provider should fix this issue. Test: Manually tested by uninstalling an app and killing and restarting the process android.process.media, to check that the downloaded files of the uninstalled app were deleted. Bug:22011579 Merged-In: I7382c4846f99035b40412a01715aee5873efa9e6 Change-Id: I7382c4846f99035b40412a01715aee5873efa9e6 --- .../providers/downloads/DownloadProvider.java | 70 +++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/src/com/android/providers/downloads/DownloadProvider.java b/src/com/android/providers/downloads/DownloadProvider.java index ee48af16..d6521d0b 100644 --- a/src/com/android/providers/downloads/DownloadProvider.java +++ b/src/com/android/providers/downloads/DownloadProvider.java @@ -460,6 +460,32 @@ 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); + final ArrayList idsToDelete = new ArrayList(); + try { + while (cursor.moveToNext()) { + final long downloadId = cursor.getLong(0); + final int uid = cursor.getInt(1); + final String ownerPackage = getPackageForUid(uid); + if (ownerPackage == null) { + idsToDelete.add(downloadId); + } else { + grantAllDownloadsPermission(ownerPackage, downloadId); + } + } + } finally { + cursor.close(); + } + if (idsToDelete.size() > 0) { + Log.i(Constants.TAG, + "Deleting downloads with ids " + idsToDelete + " as owner package is missing"); + deleteDownloadsWithIds(idsToDelete); + } + // 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(); @@ -473,6 +499,19 @@ public final class DownloadProvider extends ContentProvider { return true; } + private void deleteDownloadsWithIds(ArrayList downloadIds) { + final int N = downloadIds.size(); + if (N == 0) { + return; + } + final StringBuilder queryBuilder = new StringBuilder(Downloads.Impl._ID + " in ("); + for (int i = 0; i < N; i++) { + queryBuilder.append(downloadIds.get(i)); + queryBuilder.append((i == N - 1) ? ")" : ","); + } + delete(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, queryBuilder.toString(), null); + } + /** * Returns the content-provider-style MIME types of the various * types accessible through this content provider. @@ -683,6 +722,13 @@ public final class DownloadProvider extends ContentProvider { } insertRequestHeaders(db, rowID, values); + + final String callingPackage = getPackageForUid(Binder.getCallingUid()); + if (callingPackage == null) { + Log.e(Constants.TAG, "Package does not exist for calling uid"); + return null; + } + grantAllDownloadsPermission(callingPackage, rowID); notifyContentChanged(uri, match); // Always start service to handle notifications and/or scanning @@ -692,6 +738,15 @@ public final class DownloadProvider extends ContentProvider { return ContentUris.withAppendedId(Downloads.Impl.CONTENT_URI, rowID); } + private String getPackageForUid(int uid) { + String[] packages = getContext().getPackageManager().getPackagesForUid(uid); + if (packages == null || packages.length == 0) { + return null; + } + // For permission related purposes, any package belonging to the given uid should work. + return packages[0]; + } + /** * Check that the file URI provided for DESTINATION_FILE_URI is valid. */ @@ -1139,7 +1194,9 @@ public final class DownloadProvider extends ContentProvider { public int delete(final Uri uri, final String where, final String[] whereArgs) { - Helpers.validateSelection(where, sAppReadableColumnsSet); + if (shouldRestrictVisibility()) { + Helpers.validateSelection(where, sAppReadableColumnsSet); + } SQLiteDatabase db = mOpenHelper.getWritableDatabase(); int count; @@ -1336,4 +1393,15 @@ public final class DownloadProvider extends ContentProvider { to.put(key, defaultValue); } } + + private void grantAllDownloadsPermission(String toPackage, long id) { + final Uri uri = ContentUris.withAppendedId(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, id); + getContext().grantUriPermission(toPackage, 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); + } } -- cgit v1.2.3