Merge release-20210322.0-43-ge21a71bff (automated)

This commit is contained in:
gVisor bot 2021-04-05 19:06:01 +00:00
commit 9fb1436a3e
4 changed files with 125 additions and 48 deletions

View File

@ -35,6 +35,7 @@ package verity
import ( import (
"bytes" "bytes"
"encoding/hex"
"encoding/json" "encoding/json"
"fmt" "fmt"
"math" "math"
@ -105,6 +106,13 @@ var (
verityMu sync.RWMutex verityMu sync.RWMutex
) )
// Mount option names for verityfs.
const (
moptLowerPath = "lower_path"
moptRootHash = "root_hash"
moptRootName = "root_name"
)
// HashAlgorithm is a type specifying the algorithm used to hash the file // HashAlgorithm is a type specifying the algorithm used to hash the file
// content. // content.
type HashAlgorithm int type HashAlgorithm int
@ -171,6 +179,9 @@ type filesystem struct {
// system. // system.
alg HashAlgorithm alg HashAlgorithm
// opts is the string mount options passed to opts.Data.
opts string
// renameMu synchronizes renaming with non-renaming operations in order // renameMu synchronizes renaming with non-renaming operations in order
// to ensure consistent lock ordering between dentry.dirMu in different // to ensure consistent lock ordering between dentry.dirMu in different
// dentries. // dentries.
@ -193,9 +204,6 @@ type filesystem struct {
// //
// +stateify savable // +stateify savable
type InternalFilesystemOptions struct { type InternalFilesystemOptions struct {
// RootMerkleFileName is the name of the verity root Merkle tree file.
RootMerkleFileName string
// LowerName is the name of the filesystem wrapped by verity fs. // LowerName is the name of the filesystem wrapped by verity fs.
LowerName string LowerName string
@ -203,9 +211,6 @@ type InternalFilesystemOptions struct {
// system. // system.
Alg HashAlgorithm Alg HashAlgorithm
// RootHash is the root hash of the overall verity file system.
RootHash []byte
// AllowRuntimeEnable specifies whether the verity file system allows // AllowRuntimeEnable specifies whether the verity file system allows
// enabling verification for files (i.e. building Merkle trees) during // enabling verification for files (i.e. building Merkle trees) during
// runtime. // runtime.
@ -239,28 +244,99 @@ func alertIntegrityViolation(msg string) error {
// GetFilesystem implements vfs.FilesystemType.GetFilesystem. // GetFilesystem implements vfs.FilesystemType.GetFilesystem.
func (fstype FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.VirtualFilesystem, creds *auth.Credentials, source string, opts vfs.GetFilesystemOptions) (*vfs.Filesystem, *vfs.Dentry, error) { func (fstype FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.VirtualFilesystem, creds *auth.Credentials, source string, opts vfs.GetFilesystemOptions) (*vfs.Filesystem, *vfs.Dentry, error) {
mopts := vfs.GenericParseMountOptions(opts.Data)
var rootHash []byte
if encodedRootHash, ok := mopts[moptRootHash]; ok {
delete(mopts, moptRootHash)
hash, err := hex.DecodeString(encodedRootHash)
if err != nil {
ctx.Warningf("verity.FilesystemType.GetFilesystem: Failed to decode root hash: %v", err)
return nil, nil, syserror.EINVAL
}
rootHash = hash
}
var lowerPathname string
if path, ok := mopts[moptLowerPath]; ok {
delete(mopts, moptLowerPath)
lowerPathname = path
}
rootName := "root"
if root, ok := mopts[moptRootName]; ok {
delete(mopts, moptRootName)
rootName = root
}
// Check for unparsed options.
if len(mopts) != 0 {
ctx.Warningf("verity.FilesystemType.GetFilesystem: unknown options: %v", mopts)
return nil, nil, syserror.EINVAL
}
// Handle internal options.
iopts, ok := opts.InternalData.(InternalFilesystemOptions) iopts, ok := opts.InternalData.(InternalFilesystemOptions)
if !ok { if len(lowerPathname) == 0 && !ok {
ctx.Warningf("verity.FilesystemType.GetFilesystem: missing verity configs") ctx.Warningf("verity.FilesystemType.GetFilesystem: missing verity configs")
return nil, nil, syserror.EINVAL return nil, nil, syserror.EINVAL
} }
if len(lowerPathname) != 0 {
if ok {
ctx.Warningf("verity.FilesystemType.GetFilesystem: unexpected verity configs with specified lower path")
return nil, nil, syserror.EINVAL
}
iopts = InternalFilesystemOptions{
AllowRuntimeEnable: len(rootHash) == 0,
Action: ErrorOnViolation,
}
}
action = iopts.Action action = iopts.Action
var lowerMount *vfs.Mount
var mountedLowerVD vfs.VirtualDentry
// Use an existing mount if lowerPath is provided.
if len(lowerPathname) != 0 {
vfsroot := vfs.RootFromContext(ctx)
if vfsroot.Ok() {
defer vfsroot.DecRef(ctx)
}
lowerPath := fspath.Parse(lowerPathname)
if !lowerPath.Absolute {
ctx.Infof("verity.FilesystemType.GetFilesystem: lower_path %q must be absolute", lowerPathname)
return nil, nil, syserror.EINVAL
}
var err error
mountedLowerVD, err = vfsObj.GetDentryAt(ctx, creds, &vfs.PathOperation{
Root: vfsroot,
Start: vfsroot,
Path: lowerPath,
FollowFinalSymlink: true,
}, &vfs.GetDentryOptions{
CheckSearchable: true,
})
if err != nil {
ctx.Infof("verity.FilesystemType.GetFilesystem: failed to resolve lower_path %q: %v", lowerPathname, err)
return nil, nil, err
}
lowerMount = mountedLowerVD.Mount()
defer mountedLowerVD.DecRef(ctx)
} else {
// Mount the lower file system. The lower file system is wrapped inside // Mount the lower file system. The lower file system is wrapped inside
// verity, and should not be exposed or connected. // verity, and should not be exposed or connected.
mopts := &vfs.MountOptions{ mountOpts := &vfs.MountOptions{
GetFilesystemOptions: iopts.LowerGetFSOptions, GetFilesystemOptions: iopts.LowerGetFSOptions,
InternalMount: true, InternalMount: true,
} }
mnt, err := vfsObj.MountDisconnected(ctx, creds, "", iopts.LowerName, mopts) mnt, err := vfsObj.MountDisconnected(ctx, creds, "", iopts.LowerName, mountOpts)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
lowerMount = mnt
}
fs := &filesystem{ fs := &filesystem{
creds: creds.Fork(), creds: creds.Fork(),
alg: iopts.Alg, alg: iopts.Alg,
lowerMount: mnt, lowerMount: lowerMount,
opts: opts.Data,
allowRuntimeEnable: iopts.AllowRuntimeEnable, allowRuntimeEnable: iopts.AllowRuntimeEnable,
} }
fs.vfsfs.Init(vfsObj, &fstype, fs) fs.vfsfs.Init(vfsObj, &fstype, fs)
@ -268,11 +344,11 @@ func (fstype FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.Virt
// Construct the root dentry. // Construct the root dentry.
d := fs.newDentry() d := fs.newDentry()
d.refs = 1 d.refs = 1
lowerVD := vfs.MakeVirtualDentry(mnt, mnt.Root()) lowerVD := vfs.MakeVirtualDentry(lowerMount, lowerMount.Root())
lowerVD.IncRef() lowerVD.IncRef()
d.lowerVD = lowerVD d.lowerVD = lowerVD
rootMerkleName := merkleRootPrefix + iopts.RootMerkleFileName rootMerkleName := merkleRootPrefix + rootName
lowerMerkleVD, err := vfsObj.GetDentryAt(ctx, fs.creds, &vfs.PathOperation{ lowerMerkleVD, err := vfsObj.GetDentryAt(ctx, fs.creds, &vfs.PathOperation{
Root: lowerVD, Root: lowerVD,
@ -352,7 +428,7 @@ func (fstype FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.Virt
d.mode = uint32(stat.Mode) d.mode = uint32(stat.Mode)
d.uid = stat.UID d.uid = stat.UID
d.gid = stat.GID d.gid = stat.GID
d.hash = make([]byte, len(iopts.RootHash)) d.hash = make([]byte, len(rootHash))
d.childrenNames = make(map[string]struct{}) d.childrenNames = make(map[string]struct{})
if !d.isDir() { if !d.isDir() {
@ -427,7 +503,7 @@ func (fstype FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.Virt
} }
d.hashMu.Lock() d.hashMu.Lock()
copy(d.hash, iopts.RootHash) copy(d.hash, rootHash)
d.hashMu.Unlock() d.hashMu.Unlock()
d.vfsd.Init(d) d.vfsd.Init(d)
@ -443,7 +519,7 @@ func (fs *filesystem) Release(ctx context.Context) {
// MountOptions implements vfs.FilesystemImpl.MountOptions. // MountOptions implements vfs.FilesystemImpl.MountOptions.
func (fs *filesystem) MountOptions() string { func (fs *filesystem) MountOptions() string {
return "" return fs.opts
} }
// dentry implements vfs.DentryImpl. // dentry implements vfs.DentryImpl.

View File

@ -39,6 +39,7 @@ func (fs *filesystem) StateFields() []string {
"lowerMount", "lowerMount",
"rootDentry", "rootDentry",
"alg", "alg",
"opts",
} }
} }
@ -53,6 +54,7 @@ func (fs *filesystem) StateSave(stateSinkObject state.Sink) {
stateSinkObject.Save(3, &fs.lowerMount) stateSinkObject.Save(3, &fs.lowerMount)
stateSinkObject.Save(4, &fs.rootDentry) stateSinkObject.Save(4, &fs.rootDentry)
stateSinkObject.Save(5, &fs.alg) stateSinkObject.Save(5, &fs.alg)
stateSinkObject.Save(6, &fs.opts)
} }
func (fs *filesystem) afterLoad() {} func (fs *filesystem) afterLoad() {}
@ -65,6 +67,7 @@ func (fs *filesystem) StateLoad(stateSourceObject state.Source) {
stateSourceObject.Load(3, &fs.lowerMount) stateSourceObject.Load(3, &fs.lowerMount)
stateSourceObject.Load(4, &fs.rootDentry) stateSourceObject.Load(4, &fs.rootDentry)
stateSourceObject.Load(5, &fs.alg) stateSourceObject.Load(5, &fs.alg)
stateSourceObject.Load(6, &fs.opts)
} }
func (i *InternalFilesystemOptions) StateTypeName() string { func (i *InternalFilesystemOptions) StateTypeName() string {
@ -73,10 +76,8 @@ func (i *InternalFilesystemOptions) StateTypeName() string {
func (i *InternalFilesystemOptions) StateFields() []string { func (i *InternalFilesystemOptions) StateFields() []string {
return []string{ return []string{
"RootMerkleFileName",
"LowerName", "LowerName",
"Alg", "Alg",
"RootHash",
"AllowRuntimeEnable", "AllowRuntimeEnable",
"LowerGetFSOptions", "LowerGetFSOptions",
"Action", "Action",
@ -88,26 +89,22 @@ func (i *InternalFilesystemOptions) beforeSave() {}
// +checklocksignore // +checklocksignore
func (i *InternalFilesystemOptions) StateSave(stateSinkObject state.Sink) { func (i *InternalFilesystemOptions) StateSave(stateSinkObject state.Sink) {
i.beforeSave() i.beforeSave()
stateSinkObject.Save(0, &i.RootMerkleFileName) stateSinkObject.Save(0, &i.LowerName)
stateSinkObject.Save(1, &i.LowerName) stateSinkObject.Save(1, &i.Alg)
stateSinkObject.Save(2, &i.Alg) stateSinkObject.Save(2, &i.AllowRuntimeEnable)
stateSinkObject.Save(3, &i.RootHash) stateSinkObject.Save(3, &i.LowerGetFSOptions)
stateSinkObject.Save(4, &i.AllowRuntimeEnable) stateSinkObject.Save(4, &i.Action)
stateSinkObject.Save(5, &i.LowerGetFSOptions)
stateSinkObject.Save(6, &i.Action)
} }
func (i *InternalFilesystemOptions) afterLoad() {} func (i *InternalFilesystemOptions) afterLoad() {}
// +checklocksignore // +checklocksignore
func (i *InternalFilesystemOptions) StateLoad(stateSourceObject state.Source) { func (i *InternalFilesystemOptions) StateLoad(stateSourceObject state.Source) {
stateSourceObject.Load(0, &i.RootMerkleFileName) stateSourceObject.Load(0, &i.LowerName)
stateSourceObject.Load(1, &i.LowerName) stateSourceObject.Load(1, &i.Alg)
stateSourceObject.Load(2, &i.Alg) stateSourceObject.Load(2, &i.AllowRuntimeEnable)
stateSourceObject.Load(3, &i.RootHash) stateSourceObject.Load(3, &i.LowerGetFSOptions)
stateSourceObject.Load(4, &i.AllowRuntimeEnable) stateSourceObject.Load(4, &i.Action)
stateSourceObject.Load(5, &i.LowerGetFSOptions)
stateSourceObject.Load(6, &i.Action)
} }
func (d *dentry) StateTypeName() string { func (d *dentry) StateTypeName() string {

View File

@ -92,7 +92,7 @@ func registerFilesystems(k *kernel.Kernel) error {
}) })
vfsObj.MustRegisterFilesystemType(verity.Name, &verity.FilesystemType{}, &vfs.RegisterFilesystemTypeOptions{ vfsObj.MustRegisterFilesystemType(verity.Name, &verity.FilesystemType{}, &vfs.RegisterFilesystemTypeOptions{
AllowUserList: true, AllowUserList: true,
AllowUserMount: false, AllowUserMount: true,
}) })
// Setup files in devtmpfs. // Setup files in devtmpfs.
@ -483,7 +483,7 @@ func (c *containerMounter) getMountNameAndOptionsVFS2(conf *config.Config, m *mo
var data []string var data []string
var iopts interface{} var iopts interface{}
verityOpts, verityRequested, remainingMOpts, err := parseVerityMountOptions(m.Options) verityData, verityOpts, verityRequested, remainingMOpts, err := parseVerityMountOptions(m.Options)
if err != nil { if err != nil {
return "", nil, false, err return "", nil, false, err
} }
@ -555,13 +555,13 @@ func (c *containerMounter) getMountNameAndOptionsVFS2(conf *config.Config, m *mo
} }
if verityRequested { if verityRequested {
verityOpts.RootMerkleFileName = path.Base(m.Mount.Destination) verityData = verityData + "root_name=" + path.Base(m.Mount.Destination)
verityOpts.LowerName = fsName verityOpts.LowerName = fsName
verityOpts.LowerGetFSOptions = opts.GetFilesystemOptions verityOpts.LowerGetFSOptions = opts.GetFilesystemOptions
fsName = verity.Name fsName = verity.Name
opts = &vfs.MountOptions{ opts = &vfs.MountOptions{
GetFilesystemOptions: vfs.GetFilesystemOptions{ GetFilesystemOptions: vfs.GetFilesystemOptions{
Data: strings.Join(data, ","), Data: verityData,
InternalData: verityOpts, InternalData: verityOpts,
}, },
InternalMount: true, InternalMount: true,
@ -582,9 +582,10 @@ func parseKeyValue(s string) (string, string, bool) {
// parseAndFilterOptions scans the provided mount options for verity-related // parseAndFilterOptions scans the provided mount options for verity-related
// mount options. It returns the parsed set of verity mount options, as well as // mount options. It returns the parsed set of verity mount options, as well as
// the filtered set of mount options unrelated to verity. // the filtered set of mount options unrelated to verity.
func parseVerityMountOptions(mopts []string) (verity.InternalFilesystemOptions, bool, []string, error) { func parseVerityMountOptions(mopts []string) (string, verity.InternalFilesystemOptions, bool, []string, error) {
nonVerity := []string{} nonVerity := []string{}
found := false found := false
var rootHash string
verityOpts := verity.InternalFilesystemOptions{ verityOpts := verity.InternalFilesystemOptions{
Action: verity.PanicOnViolation, Action: verity.PanicOnViolation,
} }
@ -596,13 +597,13 @@ func parseVerityMountOptions(mopts []string) (verity.InternalFilesystemOptions,
k, v, ok := parseKeyValue(o) k, v, ok := parseKeyValue(o)
if !ok { if !ok {
return verityOpts, found, nonVerity, fmt.Errorf("invalid verity mount option with no value: %q", o) return "", verityOpts, found, nonVerity, fmt.Errorf("invalid verity mount option with no value: %q", o)
} }
found = true found = true
switch k { switch k {
case "verity.roothash": case "verity.roothash":
verityOpts.RootHash = []byte(v) rootHash = v
case "verity.action": case "verity.action":
switch v { switch v {
case "error": case "error":
@ -614,11 +615,12 @@ func parseVerityMountOptions(mopts []string) (verity.InternalFilesystemOptions,
verityOpts.Action = verity.PanicOnViolation verityOpts.Action = verity.PanicOnViolation
} }
default: default:
return verityOpts, found, nonVerity, fmt.Errorf("unknown verity mount option: %q", k) return "", verityOpts, found, nonVerity, fmt.Errorf("unknown verity mount option: %q", k)
} }
} }
verityOpts.AllowRuntimeEnable = len(verityOpts.RootHash) == 0 verityOpts.AllowRuntimeEnable = len(rootHash) == 0
return verityOpts, found, nonVerity, nil verityData := "root_hash=" + rootHash + ","
return verityData, verityOpts, found, nonVerity, nil
} }
// mountTmpVFS2 mounts an internal tmpfs at '/tmp' if it's safe to do so. // mountTmpVFS2 mounts an internal tmpfs at '/tmp' if it's safe to do so.

View File

@ -102,5 +102,7 @@ func (c *VerityPrepare) Execute(_ context.Context, f *flag.FlagSet, args ...inte
// Force no networking, it is not necessary to run the verity measure tool. // Force no networking, it is not necessary to run the verity measure tool.
conf.Network = config.NetworkNone conf.Network = config.NetworkNone
conf.Verity = true
return startContainerAndWait(spec, conf, cid, waitStatus) return startContainerAndWait(spec, conf, cid, waitStatus)
} }