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

Commit 0ad6283d authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

Protect usage data with OP_GET_USAGE_STATS.

APIs that return package usage data (such as the new ArtManager)
must ensure that callers hold both the PACKAGE_USAGE_STATS permission
and the OP_GET_USAGE_STATS app-op.

Bug: 77662908
Test: atest vendor/xts/gts-tests/hostsidetests/dexapis/host/
Change-Id: I7a85d959f1682d2bd5cf3684415e368fece88101
parent 56487413
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -2831,7 +2831,7 @@ public class ApplicationPackageManager extends PackageManager {
        synchronized (mLock) {
            if (mArtManager == null) {
                try {
                    mArtManager = new ArtManager(mPM.getArtManager());
                    mArtManager = new ArtManager(mContext, mPM.getArtManager());
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
+15 −10
Original line number Diff line number Diff line
@@ -16,12 +16,16 @@

package android.content.pm.dex;

import static android.Manifest.permission.PACKAGE_USAGE_STATS;
import static android.Manifest.permission.READ_RUNTIME_PROFILES;

import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.content.Context;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
@@ -62,13 +66,14 @@ public class ArtManager {
    @Retention(RetentionPolicy.SOURCE)
    public @interface ProfileType {}


    private IArtManager mArtManager;
    private final Context mContext;
    private final IArtManager mArtManager;

    /**
     * @hide
     */
    public ArtManager(@NonNull IArtManager manager) {
    public ArtManager(@NonNull Context context, @NonNull IArtManager manager) {
        mContext = context;
        mArtManager = manager;
    }

@@ -99,7 +104,7 @@ public class ArtManager {
     * @param callback the callback which should be used for the result
     * @param executor the executor which should be used to post the result
     */
    @RequiresPermission(android.Manifest.permission.READ_RUNTIME_PROFILES)
    @RequiresPermission(allOf = { READ_RUNTIME_PROFILES, PACKAGE_USAGE_STATS })
    public void snapshotRuntimeProfile(@ProfileType int profileType, @Nullable String packageName,
            @Nullable String codePath, @NonNull @CallbackExecutor Executor executor,
            @NonNull SnapshotRuntimeProfileCallback callback) {
@@ -108,9 +113,10 @@ public class ArtManager {
        SnapshotRuntimeProfileCallbackDelegate delegate =
                new SnapshotRuntimeProfileCallbackDelegate(callback, executor);
        try {
            mArtManager.snapshotRuntimeProfile(profileType, packageName, codePath, delegate);
            mArtManager.snapshotRuntimeProfile(profileType, packageName, codePath, delegate,
                    mContext.getOpPackageName());
        } catch (RemoteException e) {
            e.rethrowAsRuntimeException();
            throw e.rethrowAsRuntimeException();
        }
    }

@@ -122,14 +128,13 @@ public class ArtManager {
     * @param profileType can be either {@link ArtManager#PROFILE_APPS}
     *                    or {@link ArtManager#PROFILE_BOOT_IMAGE}
     */
    @RequiresPermission(android.Manifest.permission.READ_RUNTIME_PROFILES)
    @RequiresPermission(allOf = { READ_RUNTIME_PROFILES, PACKAGE_USAGE_STATS })
    public boolean isRuntimeProfilingEnabled(@ProfileType int profileType) {
        try {
            return mArtManager.isRuntimeProfilingEnabled(profileType);
            return mArtManager.isRuntimeProfilingEnabled(profileType, mContext.getOpPackageName());
        } catch (RemoteException e) {
            e.rethrowAsRuntimeException();
            throw e.rethrowAsRuntimeException();
        }
        return false;
    }

    /**
+3 −3
Original line number Diff line number Diff line
@@ -44,8 +44,8 @@ interface IArtManager {
     * {@link ArtManager#isRuntimeProfilingEnabled(int)} does not return true for the given
     * {@code profileType}.
     */
    oneway void snapshotRuntimeProfile(int profileType, in String packageName,
        in String codePath, in ISnapshotRuntimeProfileCallback callback);
    void snapshotRuntimeProfile(int profileType, in String packageName,
        in String codePath, in ISnapshotRuntimeProfileCallback callback, String callingPackage);

     /**
       * Returns true if runtime profiles are enabled for the given type, false otherwise.
@@ -54,5 +54,5 @@ interface IArtManager {
       *
       * @param profileType
       */
    boolean isRuntimeProfilingEnabled(int profileType);
    boolean isRuntimeProfilingEnabled(int profileType, String callingPackage);
}
+1 −1
Original line number Diff line number Diff line
@@ -2462,7 +2462,7 @@ public class PackageManagerService extends IPackageManager.Stub
                installer, mInstallLock);
        mDexManager = new DexManager(this, mPackageDexOptimizer, installer, mInstallLock,
                dexManagerListener);
        mArtManagerService = new ArtManagerService(this, installer, mInstallLock);
        mArtManagerService = new ArtManagerService(mContext, this, installer, mInstallLock);
        mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());
        mOnPermissionChangeListeners = new OnPermissionChangeListeners(
+49 −35
Original line number Diff line number Diff line
@@ -16,8 +16,9 @@

package com.android.server.pm.dex;

import android.Manifest;
import android.annotation.UserIdInt;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
@@ -38,7 +39,9 @@ import android.os.SystemProperties;
import android.os.UserHandle;
import android.system.Os;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.ArrayUtils;
@@ -47,14 +50,17 @@ import com.android.server.LocalServices;
import com.android.server.pm.Installer;
import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.PackageManagerServiceCompilerMapping;

import dalvik.system.DexFile;
import dalvik.system.VMRuntime;
import java.io.File;
import java.io.FileNotFoundException;

import libcore.io.IoUtils;
import libcore.util.NonNull;
import libcore.util.Nullable;

import java.io.File;
import java.io.FileNotFoundException;

/**
 * A system service that provides access to runtime and compiler artifacts.
 *
@@ -69,9 +75,7 @@ import libcore.util.Nullable;
 */
public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
    private static final String TAG = "ArtManagerService";

    private static boolean DEBUG = false;
    private static boolean DEBUG_IGNORE_PERMISSIONS = false;
    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);

    // Package name used to create the profile directory layout when
    // taking a snapshot of the boot image profile.
@@ -79,6 +83,7 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
    // Profile name used for the boot image profile.
    private static final String BOOT_IMAGE_PROFILE_NAME = "android.prof";

    private final Context mContext;
    private final IPackageManager mPackageManager;
    private final Object mInstallLock;
    @GuardedBy("mInstallLock")
@@ -90,7 +95,9 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
        verifyTronLoggingConstants();
    }

    public ArtManagerService(IPackageManager pm, Installer installer, Object installLock) {
    public ArtManagerService(Context context, IPackageManager pm, Installer installer,
            Object installLock) {
        mContext = context;
        mPackageManager = pm;
        mInstaller = installer;
        mInstallLock = installLock;
@@ -99,9 +106,37 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
        LocalServices.addService(ArtManagerInternal.class, new ArtManagerInternalImpl());
    }

    private boolean checkPermission(int callingUid, String callingPackage) {
        // Callers always need this permission
        mContext.enforceCallingOrSelfPermission(
                android.Manifest.permission.READ_RUNTIME_PROFILES, TAG);

        // Callers also need the ability to read usage statistics
        switch (mContext.getSystemService(AppOpsManager.class)
                .noteOp(AppOpsManager.OP_GET_USAGE_STATS, callingUid, callingPackage)) {
            case AppOpsManager.MODE_ALLOWED:
                return true;
            case AppOpsManager.MODE_DEFAULT:
                mContext.enforceCallingOrSelfPermission(
                        android.Manifest.permission.PACKAGE_USAGE_STATS, TAG);
                return true;
            default:
                return false;
        }
    }

    @Override
    public void snapshotRuntimeProfile(@ProfileType int profileType, @Nullable String packageName,
            @Nullable String codePath, @NonNull ISnapshotRuntimeProfileCallback callback) {
            @Nullable String codePath, @NonNull ISnapshotRuntimeProfileCallback callback,
            String callingPackage) {
        if (!checkPermission(Binder.getCallingUid(), callingPackage)) {
            try {
                callback.onError(ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
            } catch (RemoteException ignored) {
            }
            return;
        }

        // Sanity checks on the arguments.
        Preconditions.checkNotNull(callback);

@@ -111,9 +146,8 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
            Preconditions.checkStringNotEmpty(packageName);
        }

        // Verify that the caller has the right permissions and that the runtime profiling is
        // enabled. The call to isRuntimePermissions will checkReadRuntimeProfilePermission.
        if (!isRuntimeProfilingEnabled(profileType)) {
        // Verify that runtime profiling is enabled.
        if (!isRuntimeProfilingEnabled(profileType, callingPackage)) {
            throw new IllegalStateException("Runtime profiling is not enabled for " + profileType);
        }

@@ -231,9 +265,10 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
    }

    @Override
    public boolean isRuntimeProfilingEnabled(@ProfileType int profileType) {
        // Verify that the caller has the right permissions.
        checkReadRuntimeProfilePermission();
    public boolean isRuntimeProfilingEnabled(@ProfileType int profileType, String callingPackage) {
        if (!checkPermission(Binder.getCallingUid(), callingPackage)) {
            return false;
        }

        switch (profileType) {
            case ArtManager.PROFILE_APPS :
@@ -305,27 +340,6 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
        });
    }

    /**
     * Verify that the binder calling uid has {@code android.permission.READ_RUNTIME_PROFILE}.
     * If not, it throws a {@link SecurityException}.
     */
    private void checkReadRuntimeProfilePermission() {
        if (DEBUG_IGNORE_PERMISSIONS) {
            return;
        }
        try {
            int result = mPackageManager.checkUidPermission(
                    Manifest.permission.READ_RUNTIME_PROFILES, Binder.getCallingUid());
            if (result != PackageManager.PERMISSION_GRANTED) {
                throw new SecurityException("You need "
                        + Manifest.permission.READ_RUNTIME_PROFILES
                        + " permission to snapshot profiles.");
            }
        } catch (RemoteException e) {
            // Should not happen.
        }
    }

    /**
     * Prepare the application profiles.
     * For all code paths: