Add regression test for CVE-2021-39689 (b/206090748).
This is to ensure that a later change won't introduce a security
regression.
Bug: 280776418
Test: atest odsign_e2e_tests_full
Change-Id: Ib1c9320e272cf051f285393332e47b8c1843ff54
diff --git a/odrefresh/odrefresh_main.cc b/odrefresh/odrefresh_main.cc
index 2871a99..c0e5ade 100644
--- a/odrefresh/odrefresh_main.cc
+++ b/odrefresh/odrefresh_main.cc
@@ -20,6 +20,7 @@
#include <string_view>
#include <unordered_map>
+#include "android-base/parsebool.h"
#include "android-base/properties.h"
#include "android-base/stringprintf.h"
#include "android-base/strings.h"
@@ -37,6 +38,8 @@
namespace {
using ::android::base::GetProperty;
+using ::android::base::ParseBool;
+using ::android::base::ParseBoolResult;
using ::android::base::StartsWith;
using ::art::odrefresh::CompilationOptions;
using ::art::odrefresh::ExitCode;
@@ -155,8 +158,8 @@
config->SetStagingDir(value);
} else if (ArgumentEquals(arg, "--dry-run")) {
config->SetDryRun();
- } else if (ArgumentEquals(arg, "--partial-compilation")) {
- config->SetPartialCompilation(true);
+ } else if (ArgumentMatches(arg, "--partial-compilation=", &value)) {
+ config->SetPartialCompilation(ParseBool(value) == ParseBoolResult::kTrue);
} else if (ArgumentEquals(arg, "--no-refresh")) {
config->SetRefresh(false);
} else if (ArgumentEquals(arg, "--minimal")) {
diff --git a/test/odsign/test-src/com/android/tests/odsign/OdrefreshHostTest.java b/test/odsign/test-src/com/android/tests/odsign/OdrefreshHostTest.java
index c5af9d8..88bc465 100644
--- a/test/odsign/test-src/com/android/tests/odsign/OdrefreshHostTest.java
+++ b/test/odsign/test-src/com/android/tests/odsign/OdrefreshHostTest.java
@@ -413,6 +413,45 @@
mTestUtils.assertModifiedAfter(Set.of(OdsignTestUtils.CACHE_INFO_FILE), timeMs);
}
+ /**
+ * Regression test of CVE-2021-39689 (b/206090748): if the device doesn't have the odsign
+ * security fix, there's a risk that the existing artifacts may be manipulated, and odsign will
+ * mistakenly sign them. Therefore, odrefresh should clear all artifacts and regenerate them.
+ * I.e., no matter the compilation succeeds or not, no existing artifacts should be left.
+ *
+ * On contrary, if the device has the odsign security fix, odrefresh should keep existing
+ * artifacts (see {@link #verifyMissingArtifactTriggersCompilation}).
+ */
+ @Test
+ public void verifyArtifactsClearedWhenNoPartialCompilation() throws Exception {
+ // Remove arbitrary system server artifacts to trigger compilation.
+ simulateMissingArtifacts();
+
+ // The successful case.
+ mTestUtils.removeCompilationLogToAvoidBackoff();
+ long timeMs = mTestUtils.getCurrentTimeMs();
+ mTestUtils.runOdrefreshNoPartialCompilation();
+
+ // Existing artifacts should be replaced with new ones.
+ mTestUtils.assertModifiedAfter(mTestUtils.getExpectedPrimaryBootImage(), timeMs);
+ mTestUtils.assertModifiedAfter(mTestUtils.getExpectedBootImageMainlineExtension(), timeMs);
+ mTestUtils.assertModifiedAfter(mTestUtils.getSystemServerExpectedArtifacts(), timeMs);
+
+ // Remove arbitrary system server artifacts to trigger compilation again.
+ simulateMissingArtifacts();
+
+ // The failed case.
+ mDeviceState.makeDex2oatFail();
+ mTestUtils.removeCompilationLogToAvoidBackoff();
+ timeMs = mTestUtils.getCurrentTimeMs();
+ mTestUtils.runOdrefreshNoPartialCompilation();
+
+ // Existing artifacts should be gone.
+ mTestUtils.assertFilesNotExist(mTestUtils.getExpectedPrimaryBootImage());
+ mTestUtils.assertFilesNotExist(mTestUtils.getExpectedBootImageMainlineExtension());
+ mTestUtils.assertFilesNotExist(mTestUtils.getSystemServerExpectedArtifacts());
+ }
+
private Set<String> simulateMissingArtifacts() throws Exception {
Set<String> missingArtifacts = new HashSet<>();
String sample = mTestUtils.getSystemServerExpectedArtifacts().iterator().next();
diff --git a/test/odsign/test-src/com/android/tests/odsign/OdsignTestUtils.java b/test/odsign/test-src/com/android/tests/odsign/OdsignTestUtils.java
index 5471c1f..41e45ea 100644
--- a/test/odsign/test-src/com/android/tests/odsign/OdsignTestUtils.java
+++ b/test/odsign/test-src/com/android/tests/odsign/OdsignTestUtils.java
@@ -482,8 +482,18 @@
public void runOdrefresh(String extraArgs) throws Exception {
mTestInfo.getDevice().executeShellV2Command(ODREFRESH_BIN + " --check");
+ mTestInfo.getDevice().executeShellV2Command(ODREFRESH_BIN
+ + " --partial-compilation=true --no-refresh " + extraArgs + " --compile");
+ }
+
+ /**
+ * Simulates how odsign invokes odrefresh on a device that doesn't have the security fix for
+ * CVE-2021-39689 (b/206090748).
+ */
+ public void runOdrefreshNoPartialCompilation() throws Exception {
+ // Note that odsign doesn't call `odrefresh --check` on such a device.
mTestInfo.getDevice().executeShellV2Command(
- ODREFRESH_BIN + " --partial-compilation --no-refresh " + extraArgs + " --compile");
+ ODREFRESH_BIN + " --partial-compilation=false --no-refresh --compile");
}
public boolean areAllApexesFactoryInstalled() throws Exception {