1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.fsverity; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import android.platform.test.annotations.RequiresFlagsEnabled; 22 import android.platform.test.annotations.RootPermissionTest; 23 import android.platform.test.flag.junit.CheckFlagsRule; 24 import android.platform.test.flag.junit.host.HostFlagsValueProvider; 25 import android.security.Flags; 26 27 import com.android.blockdevicewriter.BlockDeviceWriter; 28 import com.android.tradefed.device.DeviceNotAvailableException; 29 import com.android.tradefed.device.ITestDevice; 30 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; 31 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; 32 import com.android.tradefed.testtype.junit4.DeviceTestRunOptions; 33 34 import org.junit.Rule; 35 import org.junit.Test; 36 import org.junit.runner.RunWith; 37 38 /** 39 * This test verifies fs-verity works end-to-end. There is a corresponding helper app. 40 * 41 * <p>The helper app uses a FileIntegrityManager API to enable fs-verity to a file. The host test 42 * here * tampers with the file's backing storage, then tells the helper app to read and expect 43 * success/failure on read. 44 * 45 * <p>In order to make sure a block of the file is readable only if the underlying block on disk 46 * stay intact, the test needs to bypass the filesystem and tampers with the corresponding physical 47 * address against the block device. 48 */ 49 @RootPermissionTest 50 @RunWith(DeviceJUnit4ClassRunner.class) 51 @RequiresFlagsEnabled(Flags.FLAG_FSVERITY_API) 52 public class FsVerityHostTest extends BaseHostJUnit4Test { 53 private static final String TARGET_PACKAGE = "com.android.fsverity"; 54 55 private static final String BASENAME = "test.file"; 56 57 @Rule 58 public final CheckFlagsRule mCheckFlagsRule = 59 HostFlagsValueProvider.createCheckFlagsRule(this::getDevice); 60 61 @Test testFsVeritySmallFile()62 public void testFsVeritySmallFile() throws Exception { 63 prepareTest(10000); 64 65 ITestDevice device = getDevice(); 66 BlockDeviceWriter.damageFileAgainstBlockDevice(device, getTargetFilePath(), 0); 67 BlockDeviceWriter.damageFileAgainstBlockDevice(device, getTargetFilePath(), 8192); 68 BlockDeviceWriter.dropCaches(device); 69 70 verifyRead(getTargetFilePath(), "0,2"); 71 } 72 73 @Test testFsVerityLargerFileWithOneMoreMerkleTreeLevel()74 public void testFsVerityLargerFileWithOneMoreMerkleTreeLevel() throws Exception { 75 prepareTest(128 * 4096 + 1); 76 77 ITestDevice device = getDevice(); 78 BlockDeviceWriter.damageFileAgainstBlockDevice(device, getTargetFilePath(), 4096); 79 BlockDeviceWriter.damageFileAgainstBlockDevice(device, getTargetFilePath(), 100 * 4096); 80 BlockDeviceWriter.damageFileAgainstBlockDevice(device, getTargetFilePath(), 128 * 4096 + 1); 81 BlockDeviceWriter.dropCaches(device); 82 83 verifyRead(getTargetFilePath(), "1,100,128"); 84 } 85 getTargetFilePath()86 private String getTargetFilePath() throws DeviceNotAvailableException { 87 return "/data/user/" + getDevice().getCurrentUser() + "/" + TARGET_PACKAGE + "/files/" 88 + BASENAME; 89 } 90 prepareTest(int fileSize)91 private void prepareTest(int fileSize) throws Exception { 92 DeviceTestRunOptions options = new DeviceTestRunOptions(TARGET_PACKAGE); 93 options.setTestClassName(TARGET_PACKAGE + ".Helper"); 94 options.setTestMethodName("prepareTest"); 95 options.addInstrumentationArg("basename", BASENAME); 96 options.addInstrumentationArg("fileSize", String.valueOf(fileSize)); 97 assertThat(runDeviceTests(options)).isTrue(); 98 } 99 verifyRead(String path, String indicesCsv)100 private void verifyRead(String path, String indicesCsv) throws Exception { 101 DeviceTestRunOptions options = new DeviceTestRunOptions(TARGET_PACKAGE); 102 options.setTestClassName(TARGET_PACKAGE + ".Helper"); 103 options.setTestMethodName("verifyFileRead"); 104 options.addInstrumentationArg("brokenBlockIndicesCsv", indicesCsv); 105 options.addInstrumentationArg("filePath", getTargetFilePath()); 106 assertThat(runDeviceTests(options)).isTrue(); 107 } 108 } 109