github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/mergeCode/runc/libcontainer/integration/execin_test.go (about)

     1  package integration
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"os"
     8  	"strconv"
     9  	"strings"
    10  	"syscall"
    11  	"testing"
    12  	"time"
    13  
    14  	"github.com/opencontainers/runc/libcontainer"
    15  	"github.com/opencontainers/runc/libcontainer/configs"
    16  )
    17  
    18  func TestExecIn(t *testing.T) {
    19  	if testing.Short() {
    20  		return
    21  	}
    22  	rootfs, err := newRootfs()
    23  	ok(t, err)
    24  	defer remove(rootfs)
    25  	config := newTemplateConfig(rootfs)
    26  	container, err := newContainer(config)
    27  	ok(t, err)
    28  	defer container.Destroy()
    29  
    30  	// Execute a first process in the container
    31  	stdinR, stdinW, err := os.Pipe()
    32  	ok(t, err)
    33  	process := &libcontainer.Process{
    34  		Cwd:   "/",
    35  		Args:  []string{"cat"},
    36  		Env:   standardEnvironment,
    37  		Stdin: stdinR,
    38  	}
    39  	err = container.Run(process)
    40  	stdinR.Close()
    41  	defer stdinW.Close()
    42  	ok(t, err)
    43  
    44  	buffers := newStdBuffers()
    45  	ps := &libcontainer.Process{
    46  		Cwd:    "/",
    47  		Args:   []string{"ps"},
    48  		Env:    standardEnvironment,
    49  		Stdin:  buffers.Stdin,
    50  		Stdout: buffers.Stdout,
    51  		Stderr: buffers.Stderr,
    52  	}
    53  
    54  	err = container.Run(ps)
    55  	ok(t, err)
    56  	waitProcess(ps, t)
    57  	stdinW.Close()
    58  	waitProcess(process, t)
    59  
    60  	out := buffers.Stdout.String()
    61  	if !strings.Contains(out, "cat") || !strings.Contains(out, "ps") {
    62  		t.Fatalf("unexpected running process, output %q", out)
    63  	}
    64  	if strings.Contains(out, "\r") {
    65  		t.Fatalf("unexpected carriage-return in output")
    66  	}
    67  }
    68  
    69  func TestExecInUsernsRlimit(t *testing.T) {
    70  	if _, err := os.Stat("/proc/self/ns/user"); os.IsNotExist(err) {
    71  		t.Skip("userns is unsupported")
    72  	}
    73  
    74  	testExecInRlimit(t, true)
    75  }
    76  
    77  func TestExecInRlimit(t *testing.T) {
    78  	testExecInRlimit(t, false)
    79  }
    80  
    81  func testExecInRlimit(t *testing.T, userns bool) {
    82  	if testing.Short() {
    83  		return
    84  	}
    85  
    86  	rootfs, err := newRootfs()
    87  	ok(t, err)
    88  	defer remove(rootfs)
    89  
    90  	config := newTemplateConfig(rootfs)
    91  	if userns {
    92  		config.UidMappings = []configs.IDMap{{0, 0, 1000}}
    93  		config.GidMappings = []configs.IDMap{{0, 0, 1000}}
    94  		config.Namespaces = append(config.Namespaces, configs.Namespace{Type: configs.NEWUSER})
    95  	}
    96  
    97  	container, err := newContainer(config)
    98  	ok(t, err)
    99  	defer container.Destroy()
   100  
   101  	stdinR, stdinW, err := os.Pipe()
   102  	ok(t, err)
   103  	process := &libcontainer.Process{
   104  		Cwd:   "/",
   105  		Args:  []string{"cat"},
   106  		Env:   standardEnvironment,
   107  		Stdin: stdinR,
   108  	}
   109  	err = container.Run(process)
   110  	stdinR.Close()
   111  	defer stdinW.Close()
   112  	ok(t, err)
   113  
   114  	buffers := newStdBuffers()
   115  	ps := &libcontainer.Process{
   116  		Cwd:    "/",
   117  		Args:   []string{"/bin/sh", "-c", "ulimit -n"},
   118  		Env:    standardEnvironment,
   119  		Stdin:  buffers.Stdin,
   120  		Stdout: buffers.Stdout,
   121  		Stderr: buffers.Stderr,
   122  		Rlimits: []configs.Rlimit{
   123  			// increase process rlimit higher than container rlimit to test per-process limit
   124  			{Type: syscall.RLIMIT_NOFILE, Hard: 1026, Soft: 1026},
   125  		},
   126  	}
   127  	err = container.Run(ps)
   128  	ok(t, err)
   129  	waitProcess(ps, t)
   130  
   131  	stdinW.Close()
   132  	waitProcess(process, t)
   133  
   134  	out := buffers.Stdout.String()
   135  	if limit := strings.TrimSpace(out); limit != "1026" {
   136  		t.Fatalf("expected rlimit to be 1026, got %s", limit)
   137  	}
   138  }
   139  
   140  func TestExecInAdditionalGroups(t *testing.T) {
   141  	if testing.Short() {
   142  		return
   143  	}
   144  
   145  	rootfs, err := newRootfs()
   146  	ok(t, err)
   147  	defer remove(rootfs)
   148  
   149  	config := newTemplateConfig(rootfs)
   150  	container, err := newContainer(config)
   151  	ok(t, err)
   152  	defer container.Destroy()
   153  
   154  	// Execute a first process in the container
   155  	stdinR, stdinW, err := os.Pipe()
   156  	ok(t, err)
   157  	process := &libcontainer.Process{
   158  		Cwd:   "/",
   159  		Args:  []string{"cat"},
   160  		Env:   standardEnvironment,
   161  		Stdin: stdinR,
   162  	}
   163  	err = container.Run(process)
   164  	stdinR.Close()
   165  	defer stdinW.Close()
   166  	ok(t, err)
   167  
   168  	var stdout bytes.Buffer
   169  	pconfig := libcontainer.Process{
   170  		Cwd:              "/",
   171  		Args:             []string{"sh", "-c", "id", "-Gn"},
   172  		Env:              standardEnvironment,
   173  		Stdin:            nil,
   174  		Stdout:           &stdout,
   175  		AdditionalGroups: []string{"plugdev", "audio"},
   176  	}
   177  	err = container.Run(&pconfig)
   178  	ok(t, err)
   179  
   180  	// Wait for process
   181  	waitProcess(&pconfig, t)
   182  
   183  	stdinW.Close()
   184  	waitProcess(process, t)
   185  
   186  	outputGroups := string(stdout.Bytes())
   187  
   188  	// Check that the groups output has the groups that we specified
   189  	if !strings.Contains(outputGroups, "audio") {
   190  		t.Fatalf("Listed groups do not contain the audio group as expected: %v", outputGroups)
   191  	}
   192  
   193  	if !strings.Contains(outputGroups, "plugdev") {
   194  		t.Fatalf("Listed groups do not contain the plugdev group as expected: %v", outputGroups)
   195  	}
   196  }
   197  
   198  func TestExecInError(t *testing.T) {
   199  	if testing.Short() {
   200  		return
   201  	}
   202  	rootfs, err := newRootfs()
   203  	ok(t, err)
   204  	defer remove(rootfs)
   205  	config := newTemplateConfig(rootfs)
   206  	container, err := newContainer(config)
   207  	ok(t, err)
   208  	defer container.Destroy()
   209  
   210  	// Execute a first process in the container
   211  	stdinR, stdinW, err := os.Pipe()
   212  	ok(t, err)
   213  	process := &libcontainer.Process{
   214  		Cwd:   "/",
   215  		Args:  []string{"cat"},
   216  		Env:   standardEnvironment,
   217  		Stdin: stdinR,
   218  	}
   219  	err = container.Run(process)
   220  	stdinR.Close()
   221  	defer func() {
   222  		stdinW.Close()
   223  		if _, err := process.Wait(); err != nil {
   224  			t.Log(err)
   225  		}
   226  	}()
   227  	ok(t, err)
   228  
   229  	for i := 0; i < 42; i++ {
   230  		var out bytes.Buffer
   231  		unexistent := &libcontainer.Process{
   232  			Cwd:    "/",
   233  			Args:   []string{"unexistent"},
   234  			Env:    standardEnvironment,
   235  			Stdout: &out,
   236  		}
   237  		err = container.Run(unexistent)
   238  		if err == nil {
   239  			t.Fatal("Should be an error")
   240  		}
   241  		if !strings.Contains(err.Error(), "executable file not found") {
   242  			t.Fatalf("Should be error about not found executable, got %s", err)
   243  		}
   244  		if !bytes.Contains(out.Bytes(), []byte("executable file not found")) {
   245  			t.Fatalf("executable file not found error not delivered to stdio:\n%s", out.String())
   246  		}
   247  	}
   248  }
   249  
   250  func TestExecInTTY(t *testing.T) {
   251  	if testing.Short() {
   252  		return
   253  	}
   254  	rootfs, err := newRootfs()
   255  	ok(t, err)
   256  	defer remove(rootfs)
   257  	config := newTemplateConfig(rootfs)
   258  	container, err := newContainer(config)
   259  	ok(t, err)
   260  	defer container.Destroy()
   261  
   262  	// Execute a first process in the container
   263  	stdinR, stdinW, err := os.Pipe()
   264  	ok(t, err)
   265  	process := &libcontainer.Process{
   266  		Cwd:   "/",
   267  		Args:  []string{"cat"},
   268  		Env:   standardEnvironment,
   269  		Stdin: stdinR,
   270  	}
   271  	err = container.Run(process)
   272  	stdinR.Close()
   273  	defer stdinW.Close()
   274  	ok(t, err)
   275  
   276  	var stdout bytes.Buffer
   277  	ps := &libcontainer.Process{
   278  		Cwd:  "/",
   279  		Args: []string{"ps"},
   280  		Env:  standardEnvironment,
   281  	}
   282  	console, err := ps.NewConsole(0, 0)
   283  	copy := make(chan struct{})
   284  	go func() {
   285  		io.Copy(&stdout, console)
   286  		close(copy)
   287  	}()
   288  	ok(t, err)
   289  	err = container.Run(ps)
   290  	ok(t, err)
   291  	select {
   292  	case <-time.After(5 * time.Second):
   293  		t.Fatal("Waiting for copy timed out")
   294  	case <-copy:
   295  	}
   296  	waitProcess(ps, t)
   297  
   298  	stdinW.Close()
   299  	waitProcess(process, t)
   300  
   301  	out := stdout.String()
   302  	if !strings.Contains(out, "cat") || !strings.Contains(out, "ps") {
   303  		t.Fatalf("unexpected running process, output %q", out)
   304  	}
   305  	if strings.Contains(out, "\r") {
   306  		t.Fatalf("unexpected carriage-return in output")
   307  	}
   308  }
   309  
   310  func TestExecInEnvironment(t *testing.T) {
   311  	if testing.Short() {
   312  		return
   313  	}
   314  	rootfs, err := newRootfs()
   315  	ok(t, err)
   316  	defer remove(rootfs)
   317  	config := newTemplateConfig(rootfs)
   318  	container, err := newContainer(config)
   319  	ok(t, err)
   320  	defer container.Destroy()
   321  
   322  	// Execute a first process in the container
   323  	stdinR, stdinW, err := os.Pipe()
   324  	ok(t, err)
   325  	process := &libcontainer.Process{
   326  		Cwd:   "/",
   327  		Args:  []string{"cat"},
   328  		Env:   standardEnvironment,
   329  		Stdin: stdinR,
   330  	}
   331  	err = container.Run(process)
   332  	stdinR.Close()
   333  	defer stdinW.Close()
   334  	ok(t, err)
   335  
   336  	buffers := newStdBuffers()
   337  	process2 := &libcontainer.Process{
   338  		Cwd:  "/",
   339  		Args: []string{"env"},
   340  		Env: []string{
   341  			"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
   342  			"DEBUG=true",
   343  			"DEBUG=false",
   344  			"ENV=test",
   345  		},
   346  		Stdin:  buffers.Stdin,
   347  		Stdout: buffers.Stdout,
   348  		Stderr: buffers.Stderr,
   349  	}
   350  	err = container.Run(process2)
   351  	ok(t, err)
   352  	waitProcess(process2, t)
   353  
   354  	stdinW.Close()
   355  	waitProcess(process, t)
   356  
   357  	out := buffers.Stdout.String()
   358  	// check execin's process environment
   359  	if !strings.Contains(out, "DEBUG=false") ||
   360  		!strings.Contains(out, "ENV=test") ||
   361  		!strings.Contains(out, "HOME=/root") ||
   362  		!strings.Contains(out, "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin") ||
   363  		strings.Contains(out, "DEBUG=true") {
   364  		t.Fatalf("unexpected running process, output %q", out)
   365  	}
   366  }
   367  
   368  func TestExecinPassExtraFiles(t *testing.T) {
   369  	if testing.Short() {
   370  		return
   371  	}
   372  	rootfs, err := newRootfs()
   373  	if err != nil {
   374  		t.Fatal(err)
   375  	}
   376  	defer remove(rootfs)
   377  	config := newTemplateConfig(rootfs)
   378  	container, err := newContainer(config)
   379  	if err != nil {
   380  		t.Fatal(err)
   381  	}
   382  	defer container.Destroy()
   383  
   384  	// Execute a first process in the container
   385  	stdinR, stdinW, err := os.Pipe()
   386  	if err != nil {
   387  		t.Fatal(err)
   388  	}
   389  	process := &libcontainer.Process{
   390  		Cwd:   "/",
   391  		Args:  []string{"cat"},
   392  		Env:   standardEnvironment,
   393  		Stdin: stdinR,
   394  	}
   395  	err = container.Run(process)
   396  	stdinR.Close()
   397  	defer stdinW.Close()
   398  	if err != nil {
   399  		t.Fatal(err)
   400  	}
   401  
   402  	var stdout bytes.Buffer
   403  	pipeout1, pipein1, err := os.Pipe()
   404  	pipeout2, pipein2, err := os.Pipe()
   405  	inprocess := &libcontainer.Process{
   406  		Cwd:        "/",
   407  		Args:       []string{"sh", "-c", "cd /proc/$$/fd; echo -n *; echo -n 1 >3; echo -n 2 >4"},
   408  		Env:        []string{"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"},
   409  		ExtraFiles: []*os.File{pipein1, pipein2},
   410  		Stdin:      nil,
   411  		Stdout:     &stdout,
   412  	}
   413  	err = container.Run(inprocess)
   414  	if err != nil {
   415  		t.Fatal(err)
   416  	}
   417  
   418  	waitProcess(inprocess, t)
   419  	stdinW.Close()
   420  	waitProcess(process, t)
   421  
   422  	out := string(stdout.Bytes())
   423  	// fd 5 is the directory handle for /proc/$$/fd
   424  	if out != "0 1 2 3 4 5" {
   425  		t.Fatalf("expected to have the file descriptors '0 1 2 3 4 5' passed to exec, got '%s'", out)
   426  	}
   427  	var buf = []byte{0}
   428  	_, err = pipeout1.Read(buf)
   429  	if err != nil {
   430  		t.Fatal(err)
   431  	}
   432  	out1 := string(buf)
   433  	if out1 != "1" {
   434  		t.Fatalf("expected first pipe to receive '1', got '%s'", out1)
   435  	}
   436  
   437  	_, err = pipeout2.Read(buf)
   438  	if err != nil {
   439  		t.Fatal(err)
   440  	}
   441  	out2 := string(buf)
   442  	if out2 != "2" {
   443  		t.Fatalf("expected second pipe to receive '2', got '%s'", out2)
   444  	}
   445  }
   446  
   447  func TestExecInOomScoreAdj(t *testing.T) {
   448  	if testing.Short() {
   449  		return
   450  	}
   451  	rootfs, err := newRootfs()
   452  	ok(t, err)
   453  	defer remove(rootfs)
   454  	config := newTemplateConfig(rootfs)
   455  	config.OomScoreAdj = 200
   456  	container, err := newContainer(config)
   457  	ok(t, err)
   458  	defer container.Destroy()
   459  
   460  	stdinR, stdinW, err := os.Pipe()
   461  	ok(t, err)
   462  	process := &libcontainer.Process{
   463  		Cwd:   "/",
   464  		Args:  []string{"cat"},
   465  		Env:   standardEnvironment,
   466  		Stdin: stdinR,
   467  	}
   468  	err = container.Run(process)
   469  	stdinR.Close()
   470  	defer stdinW.Close()
   471  	ok(t, err)
   472  
   473  	buffers := newStdBuffers()
   474  	ps := &libcontainer.Process{
   475  		Cwd:    "/",
   476  		Args:   []string{"/bin/sh", "-c", "cat /proc/self/oom_score_adj"},
   477  		Env:    standardEnvironment,
   478  		Stdin:  buffers.Stdin,
   479  		Stdout: buffers.Stdout,
   480  		Stderr: buffers.Stderr,
   481  	}
   482  	err = container.Run(ps)
   483  	ok(t, err)
   484  	waitProcess(ps, t)
   485  
   486  	stdinW.Close()
   487  	waitProcess(process, t)
   488  
   489  	out := buffers.Stdout.String()
   490  	if oomScoreAdj := strings.TrimSpace(out); oomScoreAdj != strconv.Itoa(config.OomScoreAdj) {
   491  		t.Fatalf("expected oomScoreAdj to be %d, got %s", config.OomScoreAdj, oomScoreAdj)
   492  	}
   493  }
   494  
   495  func TestExecInUserns(t *testing.T) {
   496  	if _, err := os.Stat("/proc/self/ns/user"); os.IsNotExist(err) {
   497  		t.Skip("userns is unsupported")
   498  	}
   499  	if testing.Short() {
   500  		return
   501  	}
   502  	rootfs, err := newRootfs()
   503  	ok(t, err)
   504  	defer remove(rootfs)
   505  	config := newTemplateConfig(rootfs)
   506  	config.UidMappings = []configs.IDMap{{0, 0, 1000}}
   507  	config.GidMappings = []configs.IDMap{{0, 0, 1000}}
   508  	config.Namespaces = append(config.Namespaces, configs.Namespace{Type: configs.NEWUSER})
   509  	container, err := newContainer(config)
   510  	ok(t, err)
   511  	defer container.Destroy()
   512  
   513  	// Execute a first process in the container
   514  	stdinR, stdinW, err := os.Pipe()
   515  	ok(t, err)
   516  
   517  	process := &libcontainer.Process{
   518  		Cwd:   "/",
   519  		Args:  []string{"cat"},
   520  		Env:   standardEnvironment,
   521  		Stdin: stdinR,
   522  	}
   523  	err = container.Run(process)
   524  	stdinR.Close()
   525  	defer stdinW.Close()
   526  	ok(t, err)
   527  
   528  	initPID, err := process.Pid()
   529  	ok(t, err)
   530  	initUserns, err := os.Readlink(fmt.Sprintf("/proc/%d/ns/user", initPID))
   531  	ok(t, err)
   532  
   533  	buffers := newStdBuffers()
   534  	process2 := &libcontainer.Process{
   535  		Cwd:  "/",
   536  		Args: []string{"readlink", "/proc/self/ns/user"},
   537  		Env: []string{
   538  			"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
   539  		},
   540  		Stdout: buffers.Stdout,
   541  		Stderr: os.Stderr,
   542  	}
   543  	err = container.Run(process2)
   544  	ok(t, err)
   545  	waitProcess(process2, t)
   546  	stdinW.Close()
   547  	waitProcess(process, t)
   548  
   549  	if out := strings.TrimSpace(buffers.Stdout.String()); out != initUserns {
   550  		t.Errorf("execin userns(%s), wanted %s", out, initUserns)
   551  	}
   552  }