Merge "Refactor the installer name verification so that we do not crash on Android Auto where the UID can change depending on the user." into rvc-dev

This commit is contained in:
TreeHugger Robot
2020-04-20 09:34:46 +00:00
committed by Android (Google) Code Review
2 changed files with 78 additions and 62 deletions

View File

@@ -27,6 +27,7 @@ import static android.content.integrity.InstallerAllowedByManifestFormula.INSTAL
import static android.content.integrity.IntegrityUtils.getHexDigest;
import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ID;
import android.annotation.BinderThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.BroadcastReceiver;
@@ -50,7 +51,6 @@ import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Slog;
@@ -89,9 +89,9 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.function.Supplier;
/** Implementation of {@link AppIntegrityManagerService}. */
public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
@@ -184,9 +184,10 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
}
@Override
@BinderThread
public void updateRuleSet(
String version, ParceledListSlice<Rule> rules, IntentSender statusReceiver) {
String ruleProvider = getCallerPackageNameOrThrow();
String ruleProvider = getCallerPackageNameOrThrow(Binder.getCallingUid());
mHandler.post(
() -> {
@@ -220,8 +221,9 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
}
@Override
@BinderThread
public String getCurrentRuleSetVersion() {
getCallerPackageNameOrThrow();
getCallerPackageNameOrThrow(Binder.getCallingUid());
RuleMetadata ruleMetadata = mIntegrityFileManager.readMetadata();
return (ruleMetadata != null && ruleMetadata.getVersion() != null)
@@ -230,8 +232,9 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
}
@Override
@BinderThread
public String getCurrentRuleSetProvider() {
getCallerPackageNameOrThrow();
getCallerPackageNameOrThrow(Binder.getCallingUid());
RuleMetadata ruleMetadata = mIntegrityFileManager.readMetadata();
return (ruleMetadata != null && ruleMetadata.getRuleProvider() != null)
@@ -251,8 +254,8 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
}
@Override
public List<String> getWhitelistedRuleProviders() throws RemoteException {
return getAllowedRuleProviders();
public List<String> getWhitelistedRuleProviders() {
return getAllowedRuleProviderSystemApps();
}
private void handleIntegrityVerification(Intent intent) {
@@ -367,23 +370,9 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
return UNKNOWN_INSTALLER;
}
try {
int actualInstallerUid =
mContext.getPackageManager().getPackageUid(installer, /* flags= */ 0);
if (actualInstallerUid != installerUid) {
// Installer package name can be faked but the installerUid cannot.
Slog.e(
TAG,
"Installer "
+ installer
+ " has UID "
+ actualInstallerUid
+ " which doesn't match alleged installer UID "
+ installerUid);
return UNKNOWN_INSTALLER;
}
} catch (PackageManager.NameNotFoundException e) {
Slog.e(TAG, "Installer package " + installer + " not found.");
// Verify that the installer UID actually contains the package. Note that comparing UIDs
// is not safe since context's uid can change in different settings; e.g. Android Auto.
if (!getPackageListForUid(installerUid).contains(installer)) {
return UNKNOWN_INSTALLER;
}
@@ -398,14 +387,13 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
Slog.e(TAG, "Installer is package installer but originating UID not found.");
return UNKNOWN_INSTALLER;
}
String[] installerPackages =
mContext.getPackageManager().getPackagesForUid(originatingUid);
if (installerPackages == null || installerPackages.length == 0) {
List<String> installerPackages = getPackageListForUid(originatingUid);
if (installerPackages.isEmpty()) {
Slog.e(TAG, "No package found associated with originating UID " + originatingUid);
return UNKNOWN_INSTALLER;
}
// In the case of multiple package sharing a UID, we just return the first one.
return installerPackages[0];
return installerPackages.get(0);
}
return installer;
@@ -652,35 +640,55 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
return installationPath;
}
private String getCallerPackageNameOrThrow() {
String callerPackageName = getCallerPackageName();
private String getCallerPackageNameOrThrow(int callingUid) {
String callerPackageName = getCallingRulePusherPackageName(callingUid);
if (callerPackageName == null) {
throw new SecurityException(
"Only system packages specified in config_integrityRuleProviderPackages are"
+ " allowed to call this method.");
"Only system packages specified in config_integrityRuleProviderPackages are "
+ "allowed to call this method.");
}
return callerPackageName;
}
private String getCallerPackageName() {
final List<String> allowedRuleProviders = getAllowedRuleProviders();
for (String packageName : allowedRuleProviders) {
try {
// At least in tests, getPackageUid gives "NameNotFound" but getPackagesFromUid
// give the correct package name.
int uid = mContext.getPackageManager().getPackageUid(packageName, 0);
if (uid == Binder.getCallingUid()) {
// Caller is allowed in the config.
if (isSystemApp(packageName)) {
return packageName;
}
}
} catch (PackageManager.NameNotFoundException e) {
// Ignore the exception. We don't expect the app to be necessarily installed.
Slog.i(TAG, "Rule provider package " + packageName + " not installed.");
}
}
return null;
private String getCallingRulePusherPackageName(int callingUid) {
// Obtain the system apps that are whitelisted in config_integrityRuleProviderPackages.
List<String> allowedRuleProviders = getAllowedRuleProviderSystemApps();
Slog.i(TAG, String.format(
"Rule provider system app list contains: %s", allowedRuleProviders));
// Identify the package names in the caller list.
List<String> callingPackageNames = getPackageListForUid(callingUid);
Slog.i(TAG, String.format("Calling packages are: ", callingPackageNames));
// Find the intersection between the allowed and calling packages. Ideally, we will have
// at most one package name here. But if we have more, it is fine.
List<String> allowedCallingPackages =
callingPackageNames
.stream()
.filter(packageName -> allowedRuleProviders.contains(packageName))
.collect(Collectors.toList());
Slog.i(TAG, String.format("Calling rule pusher packages are: ", allowedCallingPackages));
return allowedCallingPackages.isEmpty() ? null : allowedCallingPackages.get(0);
}
private boolean isRuleProvider(String installerPackageName) {
return getAllowedRuleProviderSystemApps().stream()
.anyMatch(ruleProvider -> ruleProvider.equals(installerPackageName));
}
private List<String> getAllowedRuleProviderSystemApps() {
List<String> integrityRuleProviders =
Arrays.asList(
mContext.getResources()
.getStringArray(R.array.config_integrityRuleProviderPackages));
Slog.i(TAG, String.format("Rule provider list contains: %s", integrityRuleProviders));
// Filter out the rule provider packages that are not system apps.
return integrityRuleProviders.stream()
.filter(this::isSystemApp)
.collect(Collectors.toList());
}
private boolean isSystemApp(String packageName) {
@@ -694,17 +702,6 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
}
}
private List<String> getAllowedRuleProviders() {
return Arrays.asList(
mContext.getResources()
.getStringArray(R.array.config_integrityRuleProviderPackages));
}
private boolean isRuleProvider(String installerPackageName) {
return getAllowedRuleProviders().stream()
.anyMatch(ruleProvider -> ruleProvider.equals(installerPackageName));
}
private boolean integrityCheckIncludesRuleProvider() {
return Settings.Global.getInt(
mContext.getContentResolver(),
@@ -712,4 +709,13 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
0)
== 1;
}
private List<String> getPackageListForUid(int uid) {
try {
return Arrays.asList(mContext.getPackageManager().getPackagesForUid(uid));
} catch (NullPointerException e) {
Slog.w(TAG, String.format("No packages were found for uid: %d", uid));
return List.of();
}
}
}

View File

@@ -488,9 +488,18 @@ public class AppIntegrityManagerServiceImplTest {
assertThat(mService.getCurrentRules().getList()).containsExactly(rule);
}
@Test
public void getWhitelistedRuleProviders_returnsEmptyForNonSystemApps() throws Exception {
whitelistUsAsRuleProvider();
makeUsSystemApp(false);
assertThat(mService.getWhitelistedRuleProviders()).isEmpty();
}
@Test
public void getWhitelistedRuleProviders() throws Exception {
whitelistUsAsRuleProvider();
makeUsSystemApp();
assertThat(mService.getWhitelistedRuleProviders()).containsExactly(TEST_FRAMEWORK_PACKAGE);
}
@@ -535,6 +544,7 @@ public class AppIntegrityManagerServiceImplTest {
TEST_FRAMEWORK_PACKAGE, PackageManager.GET_SIGNING_CERTIFICATES);
doReturn(packageInfo).when(mSpyPackageManager).getPackageInfo(eq(INSTALLER), anyInt());
doReturn(1).when(mSpyPackageManager).getPackageUid(eq(INSTALLER), anyInt());
doReturn(new String[]{INSTALLER}).when(mSpyPackageManager).getPackagesForUid(anyInt());
return makeVerificationIntent(INSTALLER);
}