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

Commit c36c3b94 authored by Jeff Sharkey's avatar Jeff Sharkey Committed by Joel Galenson
Browse files

Protect usage data with OP_GET_USAGE_STATS.

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

Bug: 78355661
Test: Search output directory for binaries that have READ_LOGS but not
USAGE_STATS and find none.

Change-Id: I85e3bad680bb510439d73c7db5cc50cdcb7bbb42
parent 87fb335e
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -7575,7 +7575,7 @@ Lcom/android/internal/os/HandlerCaller;->obtainMessageOO(ILjava/lang/Object;Ljav
Lcom/android/internal/os/HandlerCaller;->obtainMessageOOO(ILjava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Landroid/os/Message;
Lcom/android/internal/os/HandlerCaller;->sendMessage(Landroid/os/Message;)V
Lcom/android/internal/os/IDropBoxManagerService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/os/IDropBoxManagerService;
Lcom/android/internal/os/IDropBoxManagerService;->getNextEntry(Ljava/lang/String;J)Landroid/os/DropBoxManager$Entry;
Lcom/android/internal/os/IDropBoxManagerService;->getNextEntry(Ljava/lang/String;JLjava/lang/String;)Landroid/os/DropBoxManager$Entry;
Lcom/android/internal/os/PowerProfile;-><init>(Landroid/content/Context;)V
Lcom/android/internal/os/PowerProfile;->getAveragePower(Ljava/lang/String;)D
Lcom/android/internal/os/PowerProfile;->getAveragePower(Ljava/lang/String;I)D
+17 −5
Original line number Diff line number Diff line
@@ -16,9 +16,14 @@

package android.os;

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

import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SystemService;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemService;
import android.content.Context;
import android.util.Log;

@@ -351,16 +356,23 @@ public class DropBoxManager {

    /**
     * Gets the next entry from the drop box <em>after</em> the specified time.
     * Requires <code>android.permission.READ_LOGS</code>.  You must always call
     * {@link Entry#close()} on the return value!
     * You must always call {@link Entry#close()} on the return value!
     *
     * @param tag of entry to look for, null for all tags
     * @param msec time of the last entry seen
     * @return the next entry, or null if there are no more entries
     */
    public Entry getNextEntry(String tag, long msec) {
    @RequiresPermission(allOf = { READ_LOGS, PACKAGE_USAGE_STATS })
    public @Nullable Entry getNextEntry(String tag, long msec) {
        try {
            return mService.getNextEntry(tag, msec);
            return mService.getNextEntry(tag, msec, mContext.getOpPackageName());
        } catch (SecurityException e) {
            if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.P) {
                throw e;
            } else {
                Log.w(TAG, e.getMessage());
                return null;
            }
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
+1 −1
Original line number Diff line number Diff line
@@ -37,5 +37,5 @@ interface IDropBoxManagerService {
    boolean isTagEnabled(String tag);

    /** @see DropBoxManager#getNextEntry */
    DropBoxManager.Entry getNextEntry(String tag, long millis);
    DropBoxManager.Entry getNextEntry(String tag, long millis, String packageName);
}
+1 −1
Original line number Diff line number Diff line
@@ -236,7 +236,7 @@ DropBoxManager::getNextEntry(const String16& tag, long msec, Entry* entry)
    if (service == NULL) {
        return Status::fromExceptionCode(Status::EX_NULL_POINTER, "can't find dropbox service");
    }
    return service->getNextEntry(tag, msec, entry);
    return service->getNextEntry(tag, msec, android::String16("android"), entry);
}

}} // namespace android::os
+28 −10
Original line number Diff line number Diff line
@@ -17,12 +17,12 @@
package com.android.server;

import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Binder;
@@ -41,13 +41,13 @@ import android.text.format.Time;
import android.util.ArrayMap;
import android.util.Slog;

import libcore.io.IoUtils;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.IDropBoxManagerService;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.ObjectUtils;

import libcore.io.IoUtils;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileDescriptor;
@@ -58,7 +58,6 @@ import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Objects;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.zip.GZIPOutputStream;
@@ -145,8 +144,8 @@ public final class DropBoxManagerService extends SystemService {
        }

        @Override
        public DropBoxManager.Entry getNextEntry(String tag, long millis) {
            return DropBoxManagerService.this.getNextEntry(tag, millis);
        public DropBoxManager.Entry getNextEntry(String tag, long millis, String callingPackage) {
            return DropBoxManagerService.this.getNextEntry(tag, millis, callingPackage);
        }

        @Override
@@ -327,10 +326,29 @@ public final class DropBoxManagerService extends SystemService {
        }
    }

    public synchronized DropBoxManager.Entry getNextEntry(String tag, long millis) {
        if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.READ_LOGS)
                != PackageManager.PERMISSION_GRANTED) {
            throw new SecurityException("READ_LOGS permission required");
    private boolean checkPermission(int callingUid, String callingPackage) {
        // Callers always need this permission
        getContext().enforceCallingOrSelfPermission(
                android.Manifest.permission.READ_LOGS, TAG);

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

    public synchronized DropBoxManager.Entry getNextEntry(String tag, long millis,
            String callingPackage) {
        if (!checkPermission(Binder.getCallingUid(), callingPackage)) {
            return null;
        }

        try {