mirror of
				https://github.com/opencontainers/runc.git
				synced 2025-11-01 03:22:38 +08:00 
			
		
		
		
	 2c398bb41d
			
		
	
	2c398bb41d
	
	
	
		
			
			In all the three cases, we check that the program returned non-zero exit code. This can be done in a much simpler manner. Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
		
			
				
	
	
		
			386 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			386 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| //go:build linux && cgo && seccomp
 | |
| 
 | |
| package integration
 | |
| 
 | |
| import (
 | |
| 	"strings"
 | |
| 	"syscall"
 | |
| 	"testing"
 | |
| 
 | |
| 	"github.com/opencontainers/runc/libcontainer"
 | |
| 	"github.com/opencontainers/runc/libcontainer/configs"
 | |
| 	libseccomp "github.com/seccomp/libseccomp-golang"
 | |
| )
 | |
| 
 | |
| func TestSeccompDenySyslogWithErrno(t *testing.T) {
 | |
| 	if testing.Short() {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	errnoRet := uint(syscall.ESRCH)
 | |
| 
 | |
| 	config := newTemplateConfig(t, nil)
 | |
| 	config.Seccomp = &configs.Seccomp{
 | |
| 		DefaultAction: configs.Allow,
 | |
| 		Syscalls: []*configs.Syscall{
 | |
| 			{
 | |
| 				Name:     "syslog",
 | |
| 				Action:   configs.Errno,
 | |
| 				ErrnoRet: &errnoRet,
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	container, err := newContainer(t, config)
 | |
| 	ok(t, err)
 | |
| 	defer container.Destroy() //nolint:errcheck
 | |
| 
 | |
| 	buffers := newStdBuffers()
 | |
| 	pwd := &libcontainer.Process{
 | |
| 		Cwd:    "/",
 | |
| 		Args:   []string{"dmesg"},
 | |
| 		Env:    standardEnvironment,
 | |
| 		Stdin:  buffers.Stdin,
 | |
| 		Stdout: buffers.Stdout,
 | |
| 		Stderr: buffers.Stderr,
 | |
| 		Init:   true,
 | |
| 	}
 | |
| 
 | |
| 	err = container.Run(pwd)
 | |
| 	ok(t, err)
 | |
| 	ps, err := pwd.Wait()
 | |
| 	if err == nil {
 | |
| 		t.Fatal("Expecting error (negative return code); instead exited cleanly!")
 | |
| 	}
 | |
| 	if ps.Success() {
 | |
| 		t.Fatal("dmesg should fail with negative exit code, instead got 0!")
 | |
| 	}
 | |
| 
 | |
| 	expected := "dmesg: klogctl: No such process"
 | |
| 	actual := strings.Trim(buffers.Stderr.String(), "\n")
 | |
| 	if actual != expected {
 | |
| 		t.Fatalf("Expected output %s but got %s\n", expected, actual)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestSeccompDenySyslog(t *testing.T) {
 | |
| 	if testing.Short() {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	config := newTemplateConfig(t, nil)
 | |
| 	config.Seccomp = &configs.Seccomp{
 | |
| 		DefaultAction: configs.Allow,
 | |
| 		Syscalls: []*configs.Syscall{
 | |
| 			{
 | |
| 				Name:   "syslog",
 | |
| 				Action: configs.Errno,
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	container, err := newContainer(t, config)
 | |
| 	ok(t, err)
 | |
| 	defer container.Destroy() //nolint:errcheck
 | |
| 
 | |
| 	buffers := newStdBuffers()
 | |
| 	pwd := &libcontainer.Process{
 | |
| 		Cwd:    "/",
 | |
| 		Args:   []string{"dmesg"},
 | |
| 		Env:    standardEnvironment,
 | |
| 		Stdin:  buffers.Stdin,
 | |
| 		Stdout: buffers.Stdout,
 | |
| 		Stderr: buffers.Stderr,
 | |
| 		Init:   true,
 | |
| 	}
 | |
| 
 | |
| 	err = container.Run(pwd)
 | |
| 	ok(t, err)
 | |
| 	ps, err := pwd.Wait()
 | |
| 	if err == nil {
 | |
| 		t.Fatal("Expecting error (negative return code); instead exited cleanly!")
 | |
| 	}
 | |
| 	if ps.Success() {
 | |
| 		t.Fatal("dmesg should fail with negative exit code, instead got 0!")
 | |
| 	}
 | |
| 
 | |
| 	expected := "dmesg: klogctl: Operation not permitted"
 | |
| 	actual := strings.Trim(buffers.Stderr.String(), "\n")
 | |
| 	if actual != expected {
 | |
| 		t.Fatalf("Expected output %s but got %s\n", expected, actual)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestSeccompPermitWriteConditional(t *testing.T) {
 | |
| 	if testing.Short() {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	config := newTemplateConfig(t, nil)
 | |
| 	config.Seccomp = &configs.Seccomp{
 | |
| 		DefaultAction: configs.Allow,
 | |
| 		Syscalls: []*configs.Syscall{
 | |
| 			{
 | |
| 				Name:   "write",
 | |
| 				Action: configs.Errno,
 | |
| 				Args: []*configs.Arg{
 | |
| 					{
 | |
| 						Index: 0,
 | |
| 						Value: 2,
 | |
| 						Op:    configs.EqualTo,
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	container, err := newContainer(t, config)
 | |
| 	ok(t, err)
 | |
| 	defer container.Destroy() //nolint:errcheck
 | |
| 
 | |
| 	buffers := newStdBuffers()
 | |
| 	dmesg := &libcontainer.Process{
 | |
| 		Cwd:    "/",
 | |
| 		Args:   []string{"busybox", "ls", "/"},
 | |
| 		Env:    standardEnvironment,
 | |
| 		Stdin:  buffers.Stdin,
 | |
| 		Stdout: buffers.Stdout,
 | |
| 		Stderr: buffers.Stderr,
 | |
| 		Init:   true,
 | |
| 	}
 | |
| 
 | |
| 	err = container.Run(dmesg)
 | |
| 	ok(t, err)
 | |
| 	if _, err := dmesg.Wait(); err != nil {
 | |
| 		t.Fatalf("%s: %s", err, buffers.Stderr)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestSeccompDenyWriteConditional(t *testing.T) {
 | |
| 	if testing.Short() {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// Only test if library version is v2.2.1 or higher
 | |
| 	// Conditional filtering will always error in v2.2.0 and lower
 | |
| 	major, minor, micro := libseccomp.GetLibraryVersion()
 | |
| 	if (major == 2 && minor < 2) || (major == 2 && minor == 2 && micro < 1) {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	config := newTemplateConfig(t, nil)
 | |
| 	config.Seccomp = &configs.Seccomp{
 | |
| 		DefaultAction: configs.Allow,
 | |
| 		Syscalls: []*configs.Syscall{
 | |
| 			{
 | |
| 				Name:   "write",
 | |
| 				Action: configs.Errno,
 | |
| 				Args: []*configs.Arg{
 | |
| 					{
 | |
| 						Index: 0,
 | |
| 						Value: 2,
 | |
| 						Op:    configs.EqualTo,
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	container, err := newContainer(t, config)
 | |
| 	ok(t, err)
 | |
| 	defer container.Destroy() //nolint:errcheck
 | |
| 
 | |
| 	buffers := newStdBuffers()
 | |
| 	dmesg := &libcontainer.Process{
 | |
| 		Cwd:    "/",
 | |
| 		Args:   []string{"busybox", "ls", "does_not_exist"},
 | |
| 		Env:    standardEnvironment,
 | |
| 		Stdin:  buffers.Stdin,
 | |
| 		Stdout: buffers.Stdout,
 | |
| 		Stderr: buffers.Stderr,
 | |
| 		Init:   true,
 | |
| 	}
 | |
| 
 | |
| 	err = container.Run(dmesg)
 | |
| 	ok(t, err)
 | |
| 
 | |
| 	ps, err := dmesg.Wait()
 | |
| 	if err == nil {
 | |
| 		t.Fatal("Expecting negative return, instead got 0!")
 | |
| 	}
 | |
| 	if ps.Success() {
 | |
| 		t.Fatal("Busybox should fail with negative exit code, instead got 0!")
 | |
| 	}
 | |
| 
 | |
| 	// We're denying write to stderr, so we expect an empty buffer
 | |
| 	expected := ""
 | |
| 	actual := strings.Trim(buffers.Stderr.String(), "\n")
 | |
| 	if actual != expected {
 | |
| 		t.Fatalf("Expected output %s but got %s\n", expected, actual)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestSeccompPermitWriteMultipleConditions(t *testing.T) {
 | |
| 	if testing.Short() {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	config := newTemplateConfig(t, nil)
 | |
| 	config.Seccomp = &configs.Seccomp{
 | |
| 		DefaultAction: configs.Allow,
 | |
| 		Syscalls: []*configs.Syscall{
 | |
| 			{
 | |
| 				Name:   "write",
 | |
| 				Action: configs.Errno,
 | |
| 				Args: []*configs.Arg{
 | |
| 					{
 | |
| 						Index: 0,
 | |
| 						Value: 2,
 | |
| 						Op:    configs.EqualTo,
 | |
| 					},
 | |
| 					{
 | |
| 						Index: 2,
 | |
| 						Value: 0,
 | |
| 						Op:    configs.NotEqualTo,
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	buffers := runContainerOk(t, config, "ls", "/")
 | |
| 	// We don't need to verify the actual thing printed
 | |
| 	// Just that something was written to stdout
 | |
| 	if len(buffers.Stdout.String()) == 0 {
 | |
| 		t.Fatalf("Nothing was written to stdout, write call failed!\n")
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestSeccompDenyWriteMultipleConditions(t *testing.T) {
 | |
| 	if testing.Short() {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// Only test if library version is v2.2.1 or higher
 | |
| 	// Conditional filtering will always error in v2.2.0 and lower
 | |
| 	major, minor, micro := libseccomp.GetLibraryVersion()
 | |
| 	if (major == 2 && minor < 2) || (major == 2 && minor == 2 && micro < 1) {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	config := newTemplateConfig(t, nil)
 | |
| 	config.Seccomp = &configs.Seccomp{
 | |
| 		DefaultAction: configs.Allow,
 | |
| 		Syscalls: []*configs.Syscall{
 | |
| 			{
 | |
| 				Name:   "write",
 | |
| 				Action: configs.Errno,
 | |
| 				Args: []*configs.Arg{
 | |
| 					{
 | |
| 						Index: 0,
 | |
| 						Value: 2,
 | |
| 						Op:    configs.EqualTo,
 | |
| 					},
 | |
| 					{
 | |
| 						Index: 2,
 | |
| 						Value: 0,
 | |
| 						Op:    configs.NotEqualTo,
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	buffers, exitCode, err := runContainer(t, config, "ls", "/does_not_exist")
 | |
| 	if err == nil {
 | |
| 		t.Fatalf("Expecting error return, instead got 0")
 | |
| 	}
 | |
| 	if exitCode == 0 {
 | |
| 		t.Fatalf("Busybox should fail with negative exit code, instead got %d!", exitCode)
 | |
| 	}
 | |
| 
 | |
| 	expected := ""
 | |
| 	actual := strings.Trim(buffers.Stderr.String(), "\n")
 | |
| 	if actual != expected {
 | |
| 		t.Fatalf("Expected output %s but got %s\n", expected, actual)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestSeccompMultipleConditionSameArgDeniesStdout(t *testing.T) {
 | |
| 	if testing.Short() {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// Prevent writing to both stdout and stderr.
 | |
| 	config := newTemplateConfig(t, nil)
 | |
| 	config.Seccomp = &configs.Seccomp{
 | |
| 		DefaultAction: configs.Allow,
 | |
| 		Syscalls: []*configs.Syscall{
 | |
| 			{
 | |
| 				Name:   "write",
 | |
| 				Action: configs.Errno,
 | |
| 				Args: []*configs.Arg{
 | |
| 					{
 | |
| 						Index: 0,
 | |
| 						Value: 1,
 | |
| 						Op:    configs.EqualTo,
 | |
| 					},
 | |
| 					{
 | |
| 						Index: 0,
 | |
| 						Value: 2,
 | |
| 						Op:    configs.EqualTo,
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	buffers := runContainerOk(t, config, "ls", "/")
 | |
| 	// Verify that nothing was printed
 | |
| 	if len(buffers.Stdout.String()) != 0 {
 | |
| 		t.Fatalf("Something was written to stdout, write call succeeded!\n")
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestSeccompMultipleConditionSameArgDeniesStderr(t *testing.T) {
 | |
| 	if testing.Short() {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// Prevent writing to both stdout and stderr.
 | |
| 	config := newTemplateConfig(t, nil)
 | |
| 	config.Seccomp = &configs.Seccomp{
 | |
| 		DefaultAction: configs.Allow,
 | |
| 		Syscalls: []*configs.Syscall{
 | |
| 			{
 | |
| 				Name:   "write",
 | |
| 				Action: configs.Errno,
 | |
| 				Args: []*configs.Arg{
 | |
| 					{
 | |
| 						Index: 0,
 | |
| 						Value: 1,
 | |
| 						Op:    configs.EqualTo,
 | |
| 					},
 | |
| 					{
 | |
| 						Index: 0,
 | |
| 						Value: 2,
 | |
| 						Op:    configs.EqualTo,
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	buffers, exitCode, err := runContainer(t, config, "ls", "/does_not_exist")
 | |
| 	if err == nil {
 | |
| 		t.Fatalf("Expecting error return, instead got 0")
 | |
| 	}
 | |
| 	if exitCode == 0 {
 | |
| 		t.Fatalf("Busybox should fail with negative exit code, instead got %d!", exitCode)
 | |
| 	}
 | |
| 	// Verify nothing was printed
 | |
| 	if len(buffers.Stderr.String()) != 0 {
 | |
| 		t.Fatalf("Something was written to stderr, write call succeeded!\n")
 | |
| 	}
 | |
| }
 |