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

Commit ce774071 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "StrictMode to catch storage while locked."

parents 41cebf51 dd02e334
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -33210,6 +33210,7 @@ package android.os {
    method public android.os.StrictMode.VmPolicy.Builder detectAll();
    method public android.os.StrictMode.VmPolicy.Builder detectCleartextNetwork();
    method public android.os.StrictMode.VmPolicy.Builder detectContentUriWithoutPermission();
    method public android.os.StrictMode.VmPolicy.Builder detectCredentialProtectedWhileLocked();
    method public android.os.StrictMode.VmPolicy.Builder detectFileUriExposure();
    method public android.os.StrictMode.VmPolicy.Builder detectImplicitDirectBoot();
    method public android.os.StrictMode.VmPolicy.Builder detectLeakedClosableObjects();
@@ -33613,6 +33614,9 @@ package android.os.strictmode {
  public final class ContentUriWithoutPermissionViolation extends android.os.strictmode.Violation {
  }
  public final class CredentialProtectedWhileLockedViolation extends android.os.strictmode.Violation {
  }
  public final class CustomViolation extends android.os.strictmode.Violation {
  }
+7 −1
Original line number Diff line number Diff line
@@ -80,6 +80,8 @@ import android.view.autofill.AutofillManager.AutofillClient;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;

import dalvik.system.BlockGuard;

import libcore.io.Memory;

import java.io.File;
@@ -2521,7 +2523,11 @@ class ContextImpl extends Context {

    private File makeFilename(File base, String name) {
        if (name.indexOf(File.separatorChar) < 0) {
            return new File(base, name);
            final File res = new File(base, name);
            // We report as filesystem access here to give us the best shot at
            // detecting apps that will pass the path down to native code.
            BlockGuard.getVmPolicy().onPathAccess(res.getPath());
            return res;
        }
        throw new IllegalArgumentException(
                "File " + name + " contains a path separator");
+2 −0
Original line number Diff line number Diff line
@@ -33,6 +33,8 @@ import java.util.LinkedList;
public class Environment {
    private static final String TAG = "Environment";

    // NOTE: keep credential-protected paths in sync with StrictMode.java

    private static final String ENV_EXTERNAL_STORAGE = "EXTERNAL_STORAGE";
    private static final String ENV_ANDROID_ROOT = "ANDROID_ROOT";
    private static final String ENV_ANDROID_DATA = "ANDROID_DATA";
+110 −0
Original line number Diff line number Diff line
@@ -31,8 +31,10 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.net.TrafficStats;
import android.net.Uri;
import android.os.storage.IStorageManager;
import android.os.strictmode.CleartextNetworkViolation;
import android.os.strictmode.ContentUriWithoutPermissionViolation;
import android.os.strictmode.CredentialProtectedWhileLockedViolation;
import android.os.strictmode.CustomViolation;
import android.os.strictmode.DiskReadViolation;
import android.os.strictmode.DiskWriteViolation;
@@ -284,6 +286,8 @@ public final class StrictMode {
    private static final int DETECT_VM_NON_SDK_API_USAGE = 1 << 9;
    /** @hide */
    private static final int DETECT_VM_IMPLICIT_DIRECT_BOOT = 1 << 10;
    /** @hide */
    private static final int DETECT_VM_CREDENTIAL_PROTECTED_WHILE_LOCKED = 1 << 11;

    /** @hide */
    private static final int DETECT_VM_ALL = 0x0000ffff;
@@ -860,6 +864,9 @@ public final class StrictMode {
                    detectContentUriWithoutPermission();
                    detectUntaggedSockets();
                }
                if (targetSdk >= Build.VERSION_CODES.Q) {
                    detectCredentialProtectedWhileLocked();
                }

                // TODO: Decide whether to detect non SDK API usage beyond a certain API level.
                // TODO: enable detectImplicitDirectBoot() once system is less noisy
@@ -994,6 +1001,28 @@ public final class StrictMode {
                return disable(DETECT_VM_IMPLICIT_DIRECT_BOOT);
            }

            /**
             * Detect access to filesystem paths stored in credential protected
             * storage areas while the user is locked.
             * <p>
             * When a user is locked, credential protected storage is
             * unavailable, and files stored in these locations appear to not
             * exist, which can result in subtle app bugs if they assume default
             * behaviors or empty states. Instead, apps should store data needed
             * while a user is locked under device protected storage areas.
             *
             * @see Context#createCredentialProtectedStorageContext()
             * @see Context#createDeviceProtectedStorageContext()
             */
            public Builder detectCredentialProtectedWhileLocked() {
                return enable(DETECT_VM_CREDENTIAL_PROTECTED_WHILE_LOCKED);
            }

            /** @hide */
            public Builder permitCredentialProtectedWhileLocked() {
                return disable(DETECT_VM_CREDENTIAL_PROTECTED_WHILE_LOCKED);
            }

            /**
             * Crashes the whole process on violation. This penalty runs at the end of all enabled
             * penalties so you'll still get your logging or other violations before the process
@@ -1155,6 +1184,16 @@ public final class StrictMode {
        androidPolicy.setThreadPolicyMask(threadPolicyMask);
    }

    private static void setBlockGuardVmPolicy(@VmPolicyMask int vmPolicyMask) {
        // We only need to install BlockGuard for a small subset of VM policies
        vmPolicyMask &= DETECT_VM_CREDENTIAL_PROTECTED_WHILE_LOCKED;
        if (vmPolicyMask != 0) {
            BlockGuard.setVmPolicy(VM_ANDROID_POLICY);
        } else {
            BlockGuard.setVmPolicy(BlockGuard.LAX_VM_POLICY);
        }
    }

    // Sets up CloseGuard in Dalvik/libcore
    private static void setCloseGuardEnabled(boolean enabled) {
        if (!(CloseGuard.getReporter() instanceof AndroidCloseGuardReporter)) {
@@ -1742,6 +1781,34 @@ public final class StrictMode {
        }
    }

    private static final BlockGuard.VmPolicy VM_ANDROID_POLICY = new BlockGuard.VmPolicy() {
        @Override
        public void onPathAccess(String path) {
            if (path == null) return;

            // NOTE: keep credential-protected paths in sync with Environment.java
            if (path.startsWith("/data/user/")
                    || path.startsWith("/data/media/")
                    || path.startsWith("/data/system_ce/")
                    || path.startsWith("/data/misc_ce/")
                    || path.startsWith("/data/vendor_ce/")
                    || path.startsWith("/storage/emulated/")) {
                final int second = path.indexOf('/', 1);
                final int third = path.indexOf('/', second + 1);
                final int fourth = path.indexOf('/', third + 1);
                if (fourth == -1) return;

                try {
                    final int userId = Integer.parseInt(path.substring(third + 1, fourth));
                    onCredentialProtectedPathAccess(path, userId);
                } catch (NumberFormatException ignored) {
                }
            } else if (path.startsWith("/data/data/")) {
                onCredentialProtectedPathAccess(path, UserHandle.USER_SYSTEM);
            }
        }
    };

    /**
     * In the common case, as set by conditionallyEnableDebugLogging, we're just dropboxing any
     * violations but not showing a dialog, not loggging, and not killing the process. In these
@@ -1909,6 +1976,8 @@ public final class StrictMode {
                VMRuntime.setNonSdkApiUsageConsumer(null);
                VMRuntime.setDedupeHiddenApiWarnings(true);
            }

            setBlockGuardVmPolicy(sVmPolicy.mask);
        }
    }

@@ -1971,6 +2040,11 @@ public final class StrictMode {
        return (sVmPolicy.mask & DETECT_VM_IMPLICIT_DIRECT_BOOT) != 0;
    }

    /** @hide */
    public static boolean vmCredentialProtectedWhileLockedEnabled() {
        return (sVmPolicy.mask & DETECT_VM_CREDENTIAL_PROTECTED_WHILE_LOCKED) != 0;
    }

    /** @hide */
    public static void onSqliteObjectLeaked(String message, Throwable originStack) {
        onVmPolicyViolation(new SqliteObjectLeakedViolation(message, originStack));
@@ -2044,6 +2118,42 @@ public final class StrictMode {
        onVmPolicyViolation(new ImplicitDirectBootViolation());
    }

    /** Assume locked until we hear otherwise */
    private static volatile boolean sUserKeyUnlocked = false;

    private static boolean isUserKeyUnlocked(int userId) {
        final IStorageManager storage = IStorageManager.Stub
                .asInterface(ServiceManager.getService("mount"));
        if (storage != null) {
            try {
                return storage.isUserKeyUnlocked(userId);
            } catch (RemoteException ignored) {
            }
        }
        return false;
    }

    /** @hide */
    private static void onCredentialProtectedPathAccess(String path, int userId) {
        // We can cache the unlocked state for the userId we're running as,
        // since any relocking of that user will always result in our
        // process being killed to release any CE FDs we're holding onto.
        if (userId == UserHandle.myUserId()) {
            if (sUserKeyUnlocked) {
                return;
            } else if (isUserKeyUnlocked(userId)) {
                sUserKeyUnlocked = true;
                return;
            }
        } else if (isUserKeyUnlocked(userId)) {
            return;
        }

        onVmPolicyViolation(new CredentialProtectedWhileLockedViolation(
                "Accessed credential protected path " + path + " while user " + userId
                        + " was locked"));
    }

    // Map from VM violation fingerprint to uptime millis.
    private static final HashMap<Integer, Long> sLastVmViolationTime = new HashMap<>();

+3 −0
Original line number Diff line number Diff line
@@ -71,6 +71,8 @@ import com.android.internal.os.RoSystemProperties;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.Preconditions;

import dalvik.system.BlockGuard;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
@@ -1131,6 +1133,7 @@ public class StorageManager {

    /** {@hide} */
    public void mkdirs(File file) {
        BlockGuard.getVmPolicy().onPathAccess(file.getAbsolutePath());
        try {
            mStorageManager.mkdirs(mContext.getOpPackageName(), file.getAbsolutePath());
        } catch (RemoteException e) {
Loading