diff options
Diffstat (limited to 'runsc/specutils')
-rw-r--r-- | runsc/specutils/fs.go | 18 | ||||
-rw-r--r-- | runsc/specutils/seccomp/BUILD | 4 | ||||
-rw-r--r-- | runsc/specutils/seccomp/seccomp_test.go | 29 | ||||
-rw-r--r-- | runsc/specutils/specutils.go | 34 |
4 files changed, 61 insertions, 24 deletions
diff --git a/runsc/specutils/fs.go b/runsc/specutils/fs.go index b62504a8c..9ecd0fde6 100644 --- a/runsc/specutils/fs.go +++ b/runsc/specutils/fs.go @@ -18,6 +18,7 @@ import ( "fmt" "math/bits" "path" + "strings" specs "github.com/opencontainers/runtime-spec/specs-go" "golang.org/x/sys/unix" @@ -64,6 +65,12 @@ var optionsMap = map[string]mapping{ "sync": {set: true, val: unix.MS_SYNCHRONOUS}, } +// verityMountOptions is the set of valid verity mount option keys. +var verityMountOptions = map[string]struct{}{ + "verity.roothash": struct{}{}, + "verity.action": struct{}{}, +} + // propOptionsMap is similar to optionsMap, but it lists propagation options // that cannot be used together with other flags. var propOptionsMap = map[string]mapping{ @@ -117,6 +124,14 @@ func validateMount(mnt *specs.Mount) error { return nil } +func moptKey(opt string) string { + if len(opt) == 0 { + return opt + } + // Guaranteed to have at least one token, since opt is not empty. + return strings.SplitN(opt, "=", 2)[0] +} + // ValidateMountOptions validates that mount options are correct. func ValidateMountOptions(opts []string) error { for _, o := range opts { @@ -125,7 +140,8 @@ func ValidateMountOptions(opts []string) error { } _, ok1 := optionsMap[o] _, ok2 := propOptionsMap[o] - if !ok1 && !ok2 { + _, ok3 := verityMountOptions[moptKey(o)] + if !ok1 && !ok2 && !ok3 { return fmt.Errorf("unknown mount option %q", o) } if err := validatePropagation(o); err != nil { diff --git a/runsc/specutils/seccomp/BUILD b/runsc/specutils/seccomp/BUILD index e9e647d82..c5f5b863e 100644 --- a/runsc/specutils/seccomp/BUILD +++ b/runsc/specutils/seccomp/BUILD @@ -28,8 +28,10 @@ go_test( srcs = ["seccomp_test.go"], library = ":seccomp", deps = [ - "//pkg/binary", + "//pkg/abi/linux", "//pkg/bpf", + "//pkg/hostarch", + "//pkg/marshal", "@com_github_opencontainers_runtime_spec//specs-go:go_default_library", "@org_golang_x_sys//unix:go_default_library", ], diff --git a/runsc/specutils/seccomp/seccomp_test.go b/runsc/specutils/seccomp/seccomp_test.go index 11a6c8daa..20796bf14 100644 --- a/runsc/specutils/seccomp/seccomp_test.go +++ b/runsc/specutils/seccomp/seccomp_test.go @@ -20,20 +20,15 @@ import ( specs "github.com/opencontainers/runtime-spec/specs-go" "golang.org/x/sys/unix" - "gvisor.dev/gvisor/pkg/binary" + "gvisor.dev/gvisor/pkg/abi/linux" "gvisor.dev/gvisor/pkg/bpf" + "gvisor.dev/gvisor/pkg/hostarch" + "gvisor.dev/gvisor/pkg/marshal" ) -type seccompData struct { - nr uint32 - arch uint32 - instructionPointer uint64 - args [6]uint64 -} - -// asInput converts a seccompData to a bpf.Input. -func asInput(d seccompData) bpf.Input { - return bpf.InputBytes{binary.Marshal(nil, binary.LittleEndian, d), binary.LittleEndian} +// asInput converts a linux.SeccompData to a bpf.Input. +func asInput(d *linux.SeccompData) bpf.Input { + return bpf.InputBytes{marshal.Marshal(d), hostarch.ByteOrder} } // testInput creates an Input struct with given seccomp input values. @@ -49,13 +44,13 @@ func testInput(arch uint32, syscallName string, args *[6]uint64) bpf.Input { args = &argArray } - data := seccompData{ - nr: syscallNo, - arch: arch, - args: *args, + data := linux.SeccompData{ + Nr: int32(syscallNo), + Arch: arch, + Args: *args, } - return asInput(data) + return asInput(&data) } // testCase holds a seccomp test case. @@ -100,7 +95,7 @@ var ( }, // Syscall matches but the arch is AUDIT_ARCH_X86 so the return // value is the bad arch action. - input: asInput(seccompData{nr: 183, arch: 0x40000003}), // + input: asInput(&linux.SeccompData{Nr: 183, Arch: 0x40000003}), // expected: uint32(killThreadAction), }, { diff --git a/runsc/specutils/specutils.go b/runsc/specutils/specutils.go index 45856fd58..11b476690 100644 --- a/runsc/specutils/specutils.go +++ b/runsc/specutils/specutils.go @@ -332,14 +332,38 @@ func capsFromNames(names []string, skipSet map[linux.Capability]struct{}) (auth. return auth.CapabilitySetOfMany(caps), nil } -// Is9PMount returns true if the given mount can be mounted as an external gofer. -func Is9PMount(m specs.Mount) bool { - return m.Type == "bind" && m.Source != "" && IsVFS1SupportedDevMount(m) +// Is9PMount returns true if the given mount can be mounted as an external +// gofer. +func Is9PMount(m specs.Mount, vfs2Enabled bool) bool { + MaybeConvertToBindMount(&m) + return m.Type == "bind" && m.Source != "" && IsSupportedDevMount(m, vfs2Enabled) } -// IsVFS1SupportedDevMount returns true if m.Destination does not specify a +// MaybeConvertToBindMount converts mount type to "bind" in case any of the +// mount options are either "bind" or "rbind" as required by the OCI spec. +// +// "For bind mounts (when options include either bind or rbind), the type is a +// dummy, often "none" (not listed in /proc/filesystems)." +func MaybeConvertToBindMount(m *specs.Mount) { + if m.Type == "bind" { + return + } + for _, opt := range m.Options { + if opt == "bind" || opt == "rbind" { + m.Type = "bind" + return + } + } +} + +// IsSupportedDevMount returns true if m.Destination does not specify a // path that is hardcoded by VFS1's implementation of /dev. -func IsVFS1SupportedDevMount(m specs.Mount) bool { +func IsSupportedDevMount(m specs.Mount, vfs2Enabled bool) bool { + // VFS2 has no hardcoded files under /dev, so everything is allowed. + if vfs2Enabled { + return true + } + // See pkg/sentry/fs/dev/dev.go. var existingDevices = []string{ "/dev/fd", "/dev/stdin", "/dev/stdout", "/dev/stderr", |