...

Source file src/github.com/opencontainers/runc/libcontainer/integration/seccomp_test.go

Documentation: github.com/opencontainers/runc/libcontainer/integration

     1  //go:build linux && cgo && seccomp
     2  // +build linux,cgo,seccomp
     3  
     4  package integration
     5  
     6  import (
     7  	"strings"
     8  	"syscall"
     9  	"testing"
    10  
    11  	"github.com/opencontainers/runc/libcontainer"
    12  	"github.com/opencontainers/runc/libcontainer/configs"
    13  	libseccomp "github.com/seccomp/libseccomp-golang"
    14  )
    15  
    16  func TestSeccompDenySyslogWithErrno(t *testing.T) {
    17  	if testing.Short() {
    18  		return
    19  	}
    20  
    21  	errnoRet := uint(syscall.ESRCH)
    22  
    23  	config := newTemplateConfig(t, nil)
    24  	config.Seccomp = &configs.Seccomp{
    25  		DefaultAction: configs.Allow,
    26  		Syscalls: []*configs.Syscall{
    27  			{
    28  				Name:     "syslog",
    29  				Action:   configs.Errno,
    30  				ErrnoRet: &errnoRet,
    31  			},
    32  		},
    33  	}
    34  
    35  	container, err := newContainer(t, config)
    36  	ok(t, err)
    37  	defer container.Destroy() //nolint:errcheck
    38  
    39  	buffers := newStdBuffers()
    40  	pwd := &libcontainer.Process{
    41  		Cwd:    "/",
    42  		Args:   []string{"dmesg"},
    43  		Env:    standardEnvironment,
    44  		Stdin:  buffers.Stdin,
    45  		Stdout: buffers.Stdout,
    46  		Stderr: buffers.Stderr,
    47  		Init:   true,
    48  	}
    49  
    50  	err = container.Run(pwd)
    51  	ok(t, err)
    52  	ps, err := pwd.Wait()
    53  	if err == nil {
    54  		t.Fatal("Expecting error (negative return code); instead exited cleanly!")
    55  	}
    56  
    57  	var exitCode int
    58  	status := ps.Sys().(syscall.WaitStatus)
    59  	if status.Exited() {
    60  		exitCode = status.ExitStatus()
    61  	} else if status.Signaled() {
    62  		exitCode = -int(status.Signal())
    63  	} else {
    64  		t.Fatalf("Unrecognized exit reason!")
    65  	}
    66  
    67  	if exitCode == 0 {
    68  		t.Fatalf("dmesg should fail with negative exit code, instead got %d!", exitCode)
    69  	}
    70  
    71  	expected := "dmesg: klogctl: No such process"
    72  	actual := strings.Trim(buffers.Stderr.String(), "\n")
    73  	if actual != expected {
    74  		t.Fatalf("Expected output %s but got %s\n", expected, actual)
    75  	}
    76  }
    77  
    78  func TestSeccompDenySyslog(t *testing.T) {
    79  	if testing.Short() {
    80  		return
    81  	}
    82  
    83  	config := newTemplateConfig(t, nil)
    84  	config.Seccomp = &configs.Seccomp{
    85  		DefaultAction: configs.Allow,
    86  		Syscalls: []*configs.Syscall{
    87  			{
    88  				Name:   "syslog",
    89  				Action: configs.Errno,
    90  			},
    91  		},
    92  	}
    93  
    94  	container, err := newContainer(t, config)
    95  	ok(t, err)
    96  	defer container.Destroy() //nolint:errcheck
    97  
    98  	buffers := newStdBuffers()
    99  	pwd := &libcontainer.Process{
   100  		Cwd:    "/",
   101  		Args:   []string{"dmesg"},
   102  		Env:    standardEnvironment,
   103  		Stdin:  buffers.Stdin,
   104  		Stdout: buffers.Stdout,
   105  		Stderr: buffers.Stderr,
   106  		Init:   true,
   107  	}
   108  
   109  	err = container.Run(pwd)
   110  	ok(t, err)
   111  	ps, err := pwd.Wait()
   112  	if err == nil {
   113  		t.Fatal("Expecting error (negative return code); instead exited cleanly!")
   114  	}
   115  
   116  	var exitCode int
   117  	status := ps.Sys().(syscall.WaitStatus)
   118  	if status.Exited() {
   119  		exitCode = status.ExitStatus()
   120  	} else if status.Signaled() {
   121  		exitCode = -int(status.Signal())
   122  	} else {
   123  		t.Fatalf("Unrecognized exit reason!")
   124  	}
   125  
   126  	if exitCode == 0 {
   127  		t.Fatalf("dmesg should fail with negative exit code, instead got %d!", exitCode)
   128  	}
   129  
   130  	expected := "dmesg: klogctl: Operation not permitted"
   131  	actual := strings.Trim(buffers.Stderr.String(), "\n")
   132  	if actual != expected {
   133  		t.Fatalf("Expected output %s but got %s\n", expected, actual)
   134  	}
   135  }
   136  
   137  func TestSeccompPermitWriteConditional(t *testing.T) {
   138  	if testing.Short() {
   139  		return
   140  	}
   141  
   142  	config := newTemplateConfig(t, nil)
   143  	config.Seccomp = &configs.Seccomp{
   144  		DefaultAction: configs.Allow,
   145  		Syscalls: []*configs.Syscall{
   146  			{
   147  				Name:   "write",
   148  				Action: configs.Errno,
   149  				Args: []*configs.Arg{
   150  					{
   151  						Index: 0,
   152  						Value: 2,
   153  						Op:    configs.EqualTo,
   154  					},
   155  				},
   156  			},
   157  		},
   158  	}
   159  
   160  	container, err := newContainer(t, config)
   161  	ok(t, err)
   162  	defer container.Destroy() //nolint:errcheck
   163  
   164  	buffers := newStdBuffers()
   165  	dmesg := &libcontainer.Process{
   166  		Cwd:    "/",
   167  		Args:   []string{"busybox", "ls", "/"},
   168  		Env:    standardEnvironment,
   169  		Stdin:  buffers.Stdin,
   170  		Stdout: buffers.Stdout,
   171  		Stderr: buffers.Stderr,
   172  		Init:   true,
   173  	}
   174  
   175  	err = container.Run(dmesg)
   176  	ok(t, err)
   177  	if _, err := dmesg.Wait(); err != nil {
   178  		t.Fatalf("%s: %s", err, buffers.Stderr)
   179  	}
   180  }
   181  
   182  func TestSeccompDenyWriteConditional(t *testing.T) {
   183  	if testing.Short() {
   184  		return
   185  	}
   186  
   187  	// Only test if library version is v2.2.1 or higher
   188  	// Conditional filtering will always error in v2.2.0 and lower
   189  	major, minor, micro := libseccomp.GetLibraryVersion()
   190  	if (major == 2 && minor < 2) || (major == 2 && minor == 2 && micro < 1) {
   191  		return
   192  	}
   193  
   194  	config := newTemplateConfig(t, nil)
   195  	config.Seccomp = &configs.Seccomp{
   196  		DefaultAction: configs.Allow,
   197  		Syscalls: []*configs.Syscall{
   198  			{
   199  				Name:   "write",
   200  				Action: configs.Errno,
   201  				Args: []*configs.Arg{
   202  					{
   203  						Index: 0,
   204  						Value: 2,
   205  						Op:    configs.EqualTo,
   206  					},
   207  				},
   208  			},
   209  		},
   210  	}
   211  
   212  	container, err := newContainer(t, config)
   213  	ok(t, err)
   214  	defer container.Destroy() //nolint:errcheck
   215  
   216  	buffers := newStdBuffers()
   217  	dmesg := &libcontainer.Process{
   218  		Cwd:    "/",
   219  		Args:   []string{"busybox", "ls", "does_not_exist"},
   220  		Env:    standardEnvironment,
   221  		Stdin:  buffers.Stdin,
   222  		Stdout: buffers.Stdout,
   223  		Stderr: buffers.Stderr,
   224  		Init:   true,
   225  	}
   226  
   227  	err = container.Run(dmesg)
   228  	ok(t, err)
   229  
   230  	ps, err := dmesg.Wait()
   231  	if err == nil {
   232  		t.Fatal("Expecting negative return, instead got 0!")
   233  	}
   234  
   235  	var exitCode int
   236  	status := ps.Sys().(syscall.WaitStatus)
   237  	if status.Exited() {
   238  		exitCode = status.ExitStatus()
   239  	} else if status.Signaled() {
   240  		exitCode = -int(status.Signal())
   241  	} else {
   242  		t.Fatalf("Unrecognized exit reason!")
   243  	}
   244  
   245  	if exitCode == 0 {
   246  		t.Fatalf("Busybox should fail with negative exit code, instead got %d!", exitCode)
   247  	}
   248  
   249  	// We're denying write to stderr, so we expect an empty buffer
   250  	expected := ""
   251  	actual := strings.Trim(buffers.Stderr.String(), "\n")
   252  	if actual != expected {
   253  		t.Fatalf("Expected output %s but got %s\n", expected, actual)
   254  	}
   255  }
   256  
   257  func TestSeccompPermitWriteMultipleConditions(t *testing.T) {
   258  	if testing.Short() {
   259  		return
   260  	}
   261  
   262  	config := newTemplateConfig(t, nil)
   263  	config.Seccomp = &configs.Seccomp{
   264  		DefaultAction: configs.Allow,
   265  		Syscalls: []*configs.Syscall{
   266  			{
   267  				Name:   "write",
   268  				Action: configs.Errno,
   269  				Args: []*configs.Arg{
   270  					{
   271  						Index: 0,
   272  						Value: 2,
   273  						Op:    configs.EqualTo,
   274  					},
   275  					{
   276  						Index: 2,
   277  						Value: 0,
   278  						Op:    configs.NotEqualTo,
   279  					},
   280  				},
   281  			},
   282  		},
   283  	}
   284  
   285  	buffers := runContainerOk(t, config, "ls", "/")
   286  	// We don't need to verify the actual thing printed
   287  	// Just that something was written to stdout
   288  	if len(buffers.Stdout.String()) == 0 {
   289  		t.Fatalf("Nothing was written to stdout, write call failed!\n")
   290  	}
   291  }
   292  
   293  func TestSeccompDenyWriteMultipleConditions(t *testing.T) {
   294  	if testing.Short() {
   295  		return
   296  	}
   297  
   298  	// Only test if library version is v2.2.1 or higher
   299  	// Conditional filtering will always error in v2.2.0 and lower
   300  	major, minor, micro := libseccomp.GetLibraryVersion()
   301  	if (major == 2 && minor < 2) || (major == 2 && minor == 2 && micro < 1) {
   302  		return
   303  	}
   304  
   305  	config := newTemplateConfig(t, nil)
   306  	config.Seccomp = &configs.Seccomp{
   307  		DefaultAction: configs.Allow,
   308  		Syscalls: []*configs.Syscall{
   309  			{
   310  				Name:   "write",
   311  				Action: configs.Errno,
   312  				Args: []*configs.Arg{
   313  					{
   314  						Index: 0,
   315  						Value: 2,
   316  						Op:    configs.EqualTo,
   317  					},
   318  					{
   319  						Index: 2,
   320  						Value: 0,
   321  						Op:    configs.NotEqualTo,
   322  					},
   323  				},
   324  			},
   325  		},
   326  	}
   327  
   328  	buffers, exitCode, err := runContainer(t, config, "ls", "/does_not_exist")
   329  	if err == nil {
   330  		t.Fatalf("Expecting error return, instead got 0")
   331  	}
   332  	if exitCode == 0 {
   333  		t.Fatalf("Busybox should fail with negative exit code, instead got %d!", exitCode)
   334  	}
   335  
   336  	expected := ""
   337  	actual := strings.Trim(buffers.Stderr.String(), "\n")
   338  	if actual != expected {
   339  		t.Fatalf("Expected output %s but got %s\n", expected, actual)
   340  	}
   341  }
   342  
   343  func TestSeccompMultipleConditionSameArgDeniesStdout(t *testing.T) {
   344  	if testing.Short() {
   345  		return
   346  	}
   347  
   348  	// Prevent writing to both stdout and stderr.
   349  	config := newTemplateConfig(t, nil)
   350  	config.Seccomp = &configs.Seccomp{
   351  		DefaultAction: configs.Allow,
   352  		Syscalls: []*configs.Syscall{
   353  			{
   354  				Name:   "write",
   355  				Action: configs.Errno,
   356  				Args: []*configs.Arg{
   357  					{
   358  						Index: 0,
   359  						Value: 1,
   360  						Op:    configs.EqualTo,
   361  					},
   362  					{
   363  						Index: 0,
   364  						Value: 2,
   365  						Op:    configs.EqualTo,
   366  					},
   367  				},
   368  			},
   369  		},
   370  	}
   371  
   372  	buffers := runContainerOk(t, config, "ls", "/")
   373  	// Verify that nothing was printed
   374  	if len(buffers.Stdout.String()) != 0 {
   375  		t.Fatalf("Something was written to stdout, write call succeeded!\n")
   376  	}
   377  }
   378  
   379  func TestSeccompMultipleConditionSameArgDeniesStderr(t *testing.T) {
   380  	if testing.Short() {
   381  		return
   382  	}
   383  
   384  	// Prevent writing to both stdout and stderr.
   385  	config := newTemplateConfig(t, nil)
   386  	config.Seccomp = &configs.Seccomp{
   387  		DefaultAction: configs.Allow,
   388  		Syscalls: []*configs.Syscall{
   389  			{
   390  				Name:   "write",
   391  				Action: configs.Errno,
   392  				Args: []*configs.Arg{
   393  					{
   394  						Index: 0,
   395  						Value: 1,
   396  						Op:    configs.EqualTo,
   397  					},
   398  					{
   399  						Index: 0,
   400  						Value: 2,
   401  						Op:    configs.EqualTo,
   402  					},
   403  				},
   404  			},
   405  		},
   406  	}
   407  
   408  	buffers, exitCode, err := runContainer(t, config, "ls", "/does_not_exist")
   409  	if err == nil {
   410  		t.Fatalf("Expecting error return, instead got 0")
   411  	}
   412  	if exitCode == 0 {
   413  		t.Fatalf("Busybox should fail with negative exit code, instead got %d!", exitCode)
   414  	}
   415  	// Verify nothing was printed
   416  	if len(buffers.Stderr.String()) != 0 {
   417  		t.Fatalf("Something was written to stderr, write call succeeded!\n")
   418  	}
   419  }
   420  

View as plain text