From 820120db7345433823e266ebf40005eac6ff6826 Mon Sep 17 00:00:00 2001 From: Michael McCracken Date: Fri, 27 Sep 2024 18:23:04 -0700 Subject: [PATCH] verity: check after activation for any corruption (#18) * verity: check after activation for any corruption ActivateByVolumeKey does check for corruption via the dm_status task after activation, but if it finds that it was corrupted, it only logs that to stderr and returns 0 anyway. For cases where corruption can be detected immediately, we want to fail the mounting, so we add a second check of the same task after activating the device (or after checking the hash on an existing device), and fail early. Signed-off-by: Michael McCracken * verity: also check corruption in existing mounts If we are mounting a mol where one of the atoms already been mounted, then we should check the already-mounted devices for any corruption reported by devicemapper as well, and at least fail to mount the new image using them. Signed-off-by: Michael McCracken --------- Signed-off-by: Michael McCracken --- molecule.go | 4 ++++ squashfs/verity.go | 52 +++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/molecule.go b/molecule.go index 5ba3497..619bec5 100644 --- a/molecule.go +++ b/molecule.go @@ -61,6 +61,10 @@ func (m Molecule) mountUnderlyingAtoms() error { if err != nil { return err } + err = squashfs.ConfirmExistingVerityDeviceCurrentValidity(mountpoint.Source) + if err != nil { + return err + } } continue } diff --git a/squashfs/verity.go b/squashfs/verity.go index 6642f86..c274772 100644 --- a/squashfs/verity.go +++ b/squashfs/verity.go @@ -6,7 +6,7 @@ package squashfs // #include // #include /* -int get_verity_params(char *device, char **params) +int get_verity_params(char *device, char **params, int task_type) { struct dm_task *dmt; struct dm_info dmi; @@ -14,7 +14,7 @@ int get_verity_params(char *device, char **params) uint64_t start, length; char *type, *tmpParams; - dmt = dm_task_create(DM_DEVICE_TABLE); + dmt = dm_task_create(task_type); if (!dmt) return 1; @@ -59,6 +59,16 @@ out: dm_task_destroy(dmt); return r; } +int get_verity_table_params(char *device, char **params) +{ + return get_verity_params(device, params, DM_DEVICE_TABLE); +} + +int get_verity_status_params(char *device, char **params) +{ + return get_verity_params(device, params, DM_DEVICE_STATUS); +} + */ import "C" @@ -369,6 +379,17 @@ func HostMount(squashfs string, mountpoint string, rootHash string) error { return err } } + + // we have to check `dmsetup status $device` here because + // ActivateByVolumeKey will return some errors but will only WARN to + // stderr if corruption was found just after activation. It will + // reliably return success for a corrupted image, and we need to check + // the same thing it checks for its warning. + err = ConfirmExistingVerityDeviceCurrentValidity(verityDevPath) + if err != nil { + return err + } + } else { loopDev, err = losetup.Attach(squashfs, 0, true) if err != nil { @@ -497,7 +518,7 @@ func ConfirmExistingVerityDeviceHash(devicePath string, rootHash string, allowVe var cParams *C.char - rc := C.get_verity_params(cDevice, &cParams) + rc := C.get_verity_table_params(cDevice, &cParams) if rc != 0 { if allowVerityFailure { return nil @@ -520,3 +541,28 @@ func ConfirmExistingVerityDeviceHash(devicePath string, rootHash string, allowVe return nil } + +func ConfirmExistingVerityDeviceCurrentValidity(devicePath string) error { + device := filepath.Base(devicePath) + cDevice := C.CString(device) + defer C.free(unsafe.Pointer(cDevice)) + + var cParams *C.char + + rc := C.get_verity_status_params(cDevice, &cParams) + if rc != 0 { + return errors.Errorf("problem getting dm params from %v: %v", device, rc) + } + defer C.free(unsafe.Pointer(cParams)) + + params := C.GoString(cParams) + + if len(params) != 1 { + return errors.Errorf("invalid params for dm status for %q: %+v", device, params) + } + // valid values are "C": corruption has been found, or "V": no corruption found, yet. + if params != "V" { + return errors.Errorf("verity reports corruption on device %q", device) + } + return nil +}