Skip to content

Commit

Permalink
Create fsverity IsSupported function
Browse files Browse the repository at this point in the history
Check the Linux kernel version and test if fsverity is able to be
executed on a file to determine if Linux systems have fsverity
capabilities.

Signed-off-by: James Jenkins <James.Jenkins@ibm.com>
  • Loading branch information
Jenkins-J committed Mar 27, 2024
1 parent 4d1f5a5 commit 244f093
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 61 deletions.
21 changes: 21 additions & 0 deletions pkg/fsverity/fsverity_linux.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//go:build linux

/*
Copyright The containerd Authors.
Expand All @@ -19,9 +21,11 @@ package fsverity
import (
"fmt"
"os"
"sync"
"syscall"
"unsafe"

"github.com/containerd/containerd/v2/contrib/seccomp/kernelversion"
"golang.org/x/sys/unix"
)

Expand All @@ -48,6 +52,23 @@ const (
maxDigestSize uint16 = 64
)

var (
once sync.Once
supported bool
)

func IsSupported() bool {
once.Do(func () {
minKernelVersion := kernelversion.KernelVersion{Kernel: 5, Major: 4}
s, err := kernelversion.GreaterEqualThan(minKernelVersion)
if err != nil {
supported = false
}
supported = s
})
return supported
}

func IsEnabled(path string) (bool, error) {
f, err := os.Open(path)
if err != nil {
Expand Down
7 changes: 7 additions & 0 deletions pkg/fsverity/fsverity_other.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//go:build !linux

package fsverity

func IsSupported() bool {
return false
}
33 changes: 0 additions & 33 deletions plugins/content/local/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,13 @@ import (
"io"
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
"sync"
"time"

"github.com/containerd/containerd/v2/content"
"github.com/containerd/containerd/v2/filters"
"github.com/containerd/containerd/v2/pkg/fsverity"
"github.com/containerd/errdefs"
"github.com/containerd/log"

Expand Down Expand Up @@ -132,37 +130,6 @@ func (s *store) ReaderAt(ctx context.Context, desc ocispec.Descriptor) (content.

log.G(ctx).Debugf("Getting reader for blob %v", p)

if runtime.GOOS == "linux" {
log.G(ctx).Debugf("verifying blob with fsverity")
// check that fsverity is enabled on the blob before reading
// if not, it may not be trustworthy
enabled, err := fsverity.IsEnabled(p)
if err != nil {
log.G(ctx).WithError(err).Errorf("Error checking fsverity status of blob %s: %s", p, err.Error())
}
if !enabled {
log.G(ctx).Warnf("fsverity not enabled on blob %s", p)
} else {
verityDigest, merr := fsverity.Measure(p)
if merr != nil {
log.G(ctx).WithField("blob", p).Errorf("failed to take fsverity measurement of blob: %s", merr.Error())
} else {
log.G(ctx).Debugf("comparing measured digest to known good value")
// compare the digest to the "good" value stored in the blob label
blobInfo, err := s.Info(ctx, desc.Digest)
if err != nil {
log.G(ctx).Errorf("failed to retrieve good fsverity digest from store: %s", err.Error())
} else {
if verityDigest != blobInfo.Labels["fsverity_digest"] {
log.G(ctx).Errorf("fsverity digest does not match known good value, expected: %s; got: %s", blobInfo.Labels["fsverity_digest"], verityDigest)
log.G(ctx).Debugf("blob labels: %v", blobInfo.Labels)
return nil, fmt.Errorf("blob is not trusted, fsverity digest failed verification")
}
}
}
}
}

reader, err := OpenReader(p)
if err != nil {
return nil, fmt.Errorf("blob %s expected at %s: %w", desc.Digest, p, err)
Expand Down
28 changes: 0 additions & 28 deletions plugins/content/local/writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import (
"time"

"github.com/containerd/containerd/v2/core/content"
"github.com/containerd/containerd/v2/pkg/fsverity"
"github.com/containerd/errdefs"
"github.com/containerd/log"
"github.com/opencontainers/go-digest"
Expand Down Expand Up @@ -138,33 +137,6 @@ func (w *writer) Commit(ctx context.Context, size int64, expected digest.Digest,
return err
}

if runtime.GOOS == "linux" {
log.G(ctx).Debugf("enabling fsverity on blob %v", target)
// Enable fsverity digest verification on the blob
if err := fsverity.Enable(target); err != nil {
log.G(ctx).WithField("ref", w.ref).Errorf("failed to enable fsverity verification: %s", err.Error())
} else {
verityDigest, merr := fsverity.Measure(target)
if merr != nil {
log.G(ctx).WithField("ref", w.ref).Errorf("failed to take fsverity measurement of blob: %s", merr.Error())
} else {
log.G(ctx).Debugf("storing \"good\" digest value in metadata database")

// store the fsverity digest for later comparison
//
// TODO: find how to add content labels in the metadata database
// the 'content store' is not able to store labels on its own
//
// TODO: create a better label for the fs verity digest
// TODO: This does not work, fix it (see comment above)
if base.Labels == nil {
base.Labels = make(map[string]string)
}
base.Labels["fsverity_digest"] = verityDigest
}
}
}

// Ingest has now been made available in the content store, attempt to complete
// setting metadata but errors should only be logged and not returned since
// the content store cannot be cleanly rolled back.
Expand Down

0 comments on commit 244f093

Please sign in to comment.