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