summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/fsimpl/verity/verity.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/sentry/fsimpl/verity/verity.go')
-rw-r--r--pkg/sentry/fsimpl/verity/verity.go66
1 files changed, 47 insertions, 19 deletions
diff --git a/pkg/sentry/fsimpl/verity/verity.go b/pkg/sentry/fsimpl/verity/verity.go
index 8645078a0..374f71568 100644
--- a/pkg/sentry/fsimpl/verity/verity.go
+++ b/pkg/sentry/fsimpl/verity/verity.go
@@ -332,6 +332,11 @@ func (fstype FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.Virt
d.hash = make([]byte, len(iopts.RootHash))
d.childrenNames = make(map[string]struct{})
+ if !d.isDir() {
+ ctx.Warningf("verity root must be a directory")
+ return nil, nil, syserror.EINVAL
+ }
+
if !fs.allowRuntimeEnable {
// Get children names from the underlying file system.
offString, err := vfsObj.GetXattrAt(ctx, creds, &vfs.PathOperation{
@@ -461,6 +466,9 @@ type dentry struct {
// initialized.
lowerMerkleVD vfs.VirtualDentry
+ // symlinkTarget is the target path of a symlink file in the underlying filesystem.
+ symlinkTarget string
+
// hash is the calculated hash for the current file or directory. hash
// is protected by hashMu.
hashMu sync.RWMutex `state:"nosave"`
@@ -645,6 +653,23 @@ func (d *dentry) getLowerAt(ctx context.Context, vfsObj *vfs.VirtualFilesystem,
}
func (d *dentry) readlink(ctx context.Context) (string, error) {
+ vfsObj := d.fs.vfsfs.VirtualFilesystem()
+ if d.verityEnabled() {
+ stat, err := vfsObj.StatAt(ctx, d.fs.creds, &vfs.PathOperation{
+ Root: d.lowerVD,
+ Start: d.lowerVD,
+ }, &vfs.StatOptions{})
+ if err != nil {
+ return "", err
+ }
+ d.dirMu.Lock()
+ defer d.dirMu.Unlock()
+ if err := d.fs.verifyStatAndChildrenLocked(ctx, d, stat); err != nil {
+ return "", err
+ }
+ return d.symlinkTarget, nil
+ }
+
return d.fs.vfsfs.VirtualFilesystem().ReadlinkAt(ctx, d.fs.creds, &vfs.PathOperation{
Root: d.lowerVD,
Start: d.lowerVD,
@@ -756,7 +781,8 @@ func (fd *fileDescription) Seek(ctx context.Context, offset int64, whence int32)
// hash of the generated Merkle tree and the data size is returned. If fd
// points to a regular file, the data is the content of the file. If fd points
// to a directory, the data is all hashes of its children, written to the Merkle
-// tree file.
+// tree file. If fd represents a symlink, the data is empty and nothing is written
+// to the Merkle tree file.
//
// Preconditions: fd.d.fs.verityMu must be locked.
func (fd *fileDescription) generateMerkleLocked(ctx context.Context) ([]byte, uint64, error) {
@@ -772,30 +798,30 @@ func (fd *fileDescription) generateMerkleLocked(ctx context.Context) ([]byte, ui
FD: fd.merkleWriter,
Ctx: ctx,
}
+
+ stat, err := fd.lowerFD.Stat(ctx, vfs.StatOptions{})
+ if err != nil {
+ return nil, 0, err
+ }
+
params := &merkletree.GenerateParams{
TreeReader: &merkleReader,
TreeWriter: &merkleWriter,
Children: fd.d.childrenNames,
//TODO(b/156980949): Support passing other hash algorithms.
HashAlgorithms: fd.d.fs.alg.toLinuxHashAlg(),
+ Name: fd.d.name,
+ Mode: uint32(stat.Mode),
+ UID: stat.UID,
+ GID: stat.GID,
}
switch atomic.LoadUint32(&fd.d.mode) & linux.S_IFMT {
case linux.S_IFREG:
// For a regular file, generate a Merkle tree based on its
// content.
- var err error
- stat, err := fd.lowerFD.Stat(ctx, vfs.StatOptions{})
- if err != nil {
- return nil, 0, err
- }
-
params.File = &fdReader
params.Size = int64(stat.Size)
- params.Name = fd.d.name
- params.Mode = uint32(stat.Mode)
- params.UID = stat.UID
- params.GID = stat.GID
params.DataAndTreeInSameFile = false
case linux.S_IFDIR:
// For a directory, generate a Merkle tree based on the hashes
@@ -807,18 +833,20 @@ func (fd *fileDescription) generateMerkleLocked(ctx context.Context) ([]byte, ui
}
params.Size = int64(merkleStat.Size)
-
- stat, err := fd.lowerFD.Stat(ctx, vfs.StatOptions{})
+ params.File = &merkleReader
+ params.DataAndTreeInSameFile = true
+ case linux.S_IFLNK:
+ // For a symlink, generate a Merkle tree file but do not write the root hash
+ // of the target file content to it. Return a hash of a VerityDescriptor object
+ // which includes the symlink target name.
+ target, err := fd.d.readlink(ctx)
if err != nil {
return nil, 0, err
}
- params.File = &merkleReader
- params.Name = fd.d.name
- params.Mode = uint32(stat.Mode)
- params.UID = stat.UID
- params.GID = stat.GID
- params.DataAndTreeInSameFile = true
+ params.Size = int64(stat.Size)
+ params.DataAndTreeInSameFile = false
+ params.SymlinkTarget = target
default:
// TODO(b/167728857): Investigate whether and how we should
// enable other types of file.