From 3057b595c40a1347f43e5a90d0f77c1b794949bc Mon Sep 17 00:00:00 2001 From: Ramkumar Chinchani Date: Mon, 28 Oct 2024 20:03:08 +0000 Subject: [PATCH 1/3] feat: add support for erofs layers atomfs has added support for additional filesystem types such as erofs. Signed-off-by: Ramkumar Chinchani --- .github/workflows/coverage.yaml | 2 +- cmd/stacker/build.go | 11 +- cmd/stacker/inspect.go | 2 +- cmd/stacker/internal_go.go | 8 +- cmd/stacker/publish.go | 6 +- cmd/stacker/validate.go | 2 + go.mod | 3 +- go.sum | 8 +- install-build-deps.sh | 7 + pkg/lib/image_test.go | 5 +- pkg/overlay/metadata.go | 2 +- pkg/overlay/pack.go | 18 ++- pkg/types/layer_type.go | 37 +++-- test/atomfs-erofs.bats | 164 +++++++++++++++++++++ test/{atomfs.bats => atomfs-squashfs.bats} | 4 +- 15 files changed, 234 insertions(+), 45 deletions(-) create mode 100644 test/atomfs-erofs.bats rename test/{atomfs.bats => atomfs-squashfs.bats} (98%) diff --git a/.github/workflows/coverage.yaml b/.github/workflows/coverage.yaml index dc634f19..0d7bfd8d 100644 --- a/.github/workflows/coverage.yaml +++ b/.github/workflows/coverage.yaml @@ -32,7 +32,7 @@ on: jobs: build: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 services: registry: image: ghcr.io/project-stacker/registry:2 diff --git a/cmd/stacker/build.go b/cmd/stacker/build.go index a46ea050..3568cbbb 100644 --- a/cmd/stacker/build.go +++ b/cmd/stacker/build.go @@ -4,7 +4,7 @@ import ( "fmt" cli "github.com/urfave/cli/v2" - "machinerun.io/atomfs/squashfs" + "machinerun.io/atomfs/pkg/verity" "stackerbuild.io/stacker/pkg/stacker" "stackerbuild.io/stacker/pkg/types" ) @@ -52,12 +52,13 @@ func initCommonBuildFlags() []cli.Flag { }, &cli.StringSliceFlag{ Name: "layer-type", - Usage: "set the output layer type (supported values: tar, squashfs); can be supplied multiple times", + Usage: "set the output layer type (supported values: tar, squashfs, erofs); can be supplied multiple times", Value: cli.NewStringSlice("tar"), }, &cli.BoolFlag{ - Name: "no-squashfs-verity", - Usage: "do not append dm-verity data to squashfs archives", + Name: "no-verity", + Usage: "do not append dm-verity data to fs archives", + Aliases: []string{"no-squashfs-verity"}, }, &cli.BoolFlag{ Name: "require-hash", @@ -103,7 +104,7 @@ func newBuildArgs(ctx *cli.Context) (stacker.BuildArgs, error) { AnnotationsNamespace: ctx.String("annotations-namespace"), } var err error - verity := squashfs.VerityMetadata(!ctx.Bool("no-squashfs-verity")) + verity := verity.VerityMetadata(!ctx.Bool("no-verity")) args.LayerTypes, err = types.NewLayerTypes(ctx.StringSlice("layer-type"), verity) return args, err } diff --git a/cmd/stacker/inspect.go b/cmd/stacker/inspect.go index 43aeaee9..554de4b1 100644 --- a/cmd/stacker/inspect.go +++ b/cmd/stacker/inspect.go @@ -11,7 +11,7 @@ import ( "github.com/opencontainers/umoci/oci/casext" "github.com/pkg/errors" cli "github.com/urfave/cli/v2" - stackeroci "machinerun.io/atomfs/oci" + stackeroci "machinerun.io/atomfs/pkg/oci" ) var inspectCmd = cli.Command{ diff --git a/cmd/stacker/internal_go.go b/cmd/stacker/internal_go.go index c161c895..2888e518 100644 --- a/cmd/stacker/internal_go.go +++ b/cmd/stacker/internal_go.go @@ -9,7 +9,7 @@ import ( "github.com/pkg/errors" cli "github.com/urfave/cli/v2" "golang.org/x/sys/unix" - "machinerun.io/atomfs" + "machinerun.io/atomfs/pkg/molecule" "stackerbuild.io/stacker/pkg/lib" "stackerbuild.io/stacker/pkg/log" "stackerbuild.io/stacker/pkg/overlay" @@ -176,14 +176,14 @@ func doAtomfsMount(ctx *cli.Context) error { tag := ctx.Args().Get(0) mountpoint := ctx.Args().Get(1) - opts := atomfs.MountOCIOpts{ + opts := molecule.MountOCIOpts{ OCIDir: config.OCIDir, Tag: tag, Target: mountpoint, AllowMissingVerityData: true, } - mol, err := atomfs.BuildMoleculeFromOCI(opts) + mol, err := molecule.BuildMoleculeFromOCI(opts) if err != nil { return err } @@ -199,5 +199,5 @@ func doAtomfsUmount(ctx *cli.Context) error { } mountpoint := ctx.Args().Get(0) - return atomfs.Umount(mountpoint) + return molecule.Umount(mountpoint) } diff --git a/cmd/stacker/publish.go b/cmd/stacker/publish.go index 3eff0bb3..86ce6e64 100644 --- a/cmd/stacker/publish.go +++ b/cmd/stacker/publish.go @@ -3,7 +3,7 @@ package main import ( "github.com/pkg/errors" cli "github.com/urfave/cli/v2" - "machinerun.io/atomfs/squashfs" + "machinerun.io/atomfs/pkg/verity" "stackerbuild.io/stacker/pkg/lib" "stackerbuild.io/stacker/pkg/stacker" "stackerbuild.io/stacker/pkg/types" @@ -69,7 +69,7 @@ var publishCmd = cli.Command{ }, &cli.StringSliceFlag{ Name: "layer-type", - Usage: "set the output layer type (supported values: tar, squashfs); can be supplied multiple times", + Usage: "set the output layer type (supported values: tar, squashfs, erofs); can be supplied multiple times", Value: cli.NewStringSlice("tar"), }, &cli.StringSliceFlag{ @@ -108,7 +108,7 @@ func beforePublish(ctx *cli.Context) error { } func doPublish(ctx *cli.Context) error { - verity := squashfs.VerityMetadata(!ctx.Bool("no-squashfs-verity")) + verity := verity.VerityMetadata(!ctx.Bool("no-verity")) layerTypes, err := types.NewLayerTypes(ctx.StringSlice("layer-type"), verity) if err != nil { return err diff --git a/cmd/stacker/validate.go b/cmd/stacker/validate.go index 87a4033c..37dec461 100644 --- a/cmd/stacker/validate.go +++ b/cmd/stacker/validate.go @@ -50,6 +50,8 @@ func validateLayerTypeFlags(ctx *cli.Context) error { break case "squashfs": break + case "erofs": + break default: return errors.Errorf("unknown layer type: %s", layerType) } diff --git a/go.mod b/go.mod index f5c5e7bc..9ec39960 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/mitchellh/hashstructure v1.1.0 github.com/moby/buildkit v0.11.4 github.com/opencontainers/go-digest v1.0.0 - github.com/opencontainers/image-spec v1.1.0-rc4 + github.com/opencontainers/image-spec v1.1.0 github.com/opencontainers/umoci v0.4.8-0.20220412065115-12453f247749 github.com/pkg/errors v0.9.1 github.com/pkg/xattr v0.4.9 @@ -290,5 +290,6 @@ require ( replace ( github.com/opencontainers/umoci => github.com/project-stacker/umoci v0.0.0-20240906174318-e9397ba4ced0 + machinerun.io/atomfs => github.com/rchincha/atomfs v0.0.0-20250223060538-baa0a62678d1 stackerbuild.io/stacker-bom => github.com/project-stacker/stacker-bom v0.0.0-20240509203427-4d685e046780 ) diff --git a/go.sum b/go.sum index e24672f3..923ab13e 100644 --- a/go.sum +++ b/go.sum @@ -754,8 +754,8 @@ github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3ev github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/image-spec v1.1.0-rc4 h1:oOxKUJWnFC4YGHCCMNql1x4YaDfYBTS5Y4x/Cgeo1E0= -github.com/opencontainers/image-spec v1.1.0-rc4/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= +github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/opencontainers/runc v1.2.3 h1:fxE7amCzfZflJO2lHXf4y/y8M1BoAqp+FVmG19oYB80= github.com/opencontainers/runc v1.2.3/go.mod h1:nSxcWUydXrsBZVYNSkTjoQ/N6rcyTtn+1SD5D4+kRIM= github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk= @@ -821,6 +821,8 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/rchincha/atomfs v0.0.0-20250223060538-baa0a62678d1 h1:ES5uKUitazGmNIg1HhYkodWWBvClU/E5hgWp66dXfuc= +github.com/rchincha/atomfs v0.0.0-20250223060538-baa0a62678d1/go.mod h1:jrGbuGXiCPi4LFoMvcPRnqPGlxe3pW8UtLEnhUcGRmI= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= @@ -1598,8 +1600,6 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -machinerun.io/atomfs v1.1.3 h1:oV1SH7VI2MqAks7FlirhLLKvyVcJkMB0NFevXF8EJaU= -machinerun.io/atomfs v1.1.3/go.mod h1:qXz4epm3/7vEpEyf9YaTCafp3CwbUeDa1XrYyx7qbPc= modernc.org/libc v1.37.6 h1:orZH3c5wmhIQFTXF+Nt+eeauyd+ZIt2BX6ARe+kD+aw= modernc.org/libc v1.37.6/go.mod h1:YAXkAZ8ktnkCKaN9sw/UDeUVkGYJ/YquGO4FTi5nmHE= modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= diff --git a/install-build-deps.sh b/install-build-deps.sh index e7cf38dd..56ef799c 100755 --- a/install-build-deps.sh +++ b/install-build-deps.sh @@ -44,6 +44,8 @@ installdeps_ubuntu() { squashfuse libarchive-tools shellcheck + erofs-utils + erofsfuse ) case "$VERSION_ID" in @@ -86,6 +88,11 @@ installdeps_ubuntu() { sudo apt -yy install golang-go go version fi + + # cloud kernels, like linux-azure, don't include erofs in the linux-modules package and instead put it linux-modules-extra + if ! modinfo erofs &>/dev/null; then + sudo apt -yy install linux-modules-extra-$(uname -r) + fi } enable_userns() { diff --git a/pkg/lib/image_test.go b/pkg/lib/image_test.go index db532a03..c387fa49 100644 --- a/pkg/lib/image_test.go +++ b/pkg/lib/image_test.go @@ -13,7 +13,8 @@ import ( "github.com/opencontainers/umoci/mutate" "github.com/opencontainers/umoci/oci/casext" "github.com/stretchr/testify/assert" - "machinerun.io/atomfs/squashfs" + "machinerun.io/atomfs/pkg/squashfs" + "machinerun.io/atomfs/pkg/verity" ) func createImage(dir string, tag string) error { @@ -48,7 +49,7 @@ func createImage(dir string, tag string) error { // need *something* in the layer, why not just recursively include the // OCI image for maximum confusion :) - layer, mediaType, _, err := squashfs.MakeSquashfs(dir, path.Join(dir, "oci"), nil, squashfs.VerityMetadataMissing) + layer, mediaType, _, err := squashfs.MakeSquashfs(dir, path.Join(dir, "oci"), nil, verity.VerityMetadataMissing) if err != nil { return err } diff --git a/pkg/overlay/metadata.go b/pkg/overlay/metadata.go index 27f4daa6..5901b9e3 100644 --- a/pkg/overlay/metadata.go +++ b/pkg/overlay/metadata.go @@ -10,7 +10,7 @@ import ( ispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/opencontainers/umoci/oci/casext" "github.com/pkg/errors" - stackeroci "machinerun.io/atomfs/oci" + stackeroci "machinerun.io/atomfs/pkg/oci" "stackerbuild.io/stacker/pkg/log" "stackerbuild.io/stacker/pkg/types" ) diff --git a/pkg/overlay/pack.go b/pkg/overlay/pack.go index 1053e306..4ef069f1 100644 --- a/pkg/overlay/pack.go +++ b/pkg/overlay/pack.go @@ -22,8 +22,10 @@ import ( "github.com/opencontainers/umoci/oci/layer" "github.com/pkg/errors" "github.com/pkg/xattr" - stackeroci "machinerun.io/atomfs/oci" - "machinerun.io/atomfs/squashfs" + stackerfs "machinerun.io/atomfs/pkg/fs" + stackeroci "machinerun.io/atomfs/pkg/oci" + fstypes "machinerun.io/atomfs/pkg/types" + "machinerun.io/atomfs/pkg/verity" "stackerbuild.io/stacker/pkg/lib" "stackerbuild.io/stacker/pkg/log" "stackerbuild.io/stacker/pkg/storage" @@ -280,7 +282,8 @@ func generateBlob(layerType types.LayerType, contents string, ociDir string, low blob = layer.GenerateInsertLayer(contents, "/", false, &packOptions) mediaType = ispec.MediaTypeImageLayer } else { - blob, mediaType, rootHash, err = squashfs.MakeSquashfs(ociDir, contents, nil, layerType.Verity) + fsi := stackerfs.New(fstypes.FilesystemType(layerType.Type)) + blob, mediaType, rootHash, err = fsi.Make(ociDir, contents, nil, layerType.Verity) if err != nil { return nil, "", "", err } @@ -303,7 +306,7 @@ func ociPutBlob(blob io.ReadCloser, config types.StackerConfig, layerMediaType s annotations := map[string]string{} if rootHash != "" { - annotations[squashfs.VerityRootHashAnnotation] = rootHash + annotations[verity.VerityRootHashAnnotation] = rootHash } desc := ispec.Descriptor{ @@ -443,7 +446,7 @@ func generateLayer(config types.StackerConfig, _ casext.Engine, mutators []*muta } else { annotations := map[string]string{} if rootHash != "" { - annotations[squashfs.VerityRootHashAnnotation] = rootHash + annotations[verity.VerityRootHashAnnotation] = rootHash } desc, err = mutator.Add(context.Background(), mediaType, blob, history, mutate.NoopCompressor, annotations) if err != nil { @@ -693,10 +696,11 @@ func unpackOne(l ispec.Descriptor, ociDir string, extractDir string) error { return nil } - if squashfs.IsSquashfsMediaType(l.MediaType) { - return squashfs.ExtractSingleSquash( + if fsi := stackerfs.NewFromMediaType(l.MediaType); fsi != nil { + return fsi.ExtractSingle( path.Join(ociDir, "blobs", "sha256", l.Digest.Encoded()), extractDir) } + switch l.MediaType { case ispec.MediaTypeImageLayer, ispec.MediaTypeImageLayerGzip: tarEx.Lock() diff --git a/pkg/types/layer_type.go b/pkg/types/layer_type.go index 8430a404..dbab430a 100644 --- a/pkg/types/layer_type.go +++ b/pkg/types/layer_type.go @@ -7,14 +7,16 @@ import ( ispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" - "machinerun.io/atomfs/squashfs" + "machinerun.io/atomfs/pkg/erofs" + "machinerun.io/atomfs/pkg/squashfs" + "machinerun.io/atomfs/pkg/verity" ) var ErrEmptyLayers = errors.New("empty layers") type LayerType struct { Type string - Verity squashfs.VerityMetadata + Verity verity.VerityMetadata } func (lt LayerType) String() string { @@ -44,14 +46,14 @@ func (lt *LayerType) UnmarshalText(text []byte) error { return errors.Wrapf(err, "bad verity bool: %s", fields[1]) } - lt.Verity = squashfs.VerityMetadata(result) + lt.Verity = verity.VerityMetadata(result) return nil } -func NewLayerType(lt string, verity squashfs.VerityMetadata) (LayerType, error) { +func NewLayerType(lt string, verity verity.VerityMetadata) (LayerType, error) { switch lt { - case "squashfs": + case "squashfs", "erofs": return LayerType{Type: lt, Verity: verity}, nil case "tar": return LayerType{Type: lt}, nil @@ -62,31 +64,38 @@ func NewLayerType(lt string, verity squashfs.VerityMetadata) (LayerType, error) func NewLayerTypeManifest(manifest ispec.Manifest) (LayerType, error) { if len(manifest.Layers) == 0 { - return NewLayerType("tar", squashfs.VerityMetadataMissing) + return NewLayerType("tar", verity.VerityMetadataMissing) } + _, verityMetadataPresent := manifest.Layers[0].Annotations[verity.VerityRootHashAnnotation] + switch manifest.Layers[0].MediaType { case squashfs.BaseMediaTypeLayerSquashfs: // older stackers generated media types without compression information fallthrough - case squashfs.GenerateSquashfsMediaType(squashfs.GzipCompression, squashfs.VerityMetadataMissing): + case squashfs.GenerateSquashfsMediaType(squashfs.GzipCompression): + fallthrough + case squashfs.GenerateSquashfsMediaType(squashfs.ZstdCompression): + return NewLayerType("squashfs", verity.VerityMetadata(verityMetadataPresent)) + case erofs.BaseMediaTypeLayerErofs: + // older stackers generated media types without compression information + fallthrough + case erofs.GenerateErofsMediaType(erofs.LZ4HCCompression): fallthrough - case squashfs.GenerateSquashfsMediaType(squashfs.ZstdCompression, squashfs.VerityMetadataMissing): - return NewLayerType("squashfs", squashfs.VerityMetadataMissing) - case squashfs.GenerateSquashfsMediaType(squashfs.GzipCompression, squashfs.VerityMetadataPresent): + case erofs.GenerateErofsMediaType(erofs.LZ4Compression): fallthrough - case squashfs.GenerateSquashfsMediaType(squashfs.ZstdCompression, squashfs.VerityMetadataPresent): - return NewLayerType("squashfs", squashfs.VerityMetadataPresent) + case erofs.GenerateErofsMediaType(erofs.ZstdCompression): + return NewLayerType("erofs", verity.VerityMetadata(verityMetadataPresent)) case ispec.MediaTypeImageLayerGzip: fallthrough case ispec.MediaTypeImageLayer: - return NewLayerType("tar", squashfs.VerityMetadataMissing) + return NewLayerType("tar", verity.VerityMetadataMissing) default: return LayerType{}, errors.Errorf("invalid layer type %s", manifest.Layers[0].MediaType) } } -func NewLayerTypes(lts []string, verity squashfs.VerityMetadata) ([]LayerType, error) { +func NewLayerTypes(lts []string, verity verity.VerityMetadata) ([]LayerType, error) { ret := []LayerType{} for _, lt := range lts { hoisted, err := NewLayerType(lt, verity) diff --git a/test/atomfs-erofs.bats b/test/atomfs-erofs.bats new file mode 100644 index 00000000..2662faf6 --- /dev/null +++ b/test/atomfs-erofs.bats @@ -0,0 +1,164 @@ +load helpers + +function setup() { + stacker_setup +} + +function teardown() { + cleanup +} + +function verity_checkusedloops() { + # search for loopdevices which have backing files with the current + # BATS_TEST_DIRNAME value and complain if they're present. + local usedloops="" found="" x="" + for ((x=0; x<5; x++)); do + usedloops=$(losetup -a | grep $BATS_TEST_DIRNAME || echo) + if [ -n "$usedloops" ]; then + found=1 + udevadm settle + else + return 0 + fi + done + echo "found used loops in testdir=$BATS_TEST_DIRNAME :$usedloops" >&3 + [ $found = 1 ] +} + +function basic_test() { + require_privilege priv + local verity_arg=$1 + + cat > stacker.yaml <<"EOF" +test: + from: + type: oci + url: ${{BUSYBOX_OCI}} + run: | + touch /hello +EOF + stacker build --layer-type=erofs $verity_arg --substitute BUSYBOX_OCI=${BUSYBOX_OCI} + mkdir mountpoint + stacker internal-go atomfs mount test-erofs mountpoint + + [ -f mountpoint/hello ] + stacker internal-go atomfs umount mountpoint +} + +@test "--no-verity works" { + basic_test --no-verity + verity_checkusedloops +} + +@test "mount + umount works" { + basic_test + + # last layer shouldn't exist any more, since it is unique + manifest=$(cat oci/index.json | jq -r .manifests[0].digest | cut -f2 -d:) + last_layer_num=$(($(cat oci/blobs/sha256/$manifest | jq -r '.layers | length')-1)) + last_layer_hash=$(cat oci/blobs/sha256/$manifest | jq -r .layers[$last_layer].digest | cut -f2 -d:) + [ ! -b "/dev/mapper/$last_layer_hash-verity" ] + verity_checkusedloops +} + +@test "mount + umount + mount a tree of images works" { + require_privilege priv + cat > stacker.yaml <<"EOF" +base: + from: + type: oci + url: ${{BUSYBOX_OCI}} + run: touch /base +a: + from: + type: built + tag: base + run: touch /a +b: + from: + type: built + tag: base + run: touch /b +c: + from: + type: built + tag: base + run: touch /c +EOF + stacker build --layer-type=erofs --substitute BUSYBOX_OCI=${BUSYBOX_OCI} + + mkdir a + stacker internal-go atomfs mount a-erofs a + [ -f a/a ] + + mkdir b + stacker internal-go atomfs mount b-erofs b + [ -f b/b ] + + cat /proc/self/mountinfo + echo "mountinfo after b^" + + stacker internal-go atomfs umount b + + # first layer should still exist since a is still mounted + manifest=$(cat oci/index.json | jq -r .manifests[0].digest | cut -f2 -d:) + first_layer_hash=$(cat oci/blobs/sha256/$manifest | jq -r .layers[0].digest | cut -f2 -d:) + [ -b "/dev/mapper/$first_layer_hash-verity" ] + + mkdir c + stacker internal-go atomfs mount c-erofs c + [ -f c/c ] + + cat /proc/self/mountinfo + echo "mountinfo after c^" + + stacker internal-go atomfs umount a + + cat /proc/self/mountinfo + echo "mountinfo after umount a^" + + # first layer should still exist since c is still mounted + manifest=$(cat oci/index.json | jq -r .manifests[0].digest | cut -f2 -d:) + first_layer_hash=$(cat oci/blobs/sha256/$manifest | jq -r .layers[0].digest | cut -f2 -d:) + [ -b "/dev/mapper/$first_layer_hash-verity" ] + + # c should still be ok + [ -f c/c ] + [ -f c/bin/sh ] + stacker internal-go atomfs umount c + + # c's last layer shouldn't exist any more, since it is unique + manifest=$(cat oci/index.json | jq -r .manifests[0].digest | cut -f2 -d:) + last_layer_num=$(($(cat oci/blobs/sha256/$manifest | jq -r '.layers | length')-1)) + last_layer_hash=$(cat oci/blobs/sha256/$manifest | jq -r .layers[$last_layer_num].digest | cut -f2 -d:) + [ ! -b "/dev/mapper/$last_layer_hash-verity" ] + verity_checkusedloops +} + +@test "bad existing verity device is rejected" { + require_privilege priv + cat > stacker.yaml <<"EOF" +test: + from: + type: oci + url: ${{BUSYBOX_OCI}} + run: | + touch /hello +EOF + stacker build --layer-type=erofs --substitute BUSYBOX_OCI=${BUSYBOX_OCI} + + manifest=$(cat oci/index.json | jq -r .manifests[0].digest | cut -f2 -d:) + first_layer_hash=$(cat oci/blobs/sha256/$manifest | jq -r .layers[0].digest | cut -f2 -d:) + devname="$first_layer_hash-verity" + + # make an evil device and fake it as an existing verity device + dd if=/dev/random of=mydev bs=50K count=1 + root_hash=$(veritysetup format mydev mydev.hash | grep "Root hash:" | awk '{print $NF}') + echo "root hash $root_hash" + veritysetup open mydev "$devname" mydev.hash "$root_hash" + + mkdir mountpoint + bad_stacker internal-go atomfs mount test-erofs mountpoint | grep "invalid root hash" + veritysetup close "$devname" + verity_checkusedloops +} diff --git a/test/atomfs.bats b/test/atomfs-squashfs.bats similarity index 98% rename from test/atomfs.bats rename to test/atomfs-squashfs.bats index 5857cb89..dd5118d8 100644 --- a/test/atomfs.bats +++ b/test/atomfs-squashfs.bats @@ -45,8 +45,8 @@ EOF stacker internal-go atomfs umount mountpoint } -@test "--no-squashfs-verity works" { - basic_test --no-squashfs-verity +@test "--no-verity works" { + basic_test --no-verity verity_checkusedloops } From d81ee5b992fc651b63bd7ea653144d3bab8955d8 Mon Sep 17 00:00:00 2001 From: Ramkumar Chinchani Date: Sat, 22 Mar 2025 15:38:04 -0700 Subject: [PATCH 2/3] fix: use atomfs v1.2.0 Signed-off-by: Ramkumar Chinchani --- go.mod | 3 +-- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 9ec39960..f84cf866 100644 --- a/go.mod +++ b/go.mod @@ -278,7 +278,7 @@ require ( gopkg.in/square/go-jose.v2 v2.6.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - machinerun.io/atomfs v1.1.3 + machinerun.io/atomfs v1.2.0 modernc.org/libc v1.37.6 // indirect modernc.org/mathutil v1.6.0 // indirect modernc.org/memory v1.7.2 // indirect @@ -290,6 +290,5 @@ require ( replace ( github.com/opencontainers/umoci => github.com/project-stacker/umoci v0.0.0-20240906174318-e9397ba4ced0 - machinerun.io/atomfs => github.com/rchincha/atomfs v0.0.0-20250223060538-baa0a62678d1 stackerbuild.io/stacker-bom => github.com/project-stacker/stacker-bom v0.0.0-20240509203427-4d685e046780 ) diff --git a/go.sum b/go.sum index 923ab13e..64529ae4 100644 --- a/go.sum +++ b/go.sum @@ -821,8 +821,6 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/rchincha/atomfs v0.0.0-20250223060538-baa0a62678d1 h1:ES5uKUitazGmNIg1HhYkodWWBvClU/E5hgWp66dXfuc= -github.com/rchincha/atomfs v0.0.0-20250223060538-baa0a62678d1/go.mod h1:jrGbuGXiCPi4LFoMvcPRnqPGlxe3pW8UtLEnhUcGRmI= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= @@ -1600,6 +1598,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +machinerun.io/atomfs v1.2.0 h1:w2YtDncppFjOKWGeK0yfgCYcB5dJIZSngVHb6UWljv0= +machinerun.io/atomfs v1.2.0/go.mod h1:jrGbuGXiCPi4LFoMvcPRnqPGlxe3pW8UtLEnhUcGRmI= modernc.org/libc v1.37.6 h1:orZH3c5wmhIQFTXF+Nt+eeauyd+ZIt2BX6ARe+kD+aw= modernc.org/libc v1.37.6/go.mod h1:YAXkAZ8ktnkCKaN9sw/UDeUVkGYJ/YquGO4FTi5nmHE= modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= From 96e1d27eaf1c43db78d73b314ca2c40dacd9b928 Mon Sep 17 00:00:00 2001 From: Ramkumar Chinchani Date: Sat, 22 Mar 2025 15:59:04 -0700 Subject: [PATCH 3/3] ci: use our own cached images instead of upstream Signed-off-by: Ramkumar Chinchani --- .github/workflows/build.yaml | 2 +- .github/workflows/coverage.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 87462e01..39393628 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -70,7 +70,7 @@ jobs: echo "running kernel is: $(uname -a)" - name: docker-clone run: | - make docker-clone "STACKER_DOCKER_BASE=docker://" CLONE_D="$PWD/.build/oci-clone" + make docker-clone "STACKER_DOCKER_BASE=docker://ghcr.io/project-stacker/" CLONE_D="$PWD/.build/oci-clone" - name: Go-download run: | make go-download diff --git a/.github/workflows/coverage.yaml b/.github/workflows/coverage.yaml index 0d7bfd8d..4bcc2fa8 100644 --- a/.github/workflows/coverage.yaml +++ b/.github/workflows/coverage.yaml @@ -71,7 +71,7 @@ jobs: echo "running kernel is: $(uname -a)" - name: docker-clone run: | - make docker-clone "STACKER_DOCKER_BASE=docker://" CLONE_D="$PWD/.build/oci-clone" + make docker-clone "STACKER_DOCKER_BASE=docker://ghcr.io/project-stacker/" CLONE_D="$PWD/.build/oci-clone" - name: Go-download run: | make go-download