diff options
Diffstat (limited to 'runsc/specutils')
-rw-r--r-- | runsc/specutils/BUILD | 34 | ||||
-rw-r--r-- | runsc/specutils/safemount_test/BUILD | 23 | ||||
-rw-r--r-- | runsc/specutils/safemount_test/safemount_runner.go | 117 | ||||
-rw-r--r-- | runsc/specutils/safemount_test/safemount_test.go | 53 | ||||
-rw-r--r-- | runsc/specutils/seccomp/BUILD | 38 | ||||
-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 | 409 | ||||
-rw-r--r-- | runsc/specutils/specutils_state_autogen.go | 3 | ||||
-rw-r--r-- | runsc/specutils/specutils_test.go | 271 |
11 files changed, 16 insertions, 945 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/safemount_test/BUILD b/runsc/specutils/safemount_test/BUILD deleted file mode 100644 index c39c40492..000000000 --- a/runsc/specutils/safemount_test/BUILD +++ /dev/null @@ -1,23 +0,0 @@ -load("//tools:defs.bzl", "go_binary", "go_test") - -package(licenses = ["notice"]) - -go_test( - name = "safemount_test", - size = "small", - srcs = ["safemount_test.go"], - data = [":safemount_runner"], - deps = [ - "//pkg/test/testutil", - "@org_golang_x_sys//unix:go_default_library", - ], -) - -go_binary( - name = "safemount_runner", - srcs = ["safemount_runner.go"], - deps = [ - "//runsc/specutils", - "@org_golang_x_sys//unix:go_default_library", - ], -) diff --git a/runsc/specutils/safemount_test/safemount_runner.go b/runsc/specutils/safemount_test/safemount_runner.go deleted file mode 100644 index b23193033..000000000 --- a/runsc/specutils/safemount_test/safemount_runner.go +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2021 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. - -// safemount_runner is used to test the SafeMount function. Because use of -// unix.Mount requires privilege, tests must launch this process with -// CLONE_NEWNS and CLONE_NEWUSER. -package main - -import ( - "errors" - "fmt" - "log" - "os" - "path/filepath" - - "golang.org/x/sys/unix" - "gvisor.dev/gvisor/runsc/specutils" -) - -func main() { - // The test temporary directory is the first argument. - tempdir := os.Args[1] - - tcs := []struct { - name string - testfunc func() error - }{{ - name: "unix.Mount to folder succeeds", - testfunc: func() error { - dir2Path := filepath.Join(tempdir, "subdir2") - if err := unix.Mount(filepath.Join(tempdir, "subdir"), dir2Path, "bind", unix.MS_BIND, ""); err != nil { - return fmt.Errorf("mount: %v", err) - } - return unix.Unmount(dir2Path, unix.MNT_DETACH) - }, - }, { - // unix.Mount doesn't care whether the target is a symlink. - name: "unix.Mount to symlink succeeds", - testfunc: func() error { - symlinkPath := filepath.Join(tempdir, "symlink") - if err := unix.Mount(filepath.Join(tempdir, "subdir"), symlinkPath, "bind", unix.MS_BIND, ""); err != nil { - return fmt.Errorf("mount: %v", err) - } - return unix.Unmount(symlinkPath, unix.MNT_DETACH) - }, - }, { - name: "SafeMount to folder succeeds", - testfunc: func() error { - dir2Path := filepath.Join(tempdir, "subdir2") - if err := specutils.SafeMount(filepath.Join(tempdir, "subdir"), dir2Path, "bind", unix.MS_BIND, "", "/proc"); err != nil { - return fmt.Errorf("SafeMount: %v", err) - } - return unix.Unmount(dir2Path, unix.MNT_DETACH) - }, - }, { - name: "SafeMount to symlink fails", - testfunc: func() error { - err := specutils.SafeMount(filepath.Join(tempdir, "subdir"), filepath.Join(tempdir, "symlink"), "bind", unix.MS_BIND, "", "/proc") - if err == nil { - return fmt.Errorf("SafeMount didn't fail, but should have") - } - var symErr *specutils.ErrSymlinkMount - if !errors.As(err, &symErr) { - return fmt.Errorf("expected SafeMount to fail with ErrSymlinkMount, but got: %v", err) - } - return nil - }, - }} - - for _, tc := range tcs { - if err := runTest(tempdir, tc.testfunc); err != nil { - log.Fatalf("failed test %q: %v", tc.name, err) - } - } -} - -// runTest runs testfunc with the following directory structure: -// tempdir/ -// subdir/ -// subdir2/ -// symlink --> ./subdir2 -func runTest(tempdir string, testfunc func() error) error { - // Create tempdir/subdir/. - dirPath := filepath.Join(tempdir, "subdir") - if err := os.Mkdir(dirPath, 0777); err != nil { - return fmt.Errorf("os.Mkdir(%s, 0777)", dirPath) - } - defer os.Remove(dirPath) - - // Create tempdir/subdir2/. - dir2Path := filepath.Join(tempdir, "subdir2") - if err := os.Mkdir(dir2Path, 0777); err != nil { - return fmt.Errorf("os.Mkdir(%s, 0777)", dir2Path) - } - defer os.Remove(dir2Path) - - // Create tempdir/symlink, which points to ./subdir2. - symlinkPath := filepath.Join(tempdir, "symlink") - if err := os.Symlink("./subdir2", symlinkPath); err != nil { - return fmt.Errorf("failed to create symlink %s: %v", symlinkPath, err) - } - defer os.Remove(symlinkPath) - - // Run the actual test. - return testfunc() -} diff --git a/runsc/specutils/safemount_test/safemount_test.go b/runsc/specutils/safemount_test/safemount_test.go deleted file mode 100644 index 8820978c4..000000000 --- a/runsc/specutils/safemount_test/safemount_test.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2021 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 safemount_test - -import ( - "os" - "os/exec" - "syscall" - "testing" - - "golang.org/x/sys/unix" - "gvisor.dev/gvisor/pkg/test/testutil" -) - -func TestSafeMount(t *testing.T) { - // We run the actual tests in another process, as we need CAP_SYS_ADMIN to - // call mount(2). The new process runs in its own user and mount namespaces. - runner, err := testutil.FindFile("runsc/specutils/safemount_test/safemount_runner") - if err != nil { - t.Fatalf("failed to find test runner binary: %v", err) - } - cmd := exec.Command(runner, t.TempDir()) - cmd.SysProcAttr = &unix.SysProcAttr{ - Cloneflags: unix.CLONE_NEWNS | unix.CLONE_NEWUSER, - UidMappings: []syscall.SysProcIDMap{ - {ContainerID: 0, HostID: os.Getuid(), Size: 1}, - }, - GidMappings: []syscall.SysProcIDMap{ - {ContainerID: 0, HostID: os.Getgid(), Size: 1}, - }, - GidMappingsEnableSetgroups: false, - Credential: &syscall.Credential{ - Uid: 0, - Gid: 0, - }, - } - output, err := cmd.CombinedOutput() - if err != nil { - t.Fatalf("failed running %s with error: %v\ntest output:\n%s", cmd, err, output) - } -} diff --git a/runsc/specutils/seccomp/BUILD b/runsc/specutils/seccomp/BUILD deleted file mode 100644 index c5f5b863e..000000000 --- a/runsc/specutils/seccomp/BUILD +++ /dev/null @@ -1,38 +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", - "@org_golang_x_sys//unix:go_default_library", - ], -) - -go_test( - name = "seccomp_test", - size = "small", - srcs = ["seccomp_test.go"], - library = ":seccomp", - deps = [ - "//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_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 20796bf14..000000000 --- a/runsc/specutils/seccomp/seccomp_test.go +++ /dev/null @@ -1,409 +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" - "testing" - - specs "github.com/opencontainers/runtime-spec/specs-go" - "golang.org/x/sys/unix" - "gvisor.dev/gvisor/pkg/abi/linux" - "gvisor.dev/gvisor/pkg/bpf" - "gvisor.dev/gvisor/pkg/hostarch" - "gvisor.dev/gvisor/pkg/marshal" -) - -// 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. -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 := linux.SeccompData{ - Nr: int32(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(&linux.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: unix.CLONE_FS, - Op: specs.OpEqualTo, - }, - }, - Action: specs.ActErrno, - }, - }, - }, - input: testInput(nativeArchAuditNo, "clone", &[6]uint64{unix.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: unix.CLONE_FS, - Op: specs.OpEqualTo, - }, - { - Index: 0, - Value: unix.CLONE_VM, - Op: specs.OpEqualTo, - }, - }, - Action: specs.ActErrno, - }, - }, - }, - input: testInput(nativeArchAuditNo, "clone", &[6]uint64{unix.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: unix.SOL_SOCKET, - Op: specs.OpEqualTo, - }, - { - Index: 2, - Value: unix.SO_PEERCRED, - Op: specs.OpEqualTo, - }, - }, - Action: specs.ActErrno, - }, - }, - }, - input: testInput(nativeArchAuditNo, "getsockopt", &[6]uint64{0, unix.SOL_SOCKET, unix.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: unix.SOL_SOCKET, - Op: specs.OpEqualTo, - }, - { - Index: 2, - Value: unix.SO_PEERCRED, - Op: specs.OpEqualTo, - }, - }, - Action: specs.ActErrno, - }, - }, - }, - input: testInput(nativeArchAuditNo, "getsockopt", &[6]uint64{0, unix.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: unix.CLONE_FS, - Op: specs.OpEqualTo, - }, - }, - Action: specs.ActErrno, - }, - }, - }, - input: testInput(nativeArchAuditNo, "clone", &[6]uint64{unix.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: unix.CLONE_FS, - ValueTwo: unix.CLONE_FS, - Op: specs.OpMaskedEqual, - }, - }, - Action: specs.ActErrno, - }, - }, - }, - input: testInput(nativeArchAuditNo, "clone", &[6]uint64{unix.CLONE_FS | unix.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: unix.CLONE_FS | unix.CLONE_VM, - ValueTwo: unix.CLONE_FS | unix.CLONE_VM, - Op: specs.OpMaskedEqual, - }, - }, - Action: specs.ActErrno, - }, - }, - }, - input: testInput(nativeArchAuditNo, "clone", &[6]uint64{unix.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 e2d3a75dc..000000000 --- a/runsc/specutils/specutils_test.go +++ /dev/null @@ -1,271 +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 func() { _ = 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) - } - if err := cmd.Process.Kill(); err != nil { - t.Errorf("cmd.ProcessKill(): %v", err) - } -} - -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 func() { _ = 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") - } - if err := cmd.Process.Kill(); err != nil { - t.Errorf("cmd.ProcessKill(): %v", err) - } -} - -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 func() { _ = 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 func() { _ = cmd.Wait() }() - - err := WaitForReady(cmd.Process.Pid, 50*time.Millisecond, func() (bool, error) { - return false, nil - }) - if err == nil || !strings.Contains(err.Error(), "not running yet") { - t.Errorf("ProcessWaitReady got: %v, expected: not running yet", err) - } - if err := cmd.Process.Kill(); err != nil { - t.Errorf("cmd.ProcessKill(): %v", err) - } -} - -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) - } - } - } -} |