Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 53b7e93c authored by Jeff Sharkey's avatar Jeff Sharkey Committed by Android (Google) Code Review
Browse files

Merge "Apps using storage must have runtime permission."

parents 29842a92 6fd6994c
Loading
Loading
Loading
Loading
+11 −7
Original line number Diff line number Diff line
@@ -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.
+75 −31
Original line number Diff line number Diff line
@@ -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,23 +3868,67 @@ 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) {
            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;
            } 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) {
            }

            // 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;
            } else if (mPmInternal.isInstantApp(packageName, UserHandle.getUserId(uid))) {
                return Zygote.MOUNT_EXTERNAL_NONE;
            }

            // 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 {
                return Zygote.MOUNT_EXTERNAL_WRITE;
            }
        } catch (RemoteException e) {
            // Should not happen
        }
        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
@@ -3898,15 +3947,10 @@ class StorageManagerService extends IStorageManager.Stub
                case "ak.alizandro.smartaudiobookplayer": // b/129084042
                case "com.campmobile.snow": // b/128803870
                case "com.qnap.qfile": // b/126374406
                            return Zygote.MOUNT_EXTERNAL_LEGACY;
                    }
                    return true;
            }
                return Zygote.MOUNT_EXTERNAL_WRITE;
        }
        } catch (RemoteException e) {
            // Should not happen
        }
        return Zygote.MOUNT_EXTERNAL_NONE;
        return false;
    }

    private static class Callbacks extends Handler {