Skip to content

Commit

Permalink
refactor: decouple verity from filesystem interfaces
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
rchincha committed Oct 4, 2024
1 parent c01a838 commit 01d76b1
Show file tree
Hide file tree
Showing 23 changed files with 195 additions and 43 deletions.
2 changes: 1 addition & 1 deletion cmd/atomfs/mount.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down
2 changes: 1 addition & 1 deletion cmd/atomfs/umount.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"syscall"

"github.com/urfave/cli"
"machinerun.io/atomfs/mount"
"machinerun.io/atomfs/pkg/mount"
)

var umountCmd = cli.Command{
Expand Down
4 changes: 2 additions & 2 deletions molecule.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
11 changes: 11 additions & 0 deletions pkg/common/common.go
Original file line number Diff line number Diff line change
@@ -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)
}
4 changes: 2 additions & 2 deletions erofs/erofs.go → pkg/erofs/erofs.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
38 changes: 38 additions & 0 deletions pkg/erofs/fs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package erofs

import (
"io"

"machinerun.io/atomfs/verity"
)

type erofs struct {
}

func New() *erofs {
return &erofs{}
}

func (fs *erofs) Make(tempdir string, rootfs string, eps *ExcludePaths, verity verity.VerityMetadata) (io.ReadCloser, string, string, error) {
}

// Mount a filesystem as container root, without host root privileges.
func (fs *erofs) GuestMount(fsFile string, mountpoint string) error {
return nil
}

func (fs *erofs) Mount(fsFile, mountpoint, rootHash string) error {
return nil
}

func (fs *erofs) HostMount(fsFile string, mountpoint string, rootHash string) error {
return nil
}

func (fs *erofs) Umount(mountpoint string) error {
return nil
}

func (fs *erofs) VerityDataLocation() uint64 {
return 0
}
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion erofs/verity.go → pkg/erofs/verity.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
File renamed without changes.
File renamed without changes.
30 changes: 30 additions & 0 deletions pkg/fs/fs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package fs

import (
"machinerun.io/atomfs/pkg/erofs"
"machinerun.io/atomfs/pkg/squashfs"
"machinerun.io/atomfs/pkg/types"
)

// New creates a filesystem instance.
func New(fsType types.FilesystemType) types.Filesystem {
switch fsType {
case types.Squashfs:
return squashfs.New()
case types.Erofs:
return erofs.New()
default:
return nil
}
}

// NewFromMediaType creates a filesystem instance based on media-type.
func NewFromMediaType(mediaType string) types.Filesystem {
if squashfs.IsSquashfsMediaType(mediaType) {
return New(types.Squashfs)
} else if erofs.IsErofsMediaType(mediaType) {
return New(types.Erofs)
}

return nil
}
File renamed without changes.
File renamed without changes.
41 changes: 41 additions & 0 deletions pkg/squashfs/fs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package squashfs

import (
"io"

"machinerun.io/atomfs/verity"
)

type squashfs struct {
}

func New() *squashfs {
return &squashfs{}
}

func (fs *squashfs) Make(tempdir string, rootfs string, eps *ExcludePaths, verity verity.VerityMetadata) (io.ReadCloser, string, string, error) {
}

// Mount a filesystem as container root, without host root privileges.
func (fs *squashfs) GuestMount(fsFile string, mountpoint string) error {
return nil
}

func (fs *squashfs) Mount(fsFile, mountpoint, rootHash string) error {
return nil
}

func (fs *squashfs) HostMount(fsFile string, mountpoint string, rootHash string) error {
return nil
}

func (fs *squashfs) Umount(mountpoint string) error {
return nil
}

func (fs *squashfs) VerityDataLocation() uint64 {
return 0
}

func (fs *squashfs) ExtractSingle(fsFile string, extractDir string) error {
}
12 changes: 4 additions & 8 deletions squashfs/mediatype.go → pkg/squashfs/mediatype.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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))
}
21 changes: 17 additions & 4 deletions squashfs/squashfs.go → pkg/squashfs/squashfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
32 changes: 32 additions & 0 deletions pkg/types/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package types

import (
"io"

"machinerun.io/atomfs/verity"
)

type Filesystem interface {
// Make a filesystem image.
Make(tempdir string, rootfs string, eps *ExcludePaths, verity verity.VerityMetadata) (io.ReadCloser, string, string, error)

// Mount a filesystem as container root, without host root privileges.
GuestMount(fsFile string, mountpoint string) error

Mount(fs, mountpoint, rootHash string) error

HostMount(fs string, mountpoint string, rootHash string) error

Umount(mountpoint string) error

VerityDataLocation() uint64

ExtractSingle(fsFile string, extractDir string) error
}

type FilesystemType string

const (
Squashfs FilesystemType = "squashfs"
Erofs FilesystemType = "erofs"
)
10 changes: 10 additions & 0 deletions verity/mediatype.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package verity

type VerityMetadata bool

const (
VeritySuffix = "verity"

VerityMetadataPresent VerityMetadata = true
VerityMetadataMissing VerityMetadata = false
)
29 changes: 5 additions & 24 deletions squashfs/verity.go → verity/verity.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package squashfs
package verity

// #cgo pkg-config: libcryptsetup devmapper --static
// #include <libcryptsetup.h>
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down

0 comments on commit 01d76b1

Please sign in to comment.