summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Victor Hsieh <victorhsieh@google.com> 2025-03-07 10:41:53 -0800
committer Eric Biggers <ebiggers@google.com> 2025-03-14 16:38:28 +0000
commit7ea42a51cba85c08cd6ea1aa8aa31952bdb18e2a (patch)
tree742dd0d502cc79699f4959a2ea899e5a1f3e4239
parentcfe6940d65597cfb2b9cfd47d881bdcee9f6f21d (diff)
Update test expectation in FsVerityHostTest for 16K page
Test: 'atest FsVerityTest' on devices with 4K, 16K, and "simulated" 16K page size Bug: 397562534 Flag: TEST_ONLY Change-Id: I53662a16415a2471a7ac27559123a0e42f6ea762
-rw-r--r--tests/FsVerityTest/FsVerityTestApp/src/com/android/fsverity/Helper.java63
-rw-r--r--tests/FsVerityTest/src/com/android/fsverity/FsVerityHostTest.java21
2 files changed, 56 insertions, 28 deletions
diff --git a/tests/FsVerityTest/FsVerityTestApp/src/com/android/fsverity/Helper.java b/tests/FsVerityTest/FsVerityTestApp/src/com/android/fsverity/Helper.java
index c52be7c2b0c6..8e012598c9eb 100644
--- a/tests/FsVerityTest/FsVerityTestApp/src/com/android/fsverity/Helper.java
+++ b/tests/FsVerityTest/FsVerityTestApp/src/com/android/fsverity/Helper.java
@@ -21,7 +21,10 @@ import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
import android.content.Context;
+import android.os.Bundle;
import android.security.FileIntegrityManager;
+import android.system.Os;
+import android.system.OsConstants;
import android.util.Log;
import androidx.test.core.app.ApplicationProvider;
@@ -35,8 +38,9 @@ import org.junit.Test;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
-import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
/**
* Test helper that works with the host-side test to set up a test file, and to verify fs-verity
@@ -47,8 +51,6 @@ public class Helper {
private static final String FILENAME = "test.file";
- private static final long BLOCK_SIZE = 4096;
-
@Rule
public final AdoptShellPermissionsRule mAdoptShellPermissionsRule =
new AdoptShellPermissionsRule(
@@ -58,7 +60,7 @@ public class Helper {
@Test
public void prepareTest() throws Exception {
Context context = ApplicationProvider.getApplicationContext();
- android.os.Bundle testArgs = InstrumentationRegistry.getArguments();
+ Bundle testArgs = InstrumentationRegistry.getArguments();
String basename = testArgs.getString("basename");
context.deleteFile(basename);
@@ -84,31 +86,52 @@ public class Helper {
fim.setupFsVerity(context.getFileStreamPath(basename));
}
+ private static long getPageSize() {
+ String arch = System.getProperty("os.arch");
+ Log.d(TAG, "os.arch=" + arch);
+ if ("x86_64".equals(arch)) {
+ // Override the fake 16K page size from cf_x86_64_pgagnostic. The real page size on
+ // x86_64 is always 4K. This test needs the real page size because it is testing I/O
+ // error reporting behavior that is dependent on the real page size.
+ return 4096;
+ }
+ return Os.sysconf(OsConstants._SC_PAGE_SIZE);
+ }
+
@Test
public void verifyFileRead() throws Exception {
Context context = ApplicationProvider.getApplicationContext();
- // Collect indices that the backing blocks are supposed to be corrupted.
- android.os.Bundle testArgs = InstrumentationRegistry.getArguments();
+ Bundle testArgs = InstrumentationRegistry.getArguments();
assertThat(testArgs).isNotNull();
String filePath = testArgs.getString("filePath");
- String csv = testArgs.getString("brokenBlockIndicesCsv");
- Log.d(TAG, "brokenBlockIndicesCsv: " + csv);
- String[] strings = csv.split(",");
- var corrupted = new ArrayList(strings.length);
- for (int i = 0; i < strings.length; i++) {
- corrupted.add(Integer.parseInt(strings[i]));
+ String csv = testArgs.getString("brokenByteIndicesCsv");
+ Log.d(TAG, "brokenByteIndicesCsv: " + csv);
+
+ // Build the set of pages that contain a corrupted byte.
+ final long pageSize = getPageSize();
+ Set<Long> corruptedPageIndices = new HashSet();
+ for (String s : csv.split(",")) {
+ long byteIndex = Long.parseLong(s);
+ long pageIndex = byteIndex / pageSize;
+ corruptedPageIndices.add(pageIndex);
}
-
- // Expect the read to succeed or fail per the prior.
- try (var file = new RandomAccessFile(filePath, "r")) {
- long total_blocks = (file.length() + BLOCK_SIZE - 1) / BLOCK_SIZE;
- for (int i = 0; i < (int) total_blocks; i++) {
- file.seek(i * BLOCK_SIZE);
- if (corrupted.contains(i)) {
- Log.d(TAG, "Expecting read at block #" + i + " to fail");
+ Log.d(TAG, "corruptedPageIndices=" + corruptedPageIndices);
+
+ // Read bytes from the file and verify the expected result based on the containing page.
+ // (The kernel reports fs-verity errors at page granularity.)
+ final long stride = 1024;
+ // Using a stride that is a divisor of the page size ensures that the last page is tested.
+ assertThat(pageSize % stride).isEqualTo(0);
+ try (RandomAccessFile file = new RandomAccessFile(filePath, "r")) {
+ for (long byteIndex = 0; byteIndex < file.length(); byteIndex += stride) {
+ file.seek(byteIndex);
+ long pageIndex = byteIndex / pageSize;
+ if (corruptedPageIndices.contains(pageIndex)) {
+ Log.d(TAG, "Expecting read at byte #" + byteIndex + " to fail");
assertThrows(IOException.class, () -> file.read());
} else {
+ Log.d(TAG, "Expecting read at byte #" + byteIndex + " to succeed");
assertThat(file.readByte()).isEqualTo('1');
}
}
diff --git a/tests/FsVerityTest/src/com/android/fsverity/FsVerityHostTest.java b/tests/FsVerityTest/src/com/android/fsverity/FsVerityHostTest.java
index b1d6e96dca9b..88d9e9e08dce 100644
--- a/tests/FsVerityTest/src/com/android/fsverity/FsVerityHostTest.java
+++ b/tests/FsVerityTest/src/com/android/fsverity/FsVerityHostTest.java
@@ -33,13 +33,12 @@ import org.junit.runner.RunWith;
/**
* This test verifies fs-verity works end-to-end. There is a corresponding helper app.
*
- * <p>The helper app uses a FileIntegrityManager API to enable fs-verity to a file. The host test
- * here * tampers with the file's backing storage, then tells the helper app to read and expect
+ * <p>The helper app uses a FileIntegrityManager API to enable fs-verity on a file. The host test
+ * here tampers with the file's backing storage, then tells the helper app to read and expect
* success/failure on read.
*
- * <p>In order to make sure a block of the file is readable only if the underlying block on disk
- * stay intact, the test needs to bypass the filesystem and tampers with the corresponding physical
- * address against the block device.
+ * <p>Since the filesystem by design provides no way to corrupt fs-verity files itself, the test
+ * needs to bypass the filesystem and write directly to the block device to corrupt the files.
*/
@RootPermissionTest
@RunWith(DeviceJUnit4ClassRunner.class)
@@ -57,7 +56,7 @@ public class FsVerityHostTest extends BaseHostJUnit4Test {
BlockDeviceWriter.damageFileAgainstBlockDevice(device, getTargetFilePath(), 8192);
BlockDeviceWriter.dropCaches(device);
- verifyRead(getTargetFilePath(), "0,2");
+ verifyRead(getTargetFilePath(), "0,8192");
}
@Test
@@ -70,7 +69,7 @@ public class FsVerityHostTest extends BaseHostJUnit4Test {
BlockDeviceWriter.damageFileAgainstBlockDevice(device, getTargetFilePath(), 128 * 4096 + 1);
BlockDeviceWriter.dropCaches(device);
- verifyRead(getTargetFilePath(), "1,100,128");
+ verifyRead(getTargetFilePath(), "4096,409600,524289");
}
private String getTargetFilePath() throws DeviceNotAvailableException {
@@ -87,11 +86,17 @@ public class FsVerityHostTest extends BaseHostJUnit4Test {
assertThat(runDeviceTests(options)).isTrue();
}
+ /**
+ * Verifies the read success/failure expectation given the corrupted byte indices in the file.
+ *
+ * @param path the remote file path to read.
+ * @param indicesCsv a comma-separated list of indices of bytes that were corrupted.
+ */
private void verifyRead(String path, String indicesCsv) throws Exception {
DeviceTestRunOptions options = new DeviceTestRunOptions(TARGET_PACKAGE);
options.setTestClassName(TARGET_PACKAGE + ".Helper");
options.setTestMethodName("verifyFileRead");
- options.addInstrumentationArg("brokenBlockIndicesCsv", indicesCsv);
+ options.addInstrumentationArg("brokenByteIndicesCsv", indicesCsv);
options.addInstrumentationArg("filePath", getTargetFilePath());
assertThat(runDeviceTests(options)).isTrue();
}