Merge "Apps using storage must have runtime permission."

This commit is contained in:
Jeff Sharkey
2019-03-27 19:56:51 +00:00
committed by Android (Google) Code Review
2 changed files with 87 additions and 39 deletions

View File

@@ -135,6 +135,7 @@ import java.util.concurrent.atomic.AtomicInteger;
@SystemService(Context.STORAGE_SERVICE)
public class StorageManager {
private static final String TAG = "StorageManager";
private static final boolean LOCAL_LOGV = Log.isLoggable(TAG, Log.VERBOSE);
/** {@hide} */
public static final String PROP_PRIMARY_PHYSICAL = "ro.vold.primary_physical";
@@ -1652,13 +1653,11 @@ public class StorageManager {
/**
* Check that given app holds both permission and appop.
*
* @return {@code null} if the permission and appop are held, otherwise
* returns a string indicating why access was denied.
* @hide
*/
private boolean checkPermissionAndAppOp(boolean enforce, int pid, int uid, String packageName,
String permission, int op) {
if (mContext.checkPermission(permission, pid, uid) != PERMISSION_GRANTED) {
public static boolean checkPermissionAndAppOp(Context context, boolean enforce,
int pid, int uid, String packageName, String permission, int op) {
if (context.checkPermission(permission, pid, uid) != PERMISSION_GRANTED) {
if (enforce) {
throw new SecurityException(
"Permission " + permission + " denied for package " + packageName);
@@ -1667,7 +1666,7 @@ public class StorageManager {
}
}
final AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
final AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
final int mode = appOps.noteOpNoThrow(op, uid, packageName);
switch (mode) {
case AppOpsManager.MODE_ALLOWED:
@@ -1688,6 +1687,11 @@ public class StorageManager {
}
}
private boolean checkPermissionAndAppOp(boolean enforce,
int pid, int uid, String packageName, String permission, int op) {
return checkPermissionAndAppOp(mContext, enforce, pid, uid, packageName, permission, op);
}
// Callers must hold both the old and new permissions, so that we can
// handle obscure cases like when an app targets Q but was installed on
// a device that was originally running on P before being upgraded to Q.

View File

@@ -17,10 +17,14 @@
package com.android.server;
import static android.Manifest.permission.INSTALL_PACKAGES;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
import static android.Manifest.permission.WRITE_MEDIA_STORAGE;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.OP_LEGACY_STORAGE;
import static android.app.AppOpsManager.OP_READ_EXTERNAL_STORAGE;
import static android.app.AppOpsManager.OP_REQUEST_INSTALL_PACKAGES;
import static android.app.AppOpsManager.OP_WRITE_EXTERNAL_STORAGE;
import static android.content.pm.PackageManager.FLAG_PERMISSION_HIDDEN;
import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
@@ -280,6 +284,7 @@ class StorageManagerService extends IStorageManager.Stub
private static final boolean EMULATE_FBE_SUPPORTED = true;
private static final String TAG = "StorageManagerService";
private static final boolean LOCAL_LOGV = Log.isLoggable(TAG, Log.VERBOSE);
private static final String TAG_STORAGE_BENCHMARK = "storage_benchmark";
private static final String TAG_STORAGE_TRIM = "storage_trim";
@@ -3863,44 +3868,57 @@ class StorageManagerService extends IStorageManager.Stub
}
private int getMountMode(int uid, String packageName) {
final int mode = getMountModeInternal(uid, packageName);
if (LOCAL_LOGV) {
Slog.v(TAG, "Resolved mode " + mode + " for " + packageName + "/"
+ UserHandle.formatUid(uid));
}
return mode;
}
private int getMountModeInternal(int uid, String packageName) {
try {
// Get some easy cases out of the way first
if (Process.isIsolated(uid)) {
return Zygote.MOUNT_EXTERNAL_NONE;
}
if (mIPackageManager.checkUidPermission(WRITE_MEDIA_STORAGE, uid)
== PERMISSION_GRANTED) {
return Zygote.MOUNT_EXTERNAL_FULL;
} else if (mIAppOpsService.checkOperation(OP_LEGACY_STORAGE, uid,
packageName) == MODE_ALLOWED) {
return Zygote.MOUNT_EXTERNAL_LEGACY;
} else if (mIPackageManager.checkUidPermission(INSTALL_PACKAGES, uid)
== PERMISSION_GRANTED || mIAppOpsService.checkOperation(
OP_REQUEST_INSTALL_PACKAGES, uid, packageName) == MODE_ALLOWED) {
return Zygote.MOUNT_EXTERNAL_INSTALLER;
} else if (mPmInternal.isInstantApp(packageName, UserHandle.getUserId(uid))) {
if (mPmInternal.isInstantApp(packageName, UserHandle.getUserId(uid))) {
return Zygote.MOUNT_EXTERNAL_NONE;
}
// Determine if caller is holding runtime permission
final boolean hasRead = StorageManager.checkPermissionAndAppOp(mContext, false, 0,
uid, packageName, READ_EXTERNAL_STORAGE, OP_READ_EXTERNAL_STORAGE);
final boolean hasWrite = StorageManager.checkPermissionAndAppOp(mContext, false, 0,
uid, packageName, WRITE_EXTERNAL_STORAGE, OP_WRITE_EXTERNAL_STORAGE);
final boolean hasStorage = hasRead || hasWrite;
// We're only willing to give out broad access if they also hold
// runtime permission; this is a firm CDD requirement
final boolean hasFull = mIPackageManager.checkUidPermission(WRITE_MEDIA_STORAGE,
uid) == PERMISSION_GRANTED;
if (hasFull && hasStorage) {
return Zygote.MOUNT_EXTERNAL_FULL;
}
// We're only willing to give out installer access if they also hold
// runtime permission; this is a firm CDD requirement
final boolean hasInstall = mIPackageManager.checkUidPermission(INSTALL_PACKAGES,
uid) == PERMISSION_GRANTED;
final boolean hasInstallOp = mIAppOpsService.checkOperation(OP_REQUEST_INSTALL_PACKAGES,
uid, packageName) == MODE_ALLOWED;
if ((hasInstall || hasInstallOp) && hasStorage) {
return Zygote.MOUNT_EXTERNAL_INSTALLER;
}
// Otherwise we're willing to give out sandboxed or non-sandboxed if
// they hold the runtime permission
final boolean hasLegacy = mIAppOpsService.checkOperation(OP_LEGACY_STORAGE,
uid, packageName) == MODE_ALLOWED;
final boolean hasGreylist = isLegacyGreylisted(packageName);
if ((hasLegacy || hasGreylist) && hasStorage) {
return Zygote.MOUNT_EXTERNAL_LEGACY;
} else {
if (ENABLE_LEGACY_GREYLIST) {
// STOPSHIP: remove this temporary workaround once developers
// fix bugs where they're opening _data paths in native code
switch (packageName) {
case "com.facebook.katana": // b/123996076
case "jp.naver.line.android": // b/124767356
case "com.mxtech.videoplayer.ad": // b/124531483
case "com.whatsapp": // b/124766614
case "com.maxmpz.audioplayer": // b/127886230
case "com.estrongs.android.pop": // b/127926473
case "com.roidapp.photogrid": // b/128269119
case "com.cleanmaster.mguard": // b/128384413
case "com.skype.raider": // b/128487044
case "org.telegram.messenger": // b/128652960
case "com.jrtstudio.AnotherMusicPlayer": // b/129084562
case "ak.alizandro.smartaudiobookplayer": // b/129084042
case "com.campmobile.snow": // b/128803870
case "com.qnap.qfile": // b/126374406
return Zygote.MOUNT_EXTERNAL_LEGACY;
}
}
return Zygote.MOUNT_EXTERNAL_WRITE;
}
} catch (RemoteException e) {
@@ -3909,6 +3927,32 @@ class StorageManagerService extends IStorageManager.Stub
return Zygote.MOUNT_EXTERNAL_NONE;
}
private boolean isLegacyGreylisted(String packageName) {
// TODO: decide legacy defaults at install time based on signals
if (ENABLE_LEGACY_GREYLIST) {
// STOPSHIP: remove this temporary workaround once developers
// fix bugs where they're opening _data paths in native code
switch (packageName) {
case "com.facebook.katana": // b/123996076
case "jp.naver.line.android": // b/124767356
case "com.mxtech.videoplayer.ad": // b/124531483
case "com.whatsapp": // b/124766614
case "com.maxmpz.audioplayer": // b/127886230
case "com.estrongs.android.pop": // b/127926473
case "com.roidapp.photogrid": // b/128269119
case "com.cleanmaster.mguard": // b/128384413
case "com.skype.raider": // b/128487044
case "org.telegram.messenger": // b/128652960
case "com.jrtstudio.AnotherMusicPlayer": // b/129084562
case "ak.alizandro.smartaudiobookplayer": // b/129084042
case "com.campmobile.snow": // b/128803870
case "com.qnap.qfile": // b/126374406
return true;
}
}
return false;
}
private static class Callbacks extends Handler {
private static final int MSG_STORAGE_STATE_CHANGED = 1;
private static final int MSG_VOLUME_STATE_CHANGED = 2;