diff --git a/drivers/overlay/composefs_notsupported.go b/drivers/overlay/composefs_notsupported.go index 273ef4699d..75eae0affb 100644 --- a/drivers/overlay/composefs_notsupported.go +++ b/drivers/overlay/composefs_notsupported.go @@ -18,3 +18,7 @@ func generateComposeFsBlob(toc []byte, destFile string) error { func mountErofsBlob(blobFile, mountPoint string) error { return fmt.Errorf("composefs is not supported") } + +func enableVerityRecursive(path string) error { + return fmt.Errorf("composefs is not supported") +} diff --git a/drivers/overlay/composefs_supported.go b/drivers/overlay/composefs_supported.go index 1578134f28..79e6738202 100644 --- a/drivers/overlay/composefs_supported.go +++ b/drivers/overlay/composefs_supported.go @@ -5,12 +5,18 @@ package overlay import ( "bytes" + "errors" "fmt" + "io/fs" "os" "os/exec" + "path/filepath" "sync" + "syscall" + "unsafe" "github.com/containers/storage/pkg/loopback" + "github.com/sirupsen/logrus" "golang.org/x/sys/unix" ) @@ -32,6 +38,43 @@ func composeFsSupported() bool { return err == nil } +func enableVerity(description string, fd int) error { + enableArg := unix.FsverityEnableArg{ + Version: 1, + Hash_algorithm: unix.FS_VERITY_HASH_ALG_SHA256, + Block_size: 4096, + } + + _, _, e1 := syscall.Syscall(unix.SYS_IOCTL, uintptr(fd), uintptr(unix.FS_IOC_ENABLE_VERITY), uintptr(unsafe.Pointer(&enableArg))) + if e1 != 0 { + return fmt.Errorf("failed to enable verity for %q: %w", description, e1) + } + return nil +} + +func enableVerityRecursive(path string) error { + walkFn := func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + if !d.Type().IsRegular() { + return nil + } + + f, err := os.Open(path) + if err != nil { + return err + } + defer f.Close() + + if err := enableVerity(path, int(f.Fd())); err != nil { + return err + } + return nil + } + return filepath.WalkDir(path, walkFn) +} + func generateComposeFsBlob(toc []byte, destFile string) error { writerJson, err := getComposeFsHelper() if err != nil { @@ -42,14 +85,33 @@ func generateComposeFsBlob(toc []byte, destFile string) error { if err != nil { return fmt.Errorf("failed to open output file: %w", err) } - defer unix.Close(outFd) - cmd := exec.Command(writerJson, "--format=erofs", fmt.Sprintf("--out=/proc/self/fd/%d", outFd), "/proc/self/fd/0") - cmd.ExtraFiles = []*os.File{os.NewFile(uintptr(outFd), "outFd")} - cmd.Stdin = bytes.NewReader(toc) - cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { - return fmt.Errorf("failed to convert json to erofs: %w", err) + newFd, err := unix.Open(fmt.Sprintf("/proc/self/fd/%d", outFd), unix.O_RDONLY, 0) + if err != nil { + unix.Close(outFd) + return fmt.Errorf("failed to dup output file: %w", err) + } + defer unix.Close(newFd) + + err = func() error { + defer unix.Close(outFd) + + cmd := exec.Command(writerJson, "--format=erofs", fmt.Sprintf("--out=/proc/self/fd/%d", outFd), "/proc/self/fd/0") + cmd.ExtraFiles = []*os.File{os.NewFile(uintptr(outFd), "outFd")} + cmd.Stderr = os.Stderr + cmd.Stdin = bytes.NewReader(toc) + if err := cmd.Run(); err != nil { + return fmt.Errorf("failed to convert json to erofs: %w", err) + } + return nil + }() + if err != nil { + return err + } + + if err := enableVerity("manifest file", newFd); err != nil && !errors.Is(err, unix.ENOTSUP) && !errors.Is(err, unix.ENOTTY) { + logrus.Warningf("%s", err) } + return nil } diff --git a/drivers/overlay/overlay.go b/drivers/overlay/overlay.go index a4e6b7d3ca..3170f09645 100644 --- a/drivers/overlay/overlay.go +++ b/drivers/overlay/overlay.go @@ -2064,6 +2064,11 @@ func (d *Driver) ApplyDiffFromStagingDirectory(id, parent, stagingDirectory stri } if d.useComposeFs() { + // FIXME: move this logic into the differ so we don't have to open + // the file twice. + if err := enableVerityRecursive(stagingDirectory); err != nil && !errors.Is(err, unix.ENOTSUP) && !errors.Is(err, unix.ENOTTY) { + logrus.Warningf("%s", err) + } toc := diffOutput.BigData[zstdChunkedManifest] if err := generateComposeFsBlob(toc, d.getErofsBlob(id)); err != nil { return err