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

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

Merge "Fix domain collection for wildcards" into sc-dev

parents a5a543f8 71c5debd
Loading
Loading
Loading
Loading
+28 −7
Original line number Diff line number Diff line
@@ -21,11 +21,8 @@ import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.parsing.component.ParsedActivity;
import android.content.pm.parsing.component.ParsedIntentInfo;
import android.os.Binder;
import android.os.Build;
import android.util.ArraySet;
import android.util.Patterns;
@@ -36,19 +33,31 @@ import com.android.server.pm.parsing.pkg.AndroidPackage;

import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class DomainVerificationCollector {

    // The default domain name matcher doesn't account for wildcards, so prefix with *.
    private static final Pattern DOMAIN_NAME_WITH_WILDCARD =
            Pattern.compile("(\\*\\.)?" + Patterns.DOMAIN_NAME.pattern());

    @NonNull
    private final PlatformCompat mPlatformCompat;

    @NonNull
    private final SystemConfig mSystemConfig;

    @NonNull
    private final Matcher mDomainMatcher;

    public DomainVerificationCollector(@NonNull PlatformCompat platformCompat,
            @NonNull SystemConfig systemConfig) {
        mPlatformCompat = platformCompat;
        mSystemConfig = systemConfig;

        // Cache the matcher to avoid calling into native on each check
        mDomainMatcher = DOMAIN_NAME_WITH_WILDCARD.matcher("");
    }

    /**
@@ -144,7 +153,10 @@ public class DomainVerificationCollector {
                if (intent.handlesWebUris(false)) {
                    int authorityCount = intent.countDataAuthorities();
                    for (int index = 0; index < authorityCount; index++) {
                        domains.add(intent.getDataAuthority(index).getHost());
                        String host = intent.getDataAuthority(index).getHost();
                        if (isValidHost(host)) {
                            domains.add(host);
                        }
                    }
                }
            }
@@ -188,13 +200,22 @@ public class DomainVerificationCollector {
                int authorityCount = intent.countDataAuthorities();
                for (int index = 0; index < authorityCount; index++) {
                    String host = intent.getDataAuthority(index).getHost();
                    // It's easy to misconfigure autoVerify intent filters, so to avoid
                    // adding unintended hosts, check if the host is an HTTP domain.
                    if (Patterns.DOMAIN_NAME.matcher(host).matches()) {
                    if (isValidHost(host)) {
                        domains.add(host);
                    }
                }
            }
        }
    }

    /**
     * It's easy to mis-configure autoVerify intent filters, so to avoid adding unintended hosts,
     * check if the host is an HTTP domain. This applies for both legacy and modern versions of
     * the API, which will strip invalid hosts from the legacy parsing result. This is done to
     * improve the reliability of any legacy verifiers.
     */
    private boolean isValidHost(String host) {
        mDomainMatcher.reset(host);
        return mDomainMatcher.matches();
    }
}
+65 −15
Original line number Diff line number Diff line
@@ -30,7 +30,6 @@ import android.content.pm.verify.domain.DomainVerificationManager;
import android.content.pm.verify.domain.DomainVerificationState;
import android.os.Process;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Pair;
@@ -45,6 +44,7 @@ import com.android.server.pm.verify.domain.DomainVerificationMessageCodes;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
@@ -168,22 +168,58 @@ public class DomainVerificationProxyV1 implements DomainVerificationProxy {
                    return true;
                }

                Set<String> successfulDomains = new ArraySet<>(info.getHostToStateMap().keySet());
                successfulDomains.removeAll(response.failedDomains);
                AndroidPackage pkg = mConnection.getPackage(packageName);
                if (pkg == null) {
                    return true;
                }

                ArraySet<String> failedDomains = new ArraySet<>(response.failedDomains);
                Map<String, Integer> hostToStateMap = info.getHostToStateMap();
                Set<String> hostKeySet = hostToStateMap.keySet();
                ArraySet<String> successfulDomains = new ArraySet<>(hostKeySet);
                successfulDomains.removeAll(failedDomains);

                // v1 doesn't handle wildcard domains, so check them here for the verifier
                int size = successfulDomains.size();
                for (int index = size - 1; index >= 0; index--) {
                    String domain = successfulDomains.valueAt(index);
                    if (domain.startsWith("*.")) {
                        String nonWildcardDomain = domain.substring(2);
                        if (failedDomains.contains(nonWildcardDomain)) {
                            failedDomains.add(domain);
                            successfulDomains.removeAt(index);

                            // It's possible to declare a wildcard without declaring its
                            // non-wildcard equivalent, so if it wasn't originally declared,
                            // remove the transformed domain from the failed set. Otherwise the
                            // manager will not accept the failed set as it contains an undeclared
                            // domain.
                            if (!hostKeySet.contains(nonWildcardDomain)) {
                                failedDomains.remove(nonWildcardDomain);
                            }
                        }
                    }
                }

                int callingUid = response.callingUid;
                if (!successfulDomains.isEmpty()) {
                    try {
                        mManager.setDomainVerificationStatusInternal(callingUid, domainSetId,
                                successfulDomains, DomainVerificationState.STATE_SUCCESS);
                    } catch (DomainVerificationManager.InvalidDomainSetException
                        | PackageManager.NameNotFoundException ignored) {
                            | PackageManager.NameNotFoundException e) {
                        Slog.e(TAG, "Failure reporting successful domains for " + packageName, e);
                    }
                }

                if (!failedDomains.isEmpty()) {
                    try {
                        mManager.setDomainVerificationStatusInternal(callingUid, domainSetId,
                            new ArraySet<>(response.failedDomains),
                            DomainVerificationState.STATE_LEGACY_FAILURE);
                                failedDomains, DomainVerificationState.STATE_LEGACY_FAILURE);
                    } catch (DomainVerificationManager.InvalidDomainSetException
                        | PackageManager.NameNotFoundException ignored) {
                            | PackageManager.NameNotFoundException e) {
                        Slog.e(TAG, "Failure reporting failed domains for " + packageName, e);
                    }
                }

                return true;
@@ -235,7 +271,21 @@ public class DomainVerificationProxyV1 implements DomainVerificationProxy {
        // The collector itself handles the v1 vs v2 behavior, which is based on targetSdkVersion,
        // not the version of the verification agent on device.
        ArraySet<String> domains = mCollector.collectAutoVerifyDomains(pkg);
        return TextUtils.join(" ", domains);

        // v1 doesn't handle wildcard domains, so transform them here to the root
        StringBuilder builder = new StringBuilder();
        int size = domains.size();
        for (int index = 0; index < size; index++) {
            if (index > 0) {
                builder.append(" ");
            }
            String domain = domains.valueAt(index);
            if (domain.startsWith("*.")) {
                domain = domain.substring(2);
            }
            builder.append(domain);
        }
        return builder.toString();
    }

    private static class Response {