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

Commit 1372048d authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Do not allow non-system apps to provide unverified attributions" into main

parents 64d724fc 790b7c82
Loading
Loading
Loading
Loading
+57 −32
Original line number Diff line number Diff line
@@ -604,7 +604,7 @@ public class AppOpsService extends IAppOpsService.Stub {
        }
    }

    /** Returned from {@link #verifyAndGetBypass(int, String, String, String, boolean)}. */
    /** Returned from {@link #verifyAndGetBypass(int, String, String, int, String, boolean)}. */
    private static final class PackageVerificationResult {

        final RestrictionBypass bypass;
@@ -3087,10 +3087,10 @@ public class AppOpsService extends IAppOpsService.Stub {
    public int checkPackage(int uid, String packageName) {
        Objects.requireNonNull(packageName);
        try {
            verifyAndGetBypass(uid, packageName, null, null, true);
            verifyAndGetBypass(uid, packageName, null, Process.INVALID_UID, null, true);
            // When the caller is the system, it's possible that the packageName is the special
            // one (e.g., "root") which isn't actually existed.
            if (resolveUid(packageName) == uid
            if (resolveNonAppUid(packageName) == uid
                    || (isPackageExisted(packageName)
                            && !filterAppAccessUnlocked(packageName, UserHandle.getUserId(uid)))) {
                return AppOpsManager.MODE_ALLOWED;
@@ -3306,7 +3306,7 @@ public class AppOpsService extends IAppOpsService.Stub {
            boolean shouldCollectMessage, int notedCount) {
        PackageVerificationResult pvr;
        try {
            pvr = verifyAndGetBypass(uid, packageName, attributionTag, proxyPackageName);
            pvr = verifyAndGetBypass(uid, packageName, attributionTag, proxyUid, proxyPackageName);
            if (!pvr.isAttributionTagValid) {
                attributionTag = null;
            }
@@ -3930,7 +3930,7 @@ public class AppOpsService extends IAppOpsService.Stub {
            // Test if the proxied operation will succeed before starting the proxy operation
            final SyncNotedAppOp testProxiedOp = startOperationDryRun(code,
                    proxiedUid, resolvedProxiedPackageName, proxiedAttributionTag,
                    proxiedVirtualDeviceId, resolvedProxyPackageName, proxiedFlags,
                    proxiedVirtualDeviceId, proxyUid, resolvedProxyPackageName, proxiedFlags,
                    startIfModeDefault);

            if (!shouldStartForMode(testProxiedOp.getOpMode(), startIfModeDefault)) {
@@ -3970,7 +3970,7 @@ public class AppOpsService extends IAppOpsService.Stub {
            int attributionChainId) {
        PackageVerificationResult pvr;
        try {
            pvr = verifyAndGetBypass(uid, packageName, attributionTag, proxyPackageName);
            pvr = verifyAndGetBypass(uid, packageName, attributionTag, proxyUid, proxyPackageName);
            if (!pvr.isAttributionTagValid) {
                attributionTag = null;
            }
@@ -4097,11 +4097,11 @@ public class AppOpsService extends IAppOpsService.Stub {
     */
    private SyncNotedAppOp startOperationDryRun(int code, int uid,
            @NonNull String packageName, @Nullable String attributionTag, int virtualDeviceId,
            String proxyPackageName, @OpFlags int flags,
            int proxyUid, String proxyPackageName, @OpFlags int flags,
            boolean startIfModeDefault) {
        PackageVerificationResult pvr;
        try {
            pvr = verifyAndGetBypass(uid, packageName, attributionTag, proxyPackageName);
            pvr = verifyAndGetBypass(uid, packageName, attributionTag, proxyUid, proxyPackageName);
            if (!pvr.isAttributionTagValid) {
                attributionTag = null;
            }
@@ -4656,14 +4656,18 @@ public class AppOpsService extends IAppOpsService.Stub {
    private boolean isSpecialPackage(int callingUid, @Nullable String packageName) {
        final String resolvedPackage = AppOpsManager.resolvePackageName(callingUid, packageName);
        return callingUid == Process.SYSTEM_UID
                || resolveUid(resolvedPackage) != Process.INVALID_UID;
                || resolveNonAppUid(resolvedPackage) != Process.INVALID_UID;
    }

    private boolean isCallerAndAttributionTrusted(@NonNull AttributionSource attributionSource) {
        if (attributionSource.getUid() != Binder.getCallingUid()
                && attributionSource.isTrusted(mContext)) {
            // if there is a next attribution source, it must be trusted, as well.
            if (attributionSource.getNext() == null
                    || attributionSource.getNext().isTrusted(mContext)) {
                return true;
            }
        }
        return mContext.checkPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
                Binder.getCallingPid(), Binder.getCallingUid(), null)
                == PackageManager.PERMISSION_GRANTED;
@@ -4757,19 +4761,20 @@ public class AppOpsService extends IAppOpsService.Stub {
    }

    /**
     * @see #verifyAndGetBypass(int, String, String, String, boolean)
     * @see #verifyAndGetBypass(int, String, String, int, String, boolean)
     */
    private @NonNull PackageVerificationResult verifyAndGetBypass(int uid, String packageName,
            @Nullable String attributionTag) {
        return verifyAndGetBypass(uid, packageName, attributionTag, null);
        return verifyAndGetBypass(uid, packageName, attributionTag, Process.INVALID_UID, null);
    }

    /**
     * @see #verifyAndGetBypass(int, String, String, String, boolean)
     * @see #verifyAndGetBypass(int, String, String, int, String, boolean)
     */
    private @NonNull PackageVerificationResult verifyAndGetBypass(int uid, String packageName,
            @Nullable String attributionTag, @Nullable String proxyPackageName) {
        return verifyAndGetBypass(uid, packageName, attributionTag, proxyPackageName, false);
            @Nullable String attributionTag, int proxyUid, @Nullable String proxyPackageName) {
        return verifyAndGetBypass(uid, packageName, attributionTag, proxyUid, proxyPackageName,
                false);
    }

    /**
@@ -4780,14 +4785,15 @@ public class AppOpsService extends IAppOpsService.Stub {
     * @param uid The uid the package belongs to
     * @param packageName The package the might belong to the uid
     * @param attributionTag attribution tag or {@code null} if no need to verify
     * @param proxyPackageName The proxy package, from which the attribution tag is to be pulled
     * @param proxyUid The proxy uid, from which the attribution tag is to be pulled
     * @param proxyPackageName The proxy package, from which the attribution tag may be pulled
     * @param suppressErrorLogs Whether to print to logcat about nonmatching parameters
     *
     * @return PackageVerificationResult containing {@link RestrictionBypass} and whether the
     *         attribution tag is valid
     */
    private @NonNull PackageVerificationResult verifyAndGetBypass(int uid, String packageName,
            @Nullable String attributionTag, @Nullable String proxyPackageName,
            @Nullable String attributionTag, int proxyUid, @Nullable String proxyPackageName,
            boolean suppressErrorLogs) {
        if (uid == Process.ROOT_UID) {
            // For backwards compatibility, don't check package name for root UID.
@@ -4831,34 +4837,47 @@ public class AppOpsService extends IAppOpsService.Stub {

        int callingUid = Binder.getCallingUid();

        // Allow any attribution tag for resolvable uids
        int pkgUid;
        // Allow any attribution tag for resolvable, non-app uids
        int nonAppUid;
        if (Objects.equals(packageName, "com.android.shell")) {
            // Special case for the shell which is a package but should be able
            // to bypass app attribution tag restrictions.
            pkgUid = Process.SHELL_UID;
            nonAppUid = Process.SHELL_UID;
        } else {
            pkgUid = resolveUid(packageName);
            nonAppUid = resolveNonAppUid(packageName);
        }
        if (pkgUid != Process.INVALID_UID) {
            if (pkgUid != UserHandle.getAppId(uid)) {
        if (nonAppUid != Process.INVALID_UID) {
            if (nonAppUid != UserHandle.getAppId(uid)) {
                if (!suppressErrorLogs) {
                    Slog.e(TAG, "Bad call made by uid " + callingUid + ". "
                                + "Package \"" + packageName + "\" does not belong to uid " + uid
                                + ".");
                }
                String otherUidMessage = DEBUG ? " but it is really " + pkgUid : " but it is not";
                throw new SecurityException("Specified package \"" + packageName + "\" under uid "
                        +  UserHandle.getAppId(uid) + otherUidMessage);
                String otherUidMessage =
                            DEBUG ? " but it is really " + nonAppUid : " but it is not";
                throw new SecurityException("Specified package \"" + packageName
                            + "\" under uid " +  UserHandle.getAppId(uid) + otherUidMessage);
            }
            // We only allow bypassing the attribution tag verification if the proxy is a
            // system app (or is null), in order to prevent abusive apps clogging the appops
            // system with unlimited attribution tags via proxy calls.
            boolean proxyIsSystemAppOrNull = true;
            if (proxyPackageName != null) {
                int proxyAppId = UserHandle.getAppId(proxyUid);
                if (proxyAppId >= Process.FIRST_APPLICATION_UID) {
                    proxyIsSystemAppOrNull =
                            mPackageManagerInternal.isSystemPackage(proxyPackageName);
                }
            }
            return new PackageVerificationResult(RestrictionBypass.UNRESTRICTED,
                    /* isAttributionTagValid */ true);
                    /* isAttributionTagValid */ proxyIsSystemAppOrNull);
        }

        int userId = UserHandle.getUserId(uid);
        RestrictionBypass bypass = null;
        boolean isAttributionTagValid = false;

        int pkgUid = nonAppUid;
        final long ident = Binder.clearCallingIdentity();
        try {
            PackageManagerInternal pmInt = LocalServices.getService(PackageManagerInternal.class);
@@ -5649,7 +5668,7 @@ public class AppOpsService extends IAppOpsService.Stub {
            if (nonpackageUid != -1) {
                packageName = null;
            } else {
                packageUid = resolveUid(packageName);
                packageUid = resolveNonAppUid(packageName);
                if (packageUid < 0) {
                    packageUid = AppGlobals.getPackageManager().getPackageUid(packageName,
                            PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
@@ -6749,11 +6768,17 @@ public class AppOpsService extends IAppOpsService.Stub {
                if (restricted && attrOp.isRunning()) {
                    attrOp.pause();
                } else if (attrOp.isPaused()) {
                    RestrictionBypass bypass = verifyAndGetBypass(uid, ops.packageName, attrOp.tag)
                            .bypass;
                    if (!isOpRestrictedLocked(uid, code, ops.packageName, attrOp.tag,
                            Context.DEVICE_ID_DEFAULT, bypass, false)) {
                        // Only resume if there are no other restrictions remaining on this op
                        attrOp.resume();
                    }
                }
            }
        }
    }

    private void notifyWatchersOnDefaultDevice(int code, int uid) {
        ArraySet<OnOpModeChangedListener> modeChangedListenerSet;
@@ -7198,7 +7223,7 @@ public class AppOpsService extends IAppOpsService.Stub {
        }
    }

    private static int resolveUid(String packageName)  {
    private static int resolveNonAppUid(String packageName)  {
        if (packageName == null) {
            return Process.INVALID_UID;
        }