From 29321f8a97ec1650d99ff630a05409969cc8408b Mon Sep 17 00:00:00 2001 From: Ramkumar Chinchani Date: Thu, 3 Oct 2024 20:46:15 +0000 Subject: [PATCH] refactor: decouple verity from filesystem interfaces We are going to support multiple underlying filesystems (squash, erofs and maybe more). As long as they are filesystem image blobs, verity data can be appended. Signed-off-by: Ramkumar Chinchani --- cmd/atomfs/mount.go | 2 +- cmd/atomfs/umount.go | 2 +- molecule.go | 4 +-- pkg/common/common.go | 11 ++++++++ {erofs => pkg/erofs}/erofs.go | 4 +-- pkg/erofs/fs.fo | 3 +++ {erofs => pkg/erofs}/mediatype.go | 0 {erofs => pkg/erofs}/superblock.go | 0 {erofs => pkg/erofs}/verity.go | 2 +- {erofs => pkg/erofs}/verity_static.go | 0 {erofs => pkg/erofs}/verity_test.go | 0 {log => pkg/log}/log.go | 0 {mount => pkg/mount}/mountinfo.go | 0 {squashfs => pkg/squashfs}/mediatype.go | 12 +++------ {squashfs => pkg/squashfs}/squashfs.go | 21 ++++++++++++--- {squashfs => pkg/squashfs}/superblock.go | 0 {squashfs => pkg/squashfs}/verity_static.go | 0 {squashfs => pkg/squashfs}/verity_test.go | 0 pkg/types/types.go | 14 ++++++++++ verity/mediatype.go | 10 +++++++ {squashfs => verity}/verity.go | 29 ++++----------------- 21 files changed, 71 insertions(+), 43 deletions(-) create mode 100644 pkg/common/common.go rename {erofs => pkg/erofs}/erofs.go (99%) create mode 100644 pkg/erofs/fs.fo rename {erofs => pkg/erofs}/mediatype.go (100%) rename {erofs => pkg/erofs}/superblock.go (100%) rename {erofs => pkg/erofs}/verity.go (99%) rename {erofs => pkg/erofs}/verity_static.go (100%) rename {erofs => pkg/erofs}/verity_test.go (100%) rename {log => pkg/log}/log.go (100%) rename {mount => pkg/mount}/mountinfo.go (100%) rename {squashfs => pkg/squashfs}/mediatype.go (71%) rename {squashfs => pkg/squashfs}/squashfs.go (97%) rename {squashfs => pkg/squashfs}/superblock.go (100%) rename {squashfs => pkg/squashfs}/verity_static.go (100%) rename {squashfs => pkg/squashfs}/verity_test.go (100%) create mode 100644 pkg/types/types.go create mode 100644 verity/mediatype.go rename {squashfs => verity}/verity.go (95%) diff --git a/cmd/atomfs/mount.go b/cmd/atomfs/mount.go index d0ea6b6..cf80a13 100644 --- a/cmd/atomfs/mount.go +++ b/cmd/atomfs/mount.go @@ -12,7 +12,7 @@ import ( "github.com/urfave/cli" "golang.org/x/sys/unix" "machinerun.io/atomfs" - "machinerun.io/atomfs/squashfs" + "machinerun.io/atomfs/pkg/squashfs" ) var mountCmd = cli.Command{ diff --git a/cmd/atomfs/umount.go b/cmd/atomfs/umount.go index a60a4c1..d650962 100644 --- a/cmd/atomfs/umount.go +++ b/cmd/atomfs/umount.go @@ -7,7 +7,7 @@ import ( "syscall" "github.com/urfave/cli" - "machinerun.io/atomfs/mount" + "machinerun.io/atomfs/pkg/mount" ) var umountCmd = cli.Command{ diff --git a/molecule.go b/molecule.go index 5ba3497..6823faf 100644 --- a/molecule.go +++ b/molecule.go @@ -9,8 +9,8 @@ import ( ispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" "golang.org/x/sys/unix" - "machinerun.io/atomfs/mount" - "machinerun.io/atomfs/squashfs" + "machinerun.io/atomfs/pkg/mount" + "machinerun.io/atomfs/pkg/squashfs" ) type Molecule struct { diff --git a/pkg/common/common.go b/pkg/common/common.go new file mode 100644 index 0000000..c83afc6 --- /dev/null +++ b/pkg/common/common.go @@ -0,0 +1,11 @@ +package common + +import "os" + +func FileChanged(a os.FileInfo, path string) bool { + b, err := os.Lstat(path) + if err != nil { + return true + } + return !os.SameFile(a, b) +} diff --git a/erofs/erofs.go b/pkg/erofs/erofs.go similarity index 99% rename from erofs/erofs.go rename to pkg/erofs/erofs.go index e088b71..86d37bc 100644 --- a/erofs/erofs.go +++ b/pkg/erofs/erofs.go @@ -18,8 +18,8 @@ import ( "github.com/Masterminds/semver/v3" "github.com/pkg/errors" "golang.org/x/sys/unix" - "machinerun.io/atomfs/log" - "machinerun.io/atomfs/mount" + "machinerun.io/atomfs/pkg/log" + "machinerun.io/atomfs/pkg/mount" ) var checkZstdSupported sync.Once diff --git a/pkg/erofs/fs.fo b/pkg/erofs/fs.fo new file mode 100644 index 0000000..de39a52 --- /dev/null +++ b/pkg/erofs/fs.fo @@ -0,0 +1,3 @@ +package erofs + +type erofs struct{} diff --git a/erofs/mediatype.go b/pkg/erofs/mediatype.go similarity index 100% rename from erofs/mediatype.go rename to pkg/erofs/mediatype.go diff --git a/erofs/superblock.go b/pkg/erofs/superblock.go similarity index 100% rename from erofs/superblock.go rename to pkg/erofs/superblock.go diff --git a/erofs/verity.go b/pkg/erofs/verity.go similarity index 99% rename from erofs/verity.go rename to pkg/erofs/verity.go index d0ca4d4..d678a90 100644 --- a/erofs/verity.go +++ b/pkg/erofs/verity.go @@ -77,7 +77,7 @@ import ( "github.com/martinjungblut/go-cryptsetup" "github.com/pkg/errors" "golang.org/x/sys/unix" - "machinerun.io/atomfs/mount" + "machinerun.io/atomfs/pkg/mount" ) const VerityRootHashAnnotation = "io.stackeroci.stacker.erofs_verity_root_hash" diff --git a/erofs/verity_static.go b/pkg/erofs/verity_static.go similarity index 100% rename from erofs/verity_static.go rename to pkg/erofs/verity_static.go diff --git a/erofs/verity_test.go b/pkg/erofs/verity_test.go similarity index 100% rename from erofs/verity_test.go rename to pkg/erofs/verity_test.go diff --git a/log/log.go b/pkg/log/log.go similarity index 100% rename from log/log.go rename to pkg/log/log.go diff --git a/mount/mountinfo.go b/pkg/mount/mountinfo.go similarity index 100% rename from mount/mountinfo.go rename to pkg/mount/mountinfo.go diff --git a/squashfs/mediatype.go b/pkg/squashfs/mediatype.go similarity index 71% rename from squashfs/mediatype.go rename to pkg/squashfs/mediatype.go index 051fe9b..5c33c95 100644 --- a/squashfs/mediatype.go +++ b/pkg/squashfs/mediatype.go @@ -3,21 +3,17 @@ package squashfs import ( "fmt" "strings" + + "machinerun.io/atomfs/verity" ) type SquashfsCompression string -type VerityMetadata bool const ( BaseMediaTypeLayerSquashfs = "application/vnd.stacker.image.layer.squashfs" GzipCompression SquashfsCompression = "gzip" ZstdCompression SquashfsCompression = "zstd" - - veritySuffix = "verity" - - VerityMetadataPresent VerityMetadata = true - VerityMetadataMissing VerityMetadata = false ) func IsSquashfsMediaType(mediaType string) bool { @@ -27,11 +23,11 @@ func IsSquashfsMediaType(mediaType string) bool { func GenerateSquashfsMediaType(comp SquashfsCompression, verity VerityMetadata) string { verityString := "" if verity { - verityString = fmt.Sprintf("+%s", veritySuffix) + verityString = fmt.Sprintf("+%s", verity.VeritySuffix) } return fmt.Sprintf("%s+%s%s", BaseMediaTypeLayerSquashfs, comp, verityString) } func HasVerityMetadata(mediaType string) VerityMetadata { - return VerityMetadata(strings.HasSuffix(mediaType, veritySuffix)) + return VerityMetadata(strings.HasSuffix(mediaType, verity.VeritySuffix)) } diff --git a/squashfs/squashfs.go b/pkg/squashfs/squashfs.go similarity index 97% rename from squashfs/squashfs.go rename to pkg/squashfs/squashfs.go index 328b061..f7cdebd 100644 --- a/squashfs/squashfs.go +++ b/pkg/squashfs/squashfs.go @@ -18,8 +18,10 @@ import ( "github.com/Masterminds/semver/v3" "github.com/pkg/errors" "golang.org/x/sys/unix" - "machinerun.io/atomfs/log" - "machinerun.io/atomfs/mount" + "machinerun.io/atomfs/pkg/common" + "machinerun.io/atomfs/pkg/log" + "machinerun.io/atomfs/pkg/mount" + _ "machinerun.io/atomfs/verity" ) var checkZstdSupported sync.Once @@ -168,7 +170,7 @@ func MakeSquashfs(tempdir string, rootfs string, eps *ExcludePaths, verity Verit } if verity { - rootHash, err = appendVerityData(tmpSquashfs.Name()) + rootHash, err = verity.AppendVerityData(tmpSquashfs.Name()) if err != nil { return nil, "", rootHash, err } @@ -366,7 +368,7 @@ func squashFuse(squashFile, extractDir string) (*exec.Cmd, error) { } } } - for count := 0; !fileChanged(fiPre, extractDir); count++ { + for count := 0; !common.FileChanged(fiPre, extractDir); count++ { if cmd.ProcessState != nil { // process exited, the Wait() call in the goroutine above // caused ProcessState to be populated. @@ -742,3 +744,14 @@ func whichSearch(name string, paths []string) string { return "" } + +func verityDataLocation(sblock *superblock) (uint64, error) { + squashLen := sblock.size + + // squashfs is padded out to the nearest 4k + if squashLen%4096 != 0 { + squashLen = squashLen + (4096 - squashLen%4096) + } + + return squashLen, nil +} diff --git a/squashfs/superblock.go b/pkg/squashfs/superblock.go similarity index 100% rename from squashfs/superblock.go rename to pkg/squashfs/superblock.go diff --git a/squashfs/verity_static.go b/pkg/squashfs/verity_static.go similarity index 100% rename from squashfs/verity_static.go rename to pkg/squashfs/verity_static.go diff --git a/squashfs/verity_test.go b/pkg/squashfs/verity_test.go similarity index 100% rename from squashfs/verity_test.go rename to pkg/squashfs/verity_test.go diff --git a/pkg/types/types.go b/pkg/types/types.go new file mode 100644 index 0000000..3892022 --- /dev/null +++ b/pkg/types/types.go @@ -0,0 +1,14 @@ +package types + +type FileSystem interface { + // Mount a filesystem as container root, without host root privileges. + GuestMount(squashFile string, mountpoint string) error + + Mount(squashfs, mountpoint, rootHash string) error + + HostMount(squashfs string, mountpoint string, rootHash string) error + + Umount(mountpoint string) error + + VerityDataLocation() uint64 +} diff --git a/verity/mediatype.go b/verity/mediatype.go new file mode 100644 index 0000000..6333e79 --- /dev/null +++ b/verity/mediatype.go @@ -0,0 +1,10 @@ +package verity + +type VerityMetadata bool + +const ( + VeritySuffix = "verity" + + VerityMetadataPresent VerityMetadata = true + VerityMetadataMissing VerityMetadata = false +) diff --git a/squashfs/verity.go b/verity/verity.go similarity index 95% rename from squashfs/verity.go rename to verity/verity.go index 6642f86..b81275b 100644 --- a/squashfs/verity.go +++ b/verity/verity.go @@ -1,4 +1,4 @@ -package squashfs +package verity // #cgo pkg-config: libcryptsetup devmapper --static // #include @@ -77,7 +77,7 @@ import ( "github.com/martinjungblut/go-cryptsetup" "github.com/pkg/errors" "golang.org/x/sys/unix" - "machinerun.io/atomfs/mount" + "machinerun.io/atomfs/pkg/mount" ) const VerityRootHashAnnotation = "io.stackeroci.stacker.squashfs_verity_root_hash" @@ -130,7 +130,7 @@ func isCryptsetupEINVAL(err error) bool { var cryptsetupTooOld = errors.Errorf("libcryptsetup not new enough, need >= 2.3.0") -func appendVerityData(file string) (string, error) { +func AppendVerityData(file string) (string, error) { fi, err := os.Lstat(file) if err != nil { return "", errors.WithStack(err) @@ -179,27 +179,8 @@ func appendVerityData(file string) (string, error) { return fmt.Sprintf("%x", rootHash), errors.WithStack(err) } -func verityDataLocation(sblock *superblock) (uint64, error) { - squashLen := sblock.size - - // squashfs is padded out to the nearest 4k - if squashLen%4096 != 0 { - squashLen = squashLen + (4096 - squashLen%4096) - } - - return squashLen, nil -} - func verityName(p string) string { - return fmt.Sprintf("%s-%s", p, veritySuffix) -} - -func fileChanged(a os.FileInfo, path string) bool { - b, err := os.Lstat(path) - if err != nil { - return true - } - return !os.SameFile(a, b) + return fmt.Sprintf("%s-%s", p, VeritySuffix) } // Mount a filesystem as container root, without host root @@ -454,7 +435,7 @@ func Umount(mountpoint string) error { // was this a verity mount or a regular loopback mount? (if it's a // regular loopback mount, we detached it above, so need to do anything // special here; verity doesn't play as nicely) - if strings.HasSuffix(theMount.Source, veritySuffix) { + if strings.HasSuffix(theMount.Source, VeritySuffix) { // find the loop device that backs the verity device deviceNo, err := findLoopBackingVerity(theMount.Source) if err != nil {