diff options
Diffstat (limited to 'runsc/specutils')
-rw-r--r-- | runsc/specutils/BUILD | 34 | ||||
-rw-r--r-- | runsc/specutils/seccomp/BUILD | 34 | ||||
-rw-r--r-- | runsc/specutils/seccomp/seccomp_amd64_state_autogen.go | 5 | ||||
-rw-r--r-- | runsc/specutils/seccomp/seccomp_arm64_state_autogen.go | 5 | ||||
-rw-r--r-- | runsc/specutils/seccomp/seccomp_state_autogen.go | 3 | ||||
-rw-r--r-- | runsc/specutils/seccomp/seccomp_test.go | 414 | ||||
-rw-r--r-- | runsc/specutils/specutils_state_autogen.go | 3 | ||||
-rw-r--r-- | runsc/specutils/specutils_test.go | 265 |
8 files changed, 16 insertions, 747 deletions
diff --git a/runsc/specutils/BUILD b/runsc/specutils/BUILD deleted file mode 100644 index 679d8bc8e..000000000 --- a/runsc/specutils/BUILD +++ /dev/null @@ -1,34 +0,0 @@ -load("//tools:defs.bzl", "go_library", "go_test") - -package(licenses = ["notice"]) - -go_library( - name = "specutils", - srcs = [ - "cri.go", - "fs.go", - "namespace.go", - "specutils.go", - ], - visibility = ["//:sandbox"], - deps = [ - "//pkg/abi/linux", - "//pkg/bits", - "//pkg/log", - "//pkg/sentry/kernel/auth", - "//runsc/config", - "@com_github_cenkalti_backoff//:go_default_library", - "@com_github_mohae_deepcopy//:go_default_library", - "@com_github_opencontainers_runtime_spec//specs-go:go_default_library", - "@com_github_syndtr_gocapability//capability:go_default_library", - "@org_golang_x_sys//unix:go_default_library", - ], -) - -go_test( - name = "specutils_test", - size = "small", - srcs = ["specutils_test.go"], - library = ":specutils", - deps = ["@com_github_opencontainers_runtime_spec//specs-go:go_default_library"], -) diff --git a/runsc/specutils/seccomp/BUILD b/runsc/specutils/seccomp/BUILD deleted file mode 100644 index 3520f2d6d..000000000 --- a/runsc/specutils/seccomp/BUILD +++ /dev/null @@ -1,34 +0,0 @@ -load("//tools:defs.bzl", "go_library", "go_test") - -package(licenses = ["notice"]) - -go_library( - name = "seccomp", - srcs = [ - "audit_amd64.go", - "audit_arm64.go", - "seccomp.go", - ], - visibility = ["//:sandbox"], - deps = [ - "//pkg/abi/linux", - "//pkg/bpf", - "//pkg/log", - "//pkg/seccomp", - "//pkg/sentry/kernel", - "//pkg/sentry/syscalls/linux", - "@com_github_opencontainers_runtime_spec//specs-go:go_default_library", - ], -) - -go_test( - name = "seccomp_test", - size = "small", - srcs = ["seccomp_test.go"], - library = ":seccomp", - deps = [ - "//pkg/binary", - "//pkg/bpf", - "@com_github_opencontainers_runtime_spec//specs-go:go_default_library", - ], -) diff --git a/runsc/specutils/seccomp/seccomp_amd64_state_autogen.go b/runsc/specutils/seccomp/seccomp_amd64_state_autogen.go new file mode 100644 index 000000000..27a96018b --- /dev/null +++ b/runsc/specutils/seccomp/seccomp_amd64_state_autogen.go @@ -0,0 +1,5 @@ +// automatically generated by stateify. + +// +build amd64 + +package seccomp diff --git a/runsc/specutils/seccomp/seccomp_arm64_state_autogen.go b/runsc/specutils/seccomp/seccomp_arm64_state_autogen.go new file mode 100644 index 000000000..96c64c23d --- /dev/null +++ b/runsc/specutils/seccomp/seccomp_arm64_state_autogen.go @@ -0,0 +1,5 @@ +// automatically generated by stateify. + +// +build arm64 + +package seccomp diff --git a/runsc/specutils/seccomp/seccomp_state_autogen.go b/runsc/specutils/seccomp/seccomp_state_autogen.go new file mode 100644 index 000000000..e16b5d7c2 --- /dev/null +++ b/runsc/specutils/seccomp/seccomp_state_autogen.go @@ -0,0 +1,3 @@ +// automatically generated by stateify. + +package seccomp diff --git a/runsc/specutils/seccomp/seccomp_test.go b/runsc/specutils/seccomp/seccomp_test.go deleted file mode 100644 index 850c237ba..000000000 --- a/runsc/specutils/seccomp/seccomp_test.go +++ /dev/null @@ -1,414 +0,0 @@ -// Copyright 2020 The gVisor Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package seccomp - -import ( - "fmt" - "syscall" - "testing" - - specs "github.com/opencontainers/runtime-spec/specs-go" - "gvisor.dev/gvisor/pkg/binary" - "gvisor.dev/gvisor/pkg/bpf" -) - -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} -} - -// testInput creates an Input struct with given seccomp input values. -func testInput(arch uint32, syscallName string, args *[6]uint64) bpf.Input { - syscallNo, err := lookupSyscallNo(arch, syscallName) - if err != nil { - // Assume tests set valid syscall names. - panic(err) - } - - if args == nil { - argArray := [6]uint64{0, 0, 0, 0, 0, 0} - args = &argArray - } - - data := seccompData{ - nr: syscallNo, - arch: arch, - args: *args, - } - - return asInput(data) -} - -// testCase holds a seccomp test case. -type testCase struct { - name string - config specs.LinuxSeccomp - input bpf.Input - expected uint32 -} - -var ( - // seccompTests is a list of speccomp test cases. - seccompTests = []testCase{ - { - name: "default_allow", - config: specs.LinuxSeccomp{ - DefaultAction: specs.ActAllow, - }, - input: testInput(nativeArchAuditNo, "read", nil), - expected: uint32(allowAction), - }, - { - name: "default_deny", - config: specs.LinuxSeccomp{ - DefaultAction: specs.ActErrno, - }, - input: testInput(nativeArchAuditNo, "read", nil), - expected: uint32(errnoAction), - }, - { - name: "deny_arch", - config: specs.LinuxSeccomp{ - DefaultAction: specs.ActAllow, - Syscalls: []specs.LinuxSyscall{ - { - Names: []string{ - "getcwd", - }, - Action: specs.ActErrno, - }, - }, - }, - // 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}), // - expected: uint32(killThreadAction), - }, - { - name: "match_name_errno", - config: specs.LinuxSeccomp{ - DefaultAction: specs.ActAllow, - Syscalls: []specs.LinuxSyscall{ - { - Names: []string{ - "getcwd", - "chmod", - }, - Action: specs.ActErrno, - }, - { - Names: []string{ - "write", - }, - Action: specs.ActTrace, - }, - }, - }, - input: testInput(nativeArchAuditNo, "getcwd", nil), - expected: uint32(errnoAction), - }, - { - name: "match_name_trace", - config: specs.LinuxSeccomp{ - DefaultAction: specs.ActAllow, - Syscalls: []specs.LinuxSyscall{ - { - Names: []string{ - "getcwd", - "chmod", - }, - Action: specs.ActErrno, - }, - { - Names: []string{ - "write", - }, - Action: specs.ActTrace, - }, - }, - }, - input: testInput(nativeArchAuditNo, "write", nil), - expected: uint32(traceAction), - }, - { - name: "no_match_name_allow", - config: specs.LinuxSeccomp{ - DefaultAction: specs.ActAllow, - Syscalls: []specs.LinuxSyscall{ - { - Names: []string{ - "getcwd", - "chmod", - }, - Action: specs.ActErrno, - }, - { - Names: []string{ - "write", - }, - Action: specs.ActTrace, - }, - }, - }, - input: testInput(nativeArchAuditNo, "openat", nil), - expected: uint32(allowAction), - }, - { - name: "simple_match_args", - config: specs.LinuxSeccomp{ - DefaultAction: specs.ActAllow, - Syscalls: []specs.LinuxSyscall{ - { - Names: []string{ - "clone", - }, - Args: []specs.LinuxSeccompArg{ - { - Index: 0, - Value: syscall.CLONE_FS, - Op: specs.OpEqualTo, - }, - }, - Action: specs.ActErrno, - }, - }, - }, - input: testInput(nativeArchAuditNo, "clone", &[6]uint64{syscall.CLONE_FS}), - expected: uint32(errnoAction), - }, - { - name: "match_args_or", - config: specs.LinuxSeccomp{ - DefaultAction: specs.ActAllow, - Syscalls: []specs.LinuxSyscall{ - { - Names: []string{ - "clone", - }, - Args: []specs.LinuxSeccompArg{ - { - Index: 0, - Value: syscall.CLONE_FS, - Op: specs.OpEqualTo, - }, - { - Index: 0, - Value: syscall.CLONE_VM, - Op: specs.OpEqualTo, - }, - }, - Action: specs.ActErrno, - }, - }, - }, - input: testInput(nativeArchAuditNo, "clone", &[6]uint64{syscall.CLONE_FS}), - expected: uint32(errnoAction), - }, - { - name: "match_args_and", - config: specs.LinuxSeccomp{ - DefaultAction: specs.ActAllow, - Syscalls: []specs.LinuxSyscall{ - { - Names: []string{ - "getsockopt", - }, - Args: []specs.LinuxSeccompArg{ - { - Index: 1, - Value: syscall.SOL_SOCKET, - Op: specs.OpEqualTo, - }, - { - Index: 2, - Value: syscall.SO_PEERCRED, - Op: specs.OpEqualTo, - }, - }, - Action: specs.ActErrno, - }, - }, - }, - input: testInput(nativeArchAuditNo, "getsockopt", &[6]uint64{0, syscall.SOL_SOCKET, syscall.SO_PEERCRED}), - expected: uint32(errnoAction), - }, - { - name: "no_match_args_and", - config: specs.LinuxSeccomp{ - DefaultAction: specs.ActAllow, - Syscalls: []specs.LinuxSyscall{ - { - Names: []string{ - "getsockopt", - }, - Args: []specs.LinuxSeccompArg{ - { - Index: 1, - Value: syscall.SOL_SOCKET, - Op: specs.OpEqualTo, - }, - { - Index: 2, - Value: syscall.SO_PEERCRED, - Op: specs.OpEqualTo, - }, - }, - Action: specs.ActErrno, - }, - }, - }, - input: testInput(nativeArchAuditNo, "getsockopt", &[6]uint64{0, syscall.SOL_SOCKET}), - expected: uint32(allowAction), - }, - { - name: "Simple args (no match)", - config: specs.LinuxSeccomp{ - DefaultAction: specs.ActAllow, - Syscalls: []specs.LinuxSyscall{ - { - Names: []string{ - "clone", - }, - Args: []specs.LinuxSeccompArg{ - { - Index: 0, - Value: syscall.CLONE_FS, - Op: specs.OpEqualTo, - }, - }, - Action: specs.ActErrno, - }, - }, - }, - input: testInput(nativeArchAuditNo, "clone", &[6]uint64{syscall.CLONE_VM}), - expected: uint32(allowAction), - }, - { - name: "OpMaskedEqual (match)", - config: specs.LinuxSeccomp{ - DefaultAction: specs.ActAllow, - Syscalls: []specs.LinuxSyscall{ - { - Names: []string{ - "clone", - }, - Args: []specs.LinuxSeccompArg{ - { - Index: 0, - Value: syscall.CLONE_FS, - ValueTwo: syscall.CLONE_FS, - Op: specs.OpMaskedEqual, - }, - }, - Action: specs.ActErrno, - }, - }, - }, - input: testInput(nativeArchAuditNo, "clone", &[6]uint64{syscall.CLONE_FS | syscall.CLONE_VM}), - expected: uint32(errnoAction), - }, - { - name: "OpMaskedEqual (no match)", - config: specs.LinuxSeccomp{ - DefaultAction: specs.ActAllow, - Syscalls: []specs.LinuxSyscall{ - { - Names: []string{ - "clone", - }, - Args: []specs.LinuxSeccompArg{ - { - Index: 0, - Value: syscall.CLONE_FS | syscall.CLONE_VM, - ValueTwo: syscall.CLONE_FS | syscall.CLONE_VM, - Op: specs.OpMaskedEqual, - }, - }, - Action: specs.ActErrno, - }, - }, - }, - input: testInput(nativeArchAuditNo, "clone", &[6]uint64{syscall.CLONE_FS}), - expected: uint32(allowAction), - }, - { - name: "OpMaskedEqual (clone)", - config: specs.LinuxSeccomp{ - DefaultAction: specs.ActErrno, - Syscalls: []specs.LinuxSyscall{ - { - Names: []string{ - "clone", - }, - // This comes from the Docker default seccomp - // profile for clone. - Args: []specs.LinuxSeccompArg{ - { - Index: 0, - Value: 0x7e020000, - ValueTwo: 0x0, - Op: specs.OpMaskedEqual, - }, - }, - Action: specs.ActAllow, - }, - }, - }, - input: testInput(nativeArchAuditNo, "clone", &[6]uint64{0x50f00}), - expected: uint32(allowAction), - }, - } -) - -// TestRunscSeccomp generates seccomp programs from OCI config and executes -// them using runsc's library, comparing against expected results. -func TestRunscSeccomp(t *testing.T) { - for _, tc := range seccompTests { - t.Run(tc.name, func(t *testing.T) { - runscProgram, err := BuildProgram(&tc.config) - if err != nil { - t.Fatalf("generating runsc BPF: %v", err) - } - - if err := checkProgram(runscProgram, tc.input, tc.expected); err != nil { - t.Fatalf("running runsc BPF: %v", err) - } - }) - } -} - -// checkProgram runs the given program over the given input and checks the -// result against the expected output. -func checkProgram(p bpf.Program, in bpf.Input, expected uint32) error { - result, err := bpf.Exec(p, in) - if err != nil { - return err - } - - if result != expected { - // Include a decoded version of the program in output for debugging purposes. - decoded, _ := bpf.DecodeProgram(p) - return fmt.Errorf("Unexpected result: got: %d, expected: %d\nBPF Program\n%s", result, expected, decoded) - } - - return nil -} diff --git a/runsc/specutils/specutils_state_autogen.go b/runsc/specutils/specutils_state_autogen.go new file mode 100644 index 000000000..11eefbaa2 --- /dev/null +++ b/runsc/specutils/specutils_state_autogen.go @@ -0,0 +1,3 @@ +// automatically generated by stateify. + +package specutils diff --git a/runsc/specutils/specutils_test.go b/runsc/specutils/specutils_test.go deleted file mode 100644 index 2c86fffe8..000000000 --- a/runsc/specutils/specutils_test.go +++ /dev/null @@ -1,265 +0,0 @@ -// Copyright 2018 The gVisor Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package specutils - -import ( - "fmt" - "os/exec" - "strings" - "testing" - "time" - - specs "github.com/opencontainers/runtime-spec/specs-go" -) - -func TestWaitForReadyHappy(t *testing.T) { - cmd := exec.Command("/bin/sleep", "1000") - if err := cmd.Start(); err != nil { - t.Fatalf("cmd.Start() failed, err: %v", err) - } - defer cmd.Wait() - - var count int - err := WaitForReady(cmd.Process.Pid, 5*time.Second, func() (bool, error) { - if count < 3 { - count++ - return false, nil - } - return true, nil - }) - if err != nil { - t.Errorf("ProcessWaitReady got: %v, expected: nil", err) - } - cmd.Process.Kill() -} - -func TestWaitForReadyFail(t *testing.T) { - cmd := exec.Command("/bin/sleep", "1000") - if err := cmd.Start(); err != nil { - t.Fatalf("cmd.Start() failed, err: %v", err) - } - defer cmd.Wait() - - var count int - err := WaitForReady(cmd.Process.Pid, 5*time.Second, func() (bool, error) { - if count < 3 { - count++ - return false, nil - } - return false, fmt.Errorf("Fake error") - }) - if err == nil { - t.Errorf("ProcessWaitReady got: nil, expected: error") - } - cmd.Process.Kill() -} - -func TestWaitForReadyNotRunning(t *testing.T) { - cmd := exec.Command("/bin/true") - if err := cmd.Start(); err != nil { - t.Fatalf("cmd.Start() failed, err: %v", err) - } - defer cmd.Wait() - - err := WaitForReady(cmd.Process.Pid, 5*time.Second, func() (bool, error) { - return false, nil - }) - if err != nil && !strings.Contains(err.Error(), "terminated") { - t.Errorf("ProcessWaitReady got: %v, expected: process terminated", err) - } - if err == nil { - t.Errorf("ProcessWaitReady incorrectly succeeded") - } -} - -func TestWaitForReadyTimeout(t *testing.T) { - cmd := exec.Command("/bin/sleep", "1000") - if err := cmd.Start(); err != nil { - t.Fatalf("cmd.Start() failed, err: %v", err) - } - defer cmd.Wait() - - err := WaitForReady(cmd.Process.Pid, 50*time.Millisecond, func() (bool, error) { - return false, nil - }) - if !strings.Contains(err.Error(), "not running yet") { - t.Errorf("ProcessWaitReady got: %v, expected: not running yet", err) - } - cmd.Process.Kill() -} - -func TestSpecInvalid(t *testing.T) { - for _, test := range []struct { - name string - spec specs.Spec - error string - }{ - { - name: "valid", - spec: specs.Spec{ - Root: &specs.Root{Path: "/"}, - Process: &specs.Process{ - Args: []string{"/bin/true"}, - }, - Mounts: []specs.Mount{ - { - Source: "src", - Destination: "/dst", - }, - }, - }, - error: "", - }, - { - name: "valid+warning", - spec: specs.Spec{ - Root: &specs.Root{Path: "/"}, - Process: &specs.Process{ - Args: []string{"/bin/true"}, - // This is normally set by docker and will just cause warnings to be logged. - ApparmorProfile: "someprofile", - }, - // This is normally set by docker and will just cause warnings to be logged. - Linux: &specs.Linux{Seccomp: &specs.LinuxSeccomp{}}, - }, - error: "", - }, - { - name: "no root", - spec: specs.Spec{ - Process: &specs.Process{ - Args: []string{"/bin/true"}, - }, - }, - error: "must be defined", - }, - { - name: "empty root", - spec: specs.Spec{ - Root: &specs.Root{}, - Process: &specs.Process{ - Args: []string{"/bin/true"}, - }, - }, - error: "must be defined", - }, - { - name: "no process", - spec: specs.Spec{ - Root: &specs.Root{Path: "/"}, - }, - error: "must be defined", - }, - { - name: "empty args", - spec: specs.Spec{ - Root: &specs.Root{Path: "/"}, - Process: &specs.Process{}, - }, - error: "must be defined", - }, - { - name: "selinux", - spec: specs.Spec{ - Root: &specs.Root{Path: "/"}, - Process: &specs.Process{ - Args: []string{"/bin/true"}, - SelinuxLabel: "somelabel", - }, - }, - error: "is not supported", - }, - { - name: "solaris", - spec: specs.Spec{ - Root: &specs.Root{Path: "/"}, - Process: &specs.Process{ - Args: []string{"/bin/true"}, - }, - Solaris: &specs.Solaris{}, - }, - error: "is not supported", - }, - { - name: "windows", - spec: specs.Spec{ - Root: &specs.Root{Path: "/"}, - Process: &specs.Process{ - Args: []string{"/bin/true"}, - }, - Windows: &specs.Windows{}, - }, - error: "is not supported", - }, - { - name: "relative mount destination", - spec: specs.Spec{ - Root: &specs.Root{Path: "/"}, - Process: &specs.Process{ - Args: []string{"/bin/true"}, - }, - Mounts: []specs.Mount{ - { - Source: "src", - Destination: "dst", - }, - }, - }, - error: "must be an absolute path", - }, - { - name: "invalid mount option", - spec: specs.Spec{ - Root: &specs.Root{Path: "/"}, - Process: &specs.Process{ - Args: []string{"/bin/true"}, - }, - Mounts: []specs.Mount{ - { - Source: "/src", - Destination: "/dst", - Type: "bind", - Options: []string{"shared"}, - }, - }, - }, - error: "is not supported", - }, - { - name: "invalid rootfs propagation", - spec: specs.Spec{ - Root: &specs.Root{Path: "/"}, - Process: &specs.Process{ - Args: []string{"/bin/true"}, - }, - Linux: &specs.Linux{ - RootfsPropagation: "foo", - }, - }, - error: "root mount propagation option must specify private or slave", - }, - } { - err := ValidateSpec(&test.spec) - if len(test.error) == 0 { - if err != nil { - t.Errorf("ValidateSpec(%q) failed, err: %v", test.name, err) - } - } else { - if err == nil || !strings.Contains(err.Error(), test.error) { - t.Errorf("ValidateSpec(%q) wrong error, got: %v, want: .*%s.*", test.name, err, test.error) - } - } - } -} |