Merge "Add sys config to handle apexes that are allowed to be updated" into sc-dev

This commit is contained in:
Nikita Ioffe
2021-06-22 14:15:41 +00:00
committed by Android (Google) Code Review
7 changed files with 147 additions and 0 deletions

View File

@@ -62,6 +62,8 @@ interface IPackageInstaller {
void bypassNextStagedInstallerCheck(boolean value);
void bypassNextAllowedApexUpdateCheck(boolean value);
void setAllowUnlimitedSilentUpdates(String installerPackageName);
void setSilentUpdatesThrottleTime(long throttleTimeInSeconds);
}

View File

@@ -1278,6 +1278,13 @@ public abstract class PackageManager {
*/
public static final int INSTALL_STAGED = 0x00200000;
/**
* Flag parameter for {@link #installPackage} to indicate that check whether given APEX can be
* updated should be disabled for this install.
* @hide
*/
public static final int INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK = 0x00400000;
/** @hide */
@IntDef(flag = true, value = {
DONT_KILL_APP,

View File

@@ -240,6 +240,7 @@ public class SystemConfig {
private final ArraySet<String> mRollbackWhitelistedPackages = new ArraySet<>();
private final ArraySet<String> mWhitelistedStagedInstallers = new ArraySet<>();
private final ArraySet<String> mAllowedPartnerApexes = new ArraySet<>();
/**
* Map of system pre-defined, uniquely named actors; keys are namespace,
@@ -410,6 +411,10 @@ public class SystemConfig {
return mWhitelistedStagedInstallers;
}
public Set<String> getAllowedPartnerApexes() {
return mAllowedPartnerApexes;
}
public ArraySet<String> getAppDataIsolationWhitelistedApps() {
return mAppDataIsolationWhitelistedApps;
}
@@ -1212,6 +1217,21 @@ public class SystemConfig {
}
XmlUtils.skipCurrentTag(parser);
} break;
case "allowed-partner-apex": {
// TODO(b/189274479): should this be allowOemPermissions instead?
if (allowAppConfigs) {
String pkgName = parser.getAttributeValue(null, "package");
if (pkgName == null) {
Slog.w(TAG, "<" + name + "> without package in " + permFile
+ " at " + parser.getPositionDescription());
} else {
mAllowedPartnerApexes.add(pkgName);
}
} else {
logNotAllowedInPartition(name, permFile, parser);
}
XmlUtils.skipCurrentTag(parser);
} break;
default: {
Slog.w(TAG, "Tag " + name + " is unknown in "
+ permFile + " at " + parser.getPositionDescription());

View File

@@ -157,6 +157,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
private volatile boolean mOkToSendBroadcasts = false;
private volatile boolean mBypassNextStagedInstallerCheck = false;
private volatile boolean mBypassNextAllowedApexUpdateCheck = false;
/**
* File storing persisted {@link #mSessions} metadata.
@@ -650,6 +651,13 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
throw new IllegalArgumentException(
"Non-staged APEX session doesn't support INSTALL_ENABLE_ROLLBACK");
}
if (isCalledBySystemOrShell(callingUid) || mBypassNextAllowedApexUpdateCheck) {
params.installFlags |= PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK;
} else {
// Only specific APEX updates (installed through ADB, or for CTS tests) can disable
// allowed APEX update check.
params.installFlags &= ~PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK;
}
}
if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0
@@ -674,6 +682,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
}
mBypassNextStagedInstallerCheck = false;
mBypassNextAllowedApexUpdateCheck = false;
if (!params.isMultiPackage) {
// Only system components can circumvent runtime permissions when installing.
if ((params.installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0
@@ -1106,6 +1116,14 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
mBypassNextStagedInstallerCheck = value;
}
@Override
public void bypassNextAllowedApexUpdateCheck(boolean value) {
if (!isCalledBySystemOrShell(Binder.getCallingUid())) {
throw new SecurityException("Caller not allowed to bypass allowed apex update check");
}
mBypassNextAllowedApexUpdateCheck = value;
}
/**
* Set an installer to allow for the unlimited silent updates.
*/

View File

@@ -147,6 +147,7 @@ import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.dex.DexManager;
import com.android.server.pm.parsing.pkg.AndroidPackage;
@@ -2238,6 +2239,26 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
.setAdmin(mInstallSource.installerPackageName)
.write();
}
// Check if APEX update is allowed. We do this check in handleInstall, since this is one of
// the places that:
// * Shared between staged and non-staged APEX update flows.
// * Only is called after boot completes.
// The later is important, since isApexUpdateAllowed check depends on the
// ModuleInfoProvider, which is only populated after device has booted.
if (isApexSession()) {
boolean checkApexUpdateAllowed =
(params.installFlags & PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK)
== 0;
synchronized (mLock) {
if (checkApexUpdateAllowed && !isApexUpdateAllowed(mPackageName)) {
onSessionValidationFailure(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
"Update of APEX package " + mPackageName + " is not allowed");
return;
}
}
}
if (params.isStaged) {
mStagingManager.commitSession(mStagedSession);
// TODO(b/136257624): CTS test fails if we don't send session finished broadcast, even
@@ -2776,6 +2797,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
return sessionContains((s) -> !s.isApexSession());
}
private boolean isApexUpdateAllowed(String apexPackageName) {
return mPm.getModuleInfo(apexPackageName, 0) != null
|| SystemConfig.getInstance().getAllowedPartnerApexes().contains(apexPackageName);
}
/**
* Validate apex install.
* <p>

View File

@@ -307,6 +307,8 @@ class PackageManagerShellCommand extends ShellCommand {
return runLogVisibility();
case "bypass-staged-installer-check":
return runBypassStagedInstallerCheck();
case "bypass-allowed-apex-update-check":
return runBypassAllowedApexUpdateCheck();
case "set-silent-updates-policy":
return runSetSilentUpdatesPolicy();
default: {
@@ -424,6 +426,20 @@ class PackageManagerShellCommand extends ShellCommand {
}
}
private int runBypassAllowedApexUpdateCheck() {
final PrintWriter pw = getOutPrintWriter();
try {
mInterface.getPackageInstaller()
.bypassNextAllowedApexUpdateCheck(Boolean.parseBoolean(getNextArg()));
return 0;
} catch (RemoteException e) {
pw.println("Failure ["
+ e.getClass().getName() + " - "
+ e.getMessage() + "]");
return -1;
}
}
private int uninstallSystemUpdates(String packageName) {
final PrintWriter pw = getOutPrintWriter();
boolean failedUninstalls = false;

View File

@@ -221,6 +221,64 @@ public class SystemConfigTest {
assertThat(mSysConfig.getWhitelistedStagedInstallers()).isEmpty();
}
/**
* Tests that readPermissions works correctly with {@link SystemConfig#ALLOW_APP_CONFIGS}
* permission flag for the tag: {@code allowed-partner-apex}.
*/
@Test
public void readPermissions_allowAppConfigs_parsesPartnerApexAllowList()
throws IOException {
final String contents =
"<config>\n"
+ " <allowed-partner-apex package=\"com.android.apex1\" />\n"
+ "</config>";
final File folder = createTempSubfolder("folder");
createTempFile(folder, "partner-apex-allowlist.xml", contents);
mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0);
assertThat(mSysConfig.getAllowedPartnerApexes()).containsExactly("com.android.apex1");
}
/**
* Tests that readPermissions works correctly with {@link SystemConfig#ALLOW_APP_CONFIGS}
* permission flag for the tag: {@code allowed-partner-apex}.
*/
@Test
public void readPermissions_allowAppConfigs_parsesPartnerApexAllowList_noPackage()
throws IOException {
final String contents =
"<config>\n"
+ " <allowed-partner-apex/>\n"
+ "</config>";
final File folder = createTempSubfolder("folder");
createTempFile(folder, "partner-apex-allowlist.xml", contents);
mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0);
assertThat(mSysConfig.getAllowedPartnerApexes()).isEmpty();
}
/**
* Tests that readPermissions works correctly without {@link SystemConfig#ALLOW_APP_CONFIGS}
* permission flag for the tag: {@code allowed-partner-apex}.
*/
@Test
public void readPermissions_notAllowAppConfigs_doesNotParsePartnerApexAllowList()
throws IOException {
final String contents =
"<config>\n"
+ " <allowed-partner-apex package=\"com.android.apex1\" />\n"
+ "</config>";
final File folder = createTempSubfolder("folder");
createTempFile(folder, "partner-apex-allowlist.xml", contents);
mSysConfig.readPermissions(folder, /* Grant all but ALLOW_APP_CONFIGS flag */ ~0x08);
assertThat(mSysConfig.getAllowedPartnerApexes()).isEmpty();
}
/**
* Creates folderName/fileName in the mTemporaryFolder and fills it with the contents.
*