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

Commit 8aa16dfc authored by Atneya Nair's avatar Atneya Nair Committed by Android (Google) Code Review
Browse files

Merge "appops: Consolidate check/note/startOp validation" into main

parents 48f45278 e5b2400c
Loading
Loading
Loading
Loading
+123 −47
Original line number Diff line number Diff line
@@ -71,6 +71,7 @@ import static android.content.Intent.EXTRA_REPLACING;
import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
import static android.content.pm.PermissionInfo.PROTECTION_FLAG_APPOP;
import static android.permission.flags.Flags.deviceAwareAppOpNewSchemaEnabled;
import static android.permission.flags.Flags.checkOpValidatePackage;

import static com.android.internal.util.FrameworkStatsLog.APP_OP_NOTE_OP_OR_CHECK_OP_BINDER_API_CALLED;
import static com.android.internal.util.FrameworkStatsLog.APP_OP_NOTE_OP_OR_CHECK_OP_BINDER_API_CALLED__BINDER_API__CHECK_OPERATION;
@@ -2860,21 +2861,31 @@ public class AppOpsService extends IAppOpsService.Stub {

    private int checkOperationImpl(int code, int uid, String packageName,
             @Nullable String attributionTag, int virtualDeviceId, boolean raw) {
        String resolvedPackageName;
        if (!shouldUseNewCheckOp()) {
            verifyIncomingOp(code);
            if (!isValidVirtualDeviceId(virtualDeviceId)) {
            Slog.w(TAG,
                    "checkOperationImpl returned MODE_IGNORED as virtualDeviceId " + virtualDeviceId
                            + " is invalid");
                Slog.w(TAG, "checkOperationImpl returned MODE_IGNORED as virtualDeviceId "
                        + virtualDeviceId + " is invalid");
                return AppOpsManager.MODE_IGNORED;
            }
            if (!isIncomingPackageValid(packageName, UserHandle.getUserId(uid))) {
                return AppOpsManager.opToDefaultMode(code);
            }

        String resolvedPackageName = AppOpsManager.resolvePackageName(uid, packageName);
            resolvedPackageName = AppOpsManager.resolvePackageName(uid, packageName);
            if (resolvedPackageName == null) {
                return AppOpsManager.MODE_IGNORED;
            }
        } else {
            // Note, this flag changes the behavior in this case: invalid packages now don't
            // succeed checkOp
            resolvedPackageName = validateOpRequest(code, uid, packageName,
                    virtualDeviceId, false, "checkOperation");
            if (resolvedPackageName == null) {
                return AppOpsManager.MODE_IGNORED;
            }
        }
        return checkOperationUnchecked(code, uid, resolvedPackageName, attributionTag,
                virtualDeviceId, raw);
    }
@@ -3147,12 +3158,13 @@ public class AppOpsService extends IAppOpsService.Stub {
             @Nullable String attributionTag, int virtualDeviceId,
             boolean shouldCollectAsyncNotedOp, @Nullable String message,
             boolean shouldCollectMessage) {
        String resolvedPackageName;
        if (!shouldUseNewCheckOp()) {
            verifyIncomingUid(uid);
            verifyIncomingOp(code);
            if (!isValidVirtualDeviceId(virtualDeviceId)) {
            Slog.w(TAG,
                    "checkOperationImpl returned MODE_IGNORED as virtualDeviceId " + virtualDeviceId
                            + " is invalid");
                Slog.w(TAG, "checkOperationImpl returned MODE_IGNORED as virtualDeviceId "
                        + virtualDeviceId + " is invalid");
                return new SyncNotedAppOp(AppOpsManager.MODE_IGNORED, code, attributionTag,
                        packageName);
            }
@@ -3161,11 +3173,22 @@ public class AppOpsService extends IAppOpsService.Stub {
                        packageName);
            }

        String resolvedPackageName = AppOpsManager.resolvePackageName(uid, packageName);
            resolvedPackageName = AppOpsManager.resolvePackageName(uid, packageName);
            if (resolvedPackageName == null) {
                return new SyncNotedAppOp(AppOpsManager.MODE_IGNORED, code, attributionTag,
                        packageName);
            }
        } else {
            // Note, this flag changes the behavior in this case:
            // invalid package is now IGNORE instead of ERROR for consistency
            resolvedPackageName = validateOpRequest(code, uid, packageName,
                    virtualDeviceId, true, "noteOperation");
            if (resolvedPackageName == null) {
                return new SyncNotedAppOp(AppOpsManager.MODE_IGNORED, code, attributionTag,
                        packageName);
            }
        }

        return noteOperationUnchecked(code, uid, resolvedPackageName, attributionTag,
                virtualDeviceId, Process.INVALID_UID, null, null,
                Context.DEVICE_ID_DEFAULT, AppOpsManager.OP_FLAG_SELF, shouldCollectAsyncNotedOp,
@@ -3602,12 +3625,13 @@ public class AppOpsService extends IAppOpsService.Stub {
            boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, @NonNull String message,
            boolean shouldCollectMessage, @AttributionFlags int attributionFlags,
            int attributionChainId) {
        String resolvedPackageName;
        if (!shouldUseNewCheckOp()) {
            verifyIncomingUid(uid);
            verifyIncomingOp(code);
            if (!isValidVirtualDeviceId(virtualDeviceId)) {
            Slog.w(TAG,
                    "startOperationImpl returned MODE_IGNORED as virtualDeviceId " + virtualDeviceId
                            + " is invalid");
                Slog.w(TAG, "startOperationImpl returned MODE_IGNORED as virtualDeviceId "
                        + virtualDeviceId + " is invalid");
                return new SyncNotedAppOp(AppOpsManager.MODE_IGNORED, code, attributionTag,
                        packageName);
            }
@@ -3616,11 +3640,21 @@ public class AppOpsService extends IAppOpsService.Stub {
                        packageName);
            }

        String resolvedPackageName = AppOpsManager.resolvePackageName(uid, packageName);
            resolvedPackageName = AppOpsManager.resolvePackageName(uid, packageName);
            if (resolvedPackageName == null) {
                return new SyncNotedAppOp(AppOpsManager.MODE_IGNORED, code, attributionTag,
                        packageName);
            }
        } else {
            // Note, this flag changes the behavior in this case:
            // invalid package is now IGNORE instead of ERROR for consistency
            resolvedPackageName = validateOpRequest(code, uid, packageName,
                    virtualDeviceId, true, "startOperation");
            if (resolvedPackageName == null) {
                return new SyncNotedAppOp(AppOpsManager.MODE_IGNORED, code, attributionTag,
                        packageName);
            }
        }

        // As a special case for OP_RECORD_AUDIO_HOTWORD, OP_RECEIVE_AMBIENT_TRIGGER_AUDIO and
        // OP_RECORD_AUDIO_SANDBOXED which we use only for attribution purposes and not as a check,
@@ -4341,6 +4375,48 @@ public class AppOpsService extends IAppOpsService.Stub {
                || (permInfo.getProtectionFlags() & PROTECTION_FLAG_APPOP) != 0;
    }

    private boolean shouldUseNewCheckOp() {
        final long identity = Binder.clearCallingIdentity();
        try {
            return checkOpValidatePackage();
        } catch (Exception e) {
            // before device provider init, only on old storage
            return true;
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
    }

    /**
     * Validates arguments for a particular op request
     * @param shouldVerifyUid - If the calling uid needs perms for other uids, due to the method
     * being an appop write.
     * @param methodName - For logging purposes
     * @return The resolved package for the request, null on any failure
     */
    private @Nullable String validateOpRequest(int code, int uid, String packageName, int vdi,
            boolean shouldVerifyUid, String methodName) {
        verifyIncomingOp(code);
        if (shouldVerifyUid) {
            verifyIncomingUid(uid);
        }
        if (!isValidVirtualDeviceId(vdi)) {
            Slog.w(TAG, methodName + ": error due to virtualDeviceId " + vdi + " is invalid");
            return null;
        }
        if (!isIncomingPackageValid(packageName, UserHandle.getUserId(uid))) {
            Slog.w(TAG, methodName + ": error due to package: " + packageName
                            + " is invalid for " + uid);
            return null;
        }
        String resolvedPackageName = AppOpsManager.resolvePackageName(uid, packageName);
        if (resolvedPackageName == null) {
            Slog.w(TAG, methodName + ": error due to unable to resolve uid: " + uid);
            return null;
        }
        return resolvedPackageName;
    }

    private void verifyIncomingProxyUid(@NonNull AttributionSource attributionSource) {
        if (attributionSource.getUid() == Binder.getCallingUid()) {
            return;