Merge "Fix domain collection for wildcards" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
e2c749b69e
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
try {
|
||||
mManager.setDomainVerificationStatusInternal(callingUid, domainSetId,
|
||||
successfulDomains, DomainVerificationState.STATE_SUCCESS);
|
||||
} catch (DomainVerificationManager.InvalidDomainSetException
|
||||
| PackageManager.NameNotFoundException ignored) {
|
||||
if (!successfulDomains.isEmpty()) {
|
||||
try {
|
||||
mManager.setDomainVerificationStatusInternal(callingUid, domainSetId,
|
||||
successfulDomains, DomainVerificationState.STATE_SUCCESS);
|
||||
} catch (DomainVerificationManager.InvalidDomainSetException
|
||||
| PackageManager.NameNotFoundException e) {
|
||||
Slog.e(TAG, "Failure reporting successful domains for " + packageName, e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
mManager.setDomainVerificationStatusInternal(callingUid, domainSetId,
|
||||
new ArraySet<>(response.failedDomains),
|
||||
DomainVerificationState.STATE_LEGACY_FAILURE);
|
||||
} catch (DomainVerificationManager.InvalidDomainSetException
|
||||
| PackageManager.NameNotFoundException ignored) {
|
||||
|
||||
if (!failedDomains.isEmpty()) {
|
||||
try {
|
||||
mManager.setDomainVerificationStatusInternal(callingUid, domainSetId,
|
||||
failedDomains, DomainVerificationState.STATE_LEGACY_FAILURE);
|
||||
} catch (DomainVerificationManager.InvalidDomainSetException
|
||||
| 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 {
|
||||
|
||||
Reference in New Issue
Block a user