fflash: Add flag to skip disabling rootfs verification
This is useful on the rare occurrence to do testing on readonly rootfs.
BUG=None
TEST=go test ./...
TEST=ninja
TEST=bin/integration-test $dut
Change-Id: If63c2878289c8b85969959f41deaf7384ee28ec5
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/dev-util/+/3947886
Tested-by: Li-Yu Yu <aaronyu@google.com>
Reviewed-by: Terry Cheong <htcheong@chromium.org>
Commit-Queue: Li-Yu Yu <aaronyu@google.com>
diff --git a/contrib/fflash/cmd/integration-test/main.go b/contrib/fflash/cmd/integration-test/main.go
index 7a61492..f8a29cc 100644
--- a/contrib/fflash/cmd/integration-test/main.go
+++ b/contrib/fflash/cmd/integration-test/main.go
@@ -41,16 +41,22 @@
log.Fatal("failed to verify junk after writing:", err)
}
- // Flash without clobbering.
- if err := internal.CLIMain(ctx, t0, []string{target}); err != nil {
+ // Flash without clobbering, with rootfs verification.
+ if err := internal.CLIMain(ctx, t0, []string{target, "--rootfs-verification=yes"}); err != nil {
log.Fatal("non-clobbering flash failed:", err)
}
+ // Check rootfs verification is not disabled.
+ if err := checkRootfsVerification(ctx, target, true); err != nil {
+ log.Fatal("check for enabled rootfs verification failed: ", err)
+ }
+
+ // Check the junk file is still there.
if err := verifyJunk(ctx, target); err != nil {
log.Fatal("failed to verify junk after non-clobbering flash:", err)
}
- // Flash again with clobber
+ // Flash again with clobber, without rootfs verification.
if err := internal.CLIMain(ctx, t0, []string{target, "--clobber-stateful=yes"}); err != nil {
log.Fatal("clobbering flash failed:", err)
}
@@ -62,6 +68,11 @@
log.Fatal("junk file is not removed after clobbering flash")
}
+ // Check rootfs verification is disabled.
+ if err := checkRootfsVerification(ctx, target, false); err != nil {
+ log.Fatal("check for disabled rootfs verification failed: ", err)
+ }
+
log.Println("integration test complete")
}
@@ -90,3 +101,22 @@
return nil
}
+
+// checkRootfsVerification returns whether rootfs verification is in the desired state.
+func checkRootfsVerification(ctx context.Context, target string, enabled bool) error {
+ cmd := ssh.DefaultCommand(ctx)
+ cmd.Args = append(cmd.Args, target,
+ // Check that rootfs verification is disabled.
+ "/usr/libexec/debugd/helpers/dev_features_rootfs_verification", "-q",
+ )
+ if enabled {
+ // Invert the exit status. Doing so in shell allows us to distinguish
+ // ssh failures from dev_features_rootfs_verification returning non-zero.
+ //
+ // If dev_features_rootfs_verification fails, then exit 0 is executed.
+ // If dev_features_rootfs_verification succeeds, then exit 0 is skipped, exit 1 is executed.
+ cmd.Args = append(cmd.Args, "||", "exit", "0", "&&", "exit", "1")
+ }
+
+ return cmd.Run()
+}
diff --git a/contrib/fflash/internal/cli.go b/contrib/fflash/internal/cli.go
index 83b1c5a..273460a 100644
--- a/contrib/fflash/internal/cli.go
+++ b/contrib/fflash/internal/cli.go
@@ -28,6 +28,11 @@
app.Flag("board",
"flash from gs://chromeos-image-archive/${board}-release/R*. Use with caution!").
StringVar(&opts.Board)
+ rootfsVerification := app.Flag(
+ "rootfs-verification",
+ "whether rootfs verification on the new root is enabled. "+
+ "Choices: yes, no (default)",
+ ).Default(no).Enum(yes, no)
clobberStateful := app.Flag(
"clobber-stateful",
"whether to clobber the stateful partition. Choices: yes, no (default)").Default(no).Enum(yes, no)
@@ -46,6 +51,7 @@
opts.ReleaseNum = r
opts.ReleaseString = ""
}
+ opts.DisableRootfsVerification = (*rootfsVerification == no)
opts.ClobberStateful = (*clobberStateful == yes)
if *clearTpmOwner == auto {
opts.ClearTpmOwner = opts.ClobberStateful
diff --git a/contrib/fflash/internal/cli_test.go b/contrib/fflash/internal/cli_test.go
index 4026d6c..6523300 100644
--- a/contrib/fflash/internal/cli_test.go
+++ b/contrib/fflash/internal/cli_test.go
@@ -23,15 +23,20 @@
"defaults": {
args: []string{"dut"},
target: "dut",
- opts: Options{},
+ opts: Options{
+ FlashOptions: dut.FlashOptions{
+ DisableRootfsVerification: true,
+ },
+ },
},
"clobber": {
args: []string{"dut", "--clobber-stateful=yes"},
target: "dut",
opts: Options{
FlashOptions: dut.FlashOptions{
- ClobberStateful: true,
- ClearTpmOwner: true, // follows --clobber-stateful by default
+ DisableRootfsVerification: true,
+ ClobberStateful: true,
+ ClearTpmOwner: true, // follows --clobber-stateful by default
},
},
},
@@ -40,8 +45,18 @@
target: "dut",
opts: Options{
FlashOptions: dut.FlashOptions{
- ClobberStateful: true,
- ClearTpmOwner: false,
+ DisableRootfsVerification: true,
+ ClobberStateful: true,
+ ClearTpmOwner: false,
+ },
+ },
+ },
+ "disable-rootfs-verification": {
+ args: []string{"dut", "--rootfs-verification=yes"},
+ target: "dut",
+ opts: Options{
+ FlashOptions: dut.FlashOptions{
+ DisableRootfsVerification: false,
},
},
},
diff --git a/contrib/fflash/internal/dut/main.go b/contrib/fflash/internal/dut/main.go
index d92706c..8119154 100644
--- a/contrib/fflash/internal/dut/main.go
+++ b/contrib/fflash/internal/dut/main.go
@@ -87,10 +87,12 @@
result := &Result{}
- log.Println("disabling rootfs verification")
- if err := DisableRootfsVerification(ctx, partState.InactiveKernelNum); err != nil {
- log.Printf("disable rootfs verification failed (will retry after reboot): %s", err)
- result.RetryDisableRootfsVerification = true
+ if r.DisableRootfsVerification {
+ log.Println("disabling rootfs verification")
+ if err := DisableRootfsVerification(ctx, partState.InactiveKernelNum); err != nil {
+ log.Printf("disable rootfs verification failed (will retry after reboot): %s", err)
+ result.RetryDisableRootfsVerification = true
+ }
}
if r.ClearTpmOwner {
diff --git a/contrib/fflash/internal/dut/request.go b/contrib/fflash/internal/dut/request.go
index 620c251..b0bbd42 100644
--- a/contrib/fflash/internal/dut/request.go
+++ b/contrib/fflash/internal/dut/request.go
@@ -26,8 +26,9 @@
// Unlike Request.Bucket, Request.Directory, these are determined solely by
// parsing the command line without further processing.
type FlashOptions struct {
- ClobberStateful bool // whether to clobber the stateful partition
- ClearTpmOwner bool // whether to clean tpm owner on reboot
+ DisableRootfsVerification bool // whether to disable rootfs verification
+ ClobberStateful bool // whether to clobber the stateful partition
+ ClearTpmOwner bool // whether to clean tpm owner on reboot
}
type Result struct {
diff --git a/contrib/fflash/internal/main.go b/contrib/fflash/internal/main.go
index 1d05851..cea1b98 100644
--- a/contrib/fflash/internal/main.go
+++ b/contrib/fflash/internal/main.go
@@ -207,8 +207,10 @@
}
}
- if _, err := sshClient.RunSimpleOutput(devFeaturesRootfsVerification + " -q"); err != nil {
- return fmt.Errorf("failed to check rootfs verification: %w", err)
+ if opts.DisableRootfsVerification {
+ if _, err := sshClient.RunSimpleOutput(devFeaturesRootfsVerification + " -q"); err != nil {
+ return fmt.Errorf("failed to check rootfs verification: %w", err)
+ }
}
return nil