apkmanifest: parse fields related to relaxed rollback protection scheme
In case a Microdroid pVM wants to opt in a relaxed rollback protection
scheme it needs to have the following things defined in its manifest:
* <uses-permission USE_RELAXED_MICRODROID_ROLLBACK_PROTECTION>
* set android.system.virtualmachine.ROLLBACK_INDEX <property>
In case only one of the two things is defined, the VM won't boot. This
is enforced by microdroid_manager (see changes to the verify.rs).
In the follow-up patch these new fields will be used to create a new
more relaxed sealing policy.
Bug: 378681279
Test: atest MicrodroidTests
Change-Id: Iabd12fd47f0eb271f021d5ad466de4f6c0669f2b
diff --git a/tests/testapk/Android.bp b/tests/testapk/Android.bp
index 806592d..0ffab5d 100644
--- a/tests/testapk/Android.bp
+++ b/tests/testapk/Android.bp
@@ -64,6 +64,8 @@
DATA = [
":MicrodroidTestAppUpdated",
":MicrodroidTestHelperAppRelaxedRollbackProtection_correct_V5",
+ ":MicrodroidTestHelperAppRelaxedRollbackProtection_no_permission",
+ ":MicrodroidTestHelperAppRelaxedRollbackProtection_no_rollback_index",
":MicrodroidVmShareApp",
":test_microdroid_vendor_image",
":test_microdroid_vendor_image_unsigned",
@@ -74,6 +76,29 @@
defaults: ["MicrodroidTestAppsDefaults"],
manifest: "AndroidManifestV5_relaxed_rollback_protection.xml",
jni_libs: [
+ "MicrodroidTestNativeLib",
+ "MicrodroidTestNativeLibWithLibIcu",
+ ],
+ min_sdk_version: "33",
+}
+
+android_test_helper_app {
+ name: "MicrodroidTestHelperAppRelaxedRollbackProtection_no_rollback_index",
+ defaults: ["MicrodroidTestAppsDefaults"],
+ manifest: "AndroidManifestV5_relaxed_rollback_protection_no_rollback_index.xml",
+ jni_libs: [
+ "MicrodroidTestNativeLib",
+ "MicrodroidTestNativeLibWithLibIcu",
+ ],
+ min_sdk_version: "33",
+}
+
+android_test_helper_app {
+ name: "MicrodroidTestHelperAppRelaxedRollbackProtection_no_permission",
+ defaults: ["MicrodroidTestAppsDefaults"],
+ manifest: "AndroidManifestV5_relaxed_rollback_protection_no_permission.xml",
+ jni_libs: [
+ "MicrodroidTestNativeLib",
"MicrodroidTestNativeLibWithLibIcu",
],
min_sdk_version: "33",
diff --git a/tests/testapk/AndroidManifestV5.xml b/tests/testapk/AndroidManifestV5.xml
index 2ef1b6b..f80edac 100644
--- a/tests/testapk/AndroidManifestV5.xml
+++ b/tests/testapk/AndroidManifestV5.xml
@@ -18,7 +18,6 @@
android:versionCode="5">
<uses-permission android:name="android.permission.MANAGE_VIRTUAL_MACHINE" />
<uses-permission android:name="android.permission.USE_CUSTOM_VIRTUAL_MACHINE" />
- <uses-permission android:name="android.permission.USE_RELAXED_MICRODROID_ROLLBACK_PROTECTION" />
<uses-sdk android:minSdkVersion="33" android:targetSdkVersion="33" />
<uses-feature android:name="android.software.virtualization_framework" android:required="false" />
<queries>
diff --git a/tests/testapk/AndroidManifestV5_relaxed_rollback_protection.xml b/tests/testapk/AndroidManifestV5_relaxed_rollback_protection.xml
index 619d158..16c585a 100644
--- a/tests/testapk/AndroidManifestV5_relaxed_rollback_protection.xml
+++ b/tests/testapk/AndroidManifestV5_relaxed_rollback_protection.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2021 The Android Open Source Project
+<!-- Copyright (C) 2025 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -15,11 +15,13 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.microdroid.test_relaxed_rollback_protection_scheme"
- android:versionCode="5">
+ android:versionCode="5" >
<uses-permission android:name="android.permission.MANAGE_VIRTUAL_MACHINE" />
<uses-permission android:name="android.permission.USE_CUSTOM_VIRTUAL_MACHINE" />
<uses-permission android:name="android.permission.USE_RELAXED_MICRODROID_ROLLBACK_PROTECTION" />
<uses-sdk android:minSdkVersion="33" android:targetSdkVersion="33" />
<uses-feature android:name="android.software.virtualization_framework" android:required="false" />
- <application />
+ <application>
+ <property android:name="android.system.virtualmachine.ROLLBACK_INDEX" android:value="1" />
+ </application>
</manifest>
diff --git a/tests/testapk/AndroidManifestV5_relaxed_rollback_protection_no_permission.xml b/tests/testapk/AndroidManifestV5_relaxed_rollback_protection_no_permission.xml
new file mode 100644
index 0000000..91de2a0
--- /dev/null
+++ b/tests/testapk/AndroidManifestV5_relaxed_rollback_protection_no_permission.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.microdroid.test_relaxed_rollback_protection_scheme"
+ android:versionCode="5" >
+ <uses-permission android:name="android.permission.MANAGE_VIRTUAL_MACHINE" />
+ <uses-permission android:name="android.permission.USE_CUSTOM_VIRTUAL_MACHINE" />
+ <uses-sdk android:minSdkVersion="33" android:targetSdkVersion="33" />
+ <uses-feature android:name="android.software.virtualization_framework" android:required="false" />
+ <application>
+ <property android:name="android.system.virtualmachine.ROLLBACK_INDEX" android:value="1" />
+ </application>
+</manifest>
diff --git a/tests/testapk/AndroidManifestV5_relaxed_rollback_protection_no_rollback_index.xml b/tests/testapk/AndroidManifestV5_relaxed_rollback_protection_no_rollback_index.xml
new file mode 100644
index 0000000..3d6d734
--- /dev/null
+++ b/tests/testapk/AndroidManifestV5_relaxed_rollback_protection_no_rollback_index.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.microdroid.test_relaxed_rollback_protection_scheme"
+ android:versionCode="5" >
+ <uses-permission android:name="android.permission.MANAGE_VIRTUAL_MACHINE" />
+ <uses-permission android:name="android.permission.USE_CUSTOM_VIRTUAL_MACHINE" />
+ <uses-permission android:name="android.permission.USE_RELAXED_MICRODROID_ROLLBACK_PROTECTION" />
+ <uses-sdk android:minSdkVersion="33" android:targetSdkVersion="33" />
+ <uses-feature android:name="android.software.virtualization_framework" android:required="false" />
+ <application />
+</manifest>
diff --git a/tests/testapk/AndroidManifestV6.xml b/tests/testapk/AndroidManifestV6.xml
index 7dd0663..2115ef7 100644
--- a/tests/testapk/AndroidManifestV6.xml
+++ b/tests/testapk/AndroidManifestV6.xml
@@ -18,11 +18,11 @@
android:versionCode="6">
<uses-permission android:name="android.permission.MANAGE_VIRTUAL_MACHINE" />
<uses-permission android:name="android.permission.USE_CUSTOM_VIRTUAL_MACHINE" />
- <uses-permission android:name="android.permission.USE_RELAXED_MICRODROID_ROLLBACK_PROTECTION" />
<uses-sdk android:minSdkVersion="33" android:targetSdkVersion="33" />
<uses-feature android:name="android.software.virtualization_framework" android:required="false" />
<queries>
<package android:name="com.android.microdroid.vmshare_app" />
+ <package android:name="com.android.microdroid.test_relaxed_rollback_protection_scheme" />
</queries>
<application />
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/testapk/AndroidTestTemplate.xml b/tests/testapk/AndroidTestTemplate.xml
index 6cdf984..5ed7a07 100644
--- a/tests/testapk/AndroidTestTemplate.xml
+++ b/tests/testapk/AndroidTestTemplate.xml
@@ -21,7 +21,6 @@
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="test-file-name" value="{MODULE}.apk" />
<option name="test-file-name" value="MicrodroidVmShareApp.apk" />
- <option name="test-file-name" value="MicrodroidTestHelperAppRelaxedRollbackProtection_correct_V5.apk" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
<option name="run-command" value="mkdir -p /data/local/tmp/cts/microdroid" />
@@ -31,6 +30,9 @@
<option name="cleanup" value="true" />
<option name="push" value="test_microdroid_vendor_image.img->/data/local/tmp/cts/microdroid/test_microdroid_vendor_image.img" />
<option name="push" value="test_microdroid_vendor_image_unsigned.img->/data/local/tmp/cts/microdroid/test_microdroid_vendor_image_unsigned.img" />
+ <option name="push" value="MicrodroidTestHelperAppRelaxedRollbackProtection_correct_V5.apk->/data/local/tmp/cts/microdroid/MicrodroidTestHelperAppRelaxedRollbackProtection_correct_V5.apk" />
+ <option name="push" value="MicrodroidTestHelperAppRelaxedRollbackProtection_no_permission.apk->/data/local/tmp/cts/microdroid/MicrodroidTestHelperAppRelaxedRollbackProtection_no_permission.apk" />
+ <option name="push" value="MicrodroidTestHelperAppRelaxedRollbackProtection_no_rollback_index.apk->/data/local/tmp/cts/microdroid/MicrodroidTestHelperAppRelaxedRollbackProtection_no_rollback_index.apk" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.microdroid.test" />
diff --git a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
index b492684..521ee9a 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -59,6 +59,7 @@
import android.system.virtualmachine.VirtualMachineDescriptor;
import android.system.virtualmachine.VirtualMachineException;
import android.system.virtualmachine.VirtualMachineManager;
+import android.util.Log;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -130,8 +131,8 @@
private static final String VM_ATTESTATION_MESSAGE = "Hello RKP from AVF!";
private static final int ENCRYPTED_STORAGE_BYTES = 4_000_000;
- private static final String USE_RELAXED_MICRODROID_ROLLBACK_PROTECTION_PERMISSION =
- "android.permission.USE_RELAXED_MICRODROID_ROLLBACK_PROTECTION";
+ private static final String RELAXED_ROLLBACK_PROTECTION_SCHEME_TEST_PACKAGE_NAME =
+ "com.android.microdroid.test_relaxed_rollback_protection_scheme";
@Rule public Timeout globalTimeout = Timeout.seconds(300);
@@ -166,19 +167,18 @@
// Tests that rely on the state of the permission should explicitly grant or revoke it.
revokePermission(VirtualMachine.USE_CUSTOM_VIRTUAL_MACHINE_PERMISSION);
}
- revokePermission(USE_RELAXED_MICRODROID_ROLLBACK_PROTECTION_PERMISSION);
}
@After
public void tearDown() {
revokePermission(VirtualMachine.USE_CUSTOM_VIRTUAL_MACHINE_PERMISSION);
- revokePermission(USE_RELAXED_MICRODROID_ROLLBACK_PROTECTION_PERMISSION);
+ // Some tests might install additional apks, so we need to clean them up here.
+ uninstallApp(RELAXED_ROLLBACK_PROTECTION_SCHEME_TEST_PACKAGE_NAME);
}
+
private static final String EXAMPLE_STRING = "Literally any string!! :)";
private static final String VM_SHARE_APP_PACKAGE_NAME = "com.android.microdroid.vmshare_app";
- private static final String RELAXED_ROLLBACK_PROTECTION_SCHEME_PACKAGE_NAME =
- "com.android.microdroid.test_relaxed_rollback_protection_scheme";
private void createAndConnectToVmHelper(int cpuTopology, boolean shouldUseHugepages)
throws Exception {
@@ -2754,37 +2754,111 @@
assertThat(testResults.mPageSize).isEqualTo(expectedPageSize);
}
+ // This test requires MicrodroidTestApp to have USE_RELAXED_MICRODROID_ROLLBACK_PROTECTION
+ // permission. This means that the permission needs to be declared in the AndroidManifest.xml of
+ // the MicrodroidTestApp.apk. Which in turns leads microdroid_manager to enable the relaxed
+ // rollback protection scheme, which we don't want to be enabled for most of the tests here.
+ // For now comment out this test. It will be un-commented (and probably moved to a separate test
+ // apk) in a follow-up patch.
+ // TODO(ioffe): bring this test back!
+ /*
+ @Test
+ public void libIcuIsLoadable() throws Exception {
+ assumeSupportedDevice();
+ // This test relies on the test apk having USE_RELAXED_MICRODROID_ROLLBACK_PROTECTION
+ // permission.
+ grantPermission(USE_RELAXED_MICRODROID_ROLLBACK_PROTECTION_PERMISSION);
+
+ // This test requires additional test apk.
+ installApp("MicrodroidTestHelperAppRelaxedRollbackProtection_correct_V5.apk");
+
+ Context otherAppCtx =
+ getContext()
+ .createPackageContext(RELAXED_ROLLBACK_PROTECTION_SCHEME_TEST_PACKAGE_NAME, 0);
+
+ VirtualMachineConfig config =
+ new VirtualMachineConfig.Builder(otherAppCtx)
+ .setDebugLevel(DEBUG_LEVEL_FULL)
+ .setPayloadBinaryName("MicrodroidTestNativeLibWithLibIcu.so")
+ .setProtectedVm(isProtectedVm())
+ .setOs(os())
+ .build();
+
+ VirtualMachine vm = forceCreateNewVirtualMachine("test_libicu_is_loadable", config);
+
+ TestResults testResults =
+ runVmTestService(
+ TAG,
+ vm,
+ (ts, tr) -> {
+ ts.checkLibIcuIsAccessible();
+ });
+
+ // checkLibIcuIsAccessible will throw an exception if something goes wrong.
+ assertThat(testResults.mException).isNull();
+ }
+ */
+
@Test
- public void libIcuIsLoadable() throws Exception {
+ public void relaxedRollbackProtectionScheme_apkDoesNotHavePermission_bootFails()
+ throws Exception {
assumeSupportedDevice();
- // This test relies on the test apk having USE_RELAXED_MICRODROID_ROLLBACK_PROTECTION
- // permission.
- grantPermission(USE_RELAXED_MICRODROID_ROLLBACK_PROTECTION_PERMISSION);
+ // This test requires additional test apk.
+ installApp("MicrodroidTestHelperAppRelaxedRollbackProtection_no_permission.apk");
Context otherAppCtx =
getContext()
- .createPackageContext(RELAXED_ROLLBACK_PROTECTION_SCHEME_PACKAGE_NAME, 0);
+ .createPackageContext(
+ RELAXED_ROLLBACK_PROTECTION_SCHEME_TEST_PACKAGE_NAME, 0);
+
VirtualMachineConfig config =
new VirtualMachineConfig.Builder(otherAppCtx)
.setDebugLevel(DEBUG_LEVEL_FULL)
- .setPayloadBinaryName("MicrodroidTestNativeLibWithLibIcu.so")
+ .setPayloadBinaryName("MicrodroidTestNativeLib.so")
.setProtectedVm(isProtectedVm())
.setOs(os())
.build();
- VirtualMachine vm = forceCreateNewVirtualMachine("test_libicu_is_loadable", config);
+ VirtualMachine vm =
+ forceCreateNewVirtualMachine(
+ "test_relaxed_rollback_protection_scheme_no_permission", config);
+ BootResult bootResult =
+ tryBootVm(TAG, "test_relaxed_rollback_protection_scheme_no_permission");
+ assertThat(bootResult.deathReason)
+ .isEqualTo(
+ VirtualMachineCallback.STOP_REASON_MICRODROID_PAYLOAD_VERIFICATION_FAILED);
+ }
- TestResults testResults =
- runVmTestService(
- TAG,
- vm,
- (ts, tr) -> {
- ts.checkLibIcuIsAccessible();
- });
+ @Test
+ public void relaxedRollbackProtectionScheme_apkDoesNotHaveRollbackIndex_bootFails()
+ throws Exception {
+ assumeSupportedDevice();
- // checkLibIcuIsAccessible will throw an exception if something goes wrong.
- assertThat(testResults.mException).isNull();
+ // This test requires additional test apk.
+ installApp("MicrodroidTestHelperAppRelaxedRollbackProtection_no_rollback_index.apk");
+
+ Context otherAppCtx =
+ getContext()
+ .createPackageContext(
+ RELAXED_ROLLBACK_PROTECTION_SCHEME_TEST_PACKAGE_NAME, 0);
+
+ VirtualMachineConfig config =
+ new VirtualMachineConfig.Builder(otherAppCtx)
+ .setDebugLevel(DEBUG_LEVEL_FULL)
+ .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+ .setProtectedVm(isProtectedVm())
+ .setOs(os())
+ .build();
+
+ VirtualMachine vm =
+ forceCreateNewVirtualMachine(
+ "test_relaxed_rollback_protection_scheme_no_rollback_index", config);
+ BootResult bootResult =
+ tryBootVm(TAG, "test_relaxed_rollback_protection_scheme_no_rollback_index");
+ assertThat(bootResult.deathReason)
+ .isEqualTo(
+ VirtualMachineCallback.STOP_REASON_MICRODROID_PAYLOAD_VERIFICATION_FAILED);
}
private static class VmShareServiceConnection implements ServiceConnection {
@@ -2881,4 +2955,40 @@
Exception e = assertThrows(VirtualMachineException.class, runnable);
assertThat(e).hasMessageThat().contains(expectedContents);
}
+
+ private void installApp(String apkName) throws Exception {
+ String apkFile = new File("/data/local/tmp/cts/microdroid/", apkName).getAbsolutePath();
+ UiAutomation uai = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ Log.i(TAG, "Installing apk " + apkFile);
+ // We read the output of the shell command not only to see if it succeeds, but also to make
+ // sure that the installation finishes. This avoids a race condition when test tries to
+ // create a context of the installed package before the installation finished.
+ try (ParcelFileDescriptor pfd = uai.executeShellCommand("pm install " + apkFile)) {
+ try (InputStream is = new FileInputStream(pfd.getFileDescriptor())) {
+ try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
+ String line;
+ while ((line = br.readLine()) != null) {
+ Log.i(TAG, line);
+ }
+ }
+ }
+ }
+ }
+
+ private void uninstallApp(String packageName) {
+ Log.i(TAG, "Uninstalling package " + packageName);
+ UiAutomation uai = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ try (ParcelFileDescriptor pfd = uai.executeShellCommand("pm uninstall " + packageName)) {
+ try (InputStream is = new FileInputStream(pfd.getFileDescriptor())) {
+ try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
+ String line;
+ while ((line = br.readLine()) != null) {
+ Log.i(TAG, line);
+ }
+ }
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to uninstall " + packageName, e);
+ }
+ }
}