Files
renovate[bot] 379ea70912 fix(deps): update module github.com/containers/storage to v1.55.0
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-26 03:04:47 +00:00

159 lines
3.9 KiB
Go

//go:build linux && cgo
// +build linux,cgo
package overlay
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"io/fs"
"os"
"os/exec"
"path/filepath"
"strings"
"sync"
"github.com/containers/storage/pkg/chunked/dump"
"github.com/containers/storage/pkg/fsverity"
"github.com/containers/storage/pkg/loopback"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)
var (
composeFsHelperOnce sync.Once
composeFsHelperPath string
composeFsHelperErr error
)
func getComposeFsHelper() (string, error) {
composeFsHelperOnce.Do(func() {
composeFsHelperPath, composeFsHelperErr = exec.LookPath("mkcomposefs")
})
return composeFsHelperPath, composeFsHelperErr
}
func getComposefsBlob(dataDir string) string {
return filepath.Join(dataDir, "composefs.blob")
}
func generateComposeFsBlob(verityDigests map[string]string, toc interface{}, composefsDir string) error {
if err := os.MkdirAll(composefsDir, 0o700); err != nil {
return err
}
dumpReader, err := dump.GenerateDump(toc, verityDigests)
if err != nil {
return err
}
destFile := getComposefsBlob(composefsDir)
writerJson, err := getComposeFsHelper()
if err != nil {
return fmt.Errorf("failed to find mkcomposefs: %w", err)
}
fd, err := unix.Openat(unix.AT_FDCWD, destFile, unix.O_WRONLY|unix.O_CREAT|unix.O_TRUNC|unix.O_EXCL|unix.O_CLOEXEC, 0o644)
if err != nil {
return &fs.PathError{Op: "openat", Path: destFile, Err: err}
}
outFd := os.NewFile(uintptr(fd), "outFd")
fd, err = unix.Open(fmt.Sprintf("/proc/self/fd/%d", outFd.Fd()), unix.O_RDONLY|unix.O_CLOEXEC, 0)
if err != nil {
outFd.Close()
return fmt.Errorf("failed to dup output file: %w", err)
}
newFd := os.NewFile(uintptr(fd), "newFd")
defer newFd.Close()
err = func() error {
// a scope to close outFd before setting fsverity on the read-only fd.
defer outFd.Close()
errBuf := &bytes.Buffer{}
cmd := exec.Command(writerJson, "--from-file", "-", "/proc/self/fd/3")
cmd.ExtraFiles = []*os.File{outFd}
cmd.Stderr = errBuf
cmd.Stdin = dumpReader
if err := cmd.Run(); err != nil {
rErr := fmt.Errorf("failed to convert json to erofs: %w", err)
exitErr := &exec.ExitError{}
if errors.As(err, &exitErr) {
return fmt.Errorf("%w: %s", rErr, strings.TrimSpace(errBuf.String()))
}
return rErr
}
return nil
}()
if err != nil {
return err
}
if err := fsverity.EnableVerity("manifest file", int(newFd.Fd())); err != nil && !errors.Is(err, unix.ENOTSUP) && !errors.Is(err, unix.ENOTTY) {
logrus.Warningf("%s", err)
}
return nil
}
/*
typedef enum {
LCFS_EROFS_FLAGS_HAS_ACL = (1 << 0),
} lcfs_erofs_flag_t;
struct lcfs_erofs_header_s {
uint32_t magic;
uint32_t version;
uint32_t flags;
uint32_t unused[5];
} __attribute__((__packed__));
*/
// hasACL returns true if the erofs blob has ACLs enabled
func hasACL(path string) (bool, error) {
const LCFS_EROFS_FLAGS_HAS_ACL = (1 << 0)
fd, err := unix.Openat(unix.AT_FDCWD, path, unix.O_RDONLY|unix.O_CLOEXEC, 0)
if err != nil {
return false, &fs.PathError{Op: "openat", Path: path, Err: err}
}
defer unix.Close(fd)
// do not worry about checking the magic number, if the file is invalid
// we will fail to mount it anyway
flags := make([]byte, 4)
nread, err := unix.Pread(fd, flags, 8)
if err != nil {
return false, fmt.Errorf("pread %q: %w", path, err)
}
if nread != 4 {
return false, fmt.Errorf("failed to read flags from %q", path)
}
return binary.LittleEndian.Uint32(flags)&LCFS_EROFS_FLAGS_HAS_ACL != 0, nil
}
func mountComposefsBlob(dataDir, mountPoint string) error {
blobFile := getComposefsBlob(dataDir)
loop, err := loopback.AttachLoopDeviceRO(blobFile)
if err != nil {
return err
}
defer loop.Close()
hasACL, err := hasACL(blobFile)
if err != nil {
return err
}
mountOpts := "ro"
if !hasACL {
mountOpts += ",noacl"
}
if err := unix.Mount(loop.Name(), mountPoint, "erofs", unix.MS_RDONLY, mountOpts); err != nil {
return fmt.Errorf("failed to mount erofs image at %q: %w", mountPoint, err)
}
return nil
}