github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/runsc/container/container_test.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package container
    16  
    17  import (
    18  	"bytes"
    19  	"flag"
    20  	"fmt"
    21  	"io"
    22  	"io/ioutil"
    23  	"math"
    24  	"os"
    25  	"path"
    26  	"path/filepath"
    27  	"reflect"
    28  	"strconv"
    29  	"strings"
    30  	"testing"
    31  	"time"
    32  
    33  	"github.com/cenkalti/backoff"
    34  	specs "github.com/opencontainers/runtime-spec/specs-go"
    35  	"golang.org/x/sys/unix"
    36  	"github.com/SagerNet/gvisor/pkg/abi/linux"
    37  	"github.com/SagerNet/gvisor/pkg/bits"
    38  	"github.com/SagerNet/gvisor/pkg/log"
    39  	"github.com/SagerNet/gvisor/pkg/sentry/control"
    40  	"github.com/SagerNet/gvisor/pkg/sentry/kernel"
    41  	"github.com/SagerNet/gvisor/pkg/sentry/kernel/auth"
    42  	"github.com/SagerNet/gvisor/pkg/sync"
    43  	"github.com/SagerNet/gvisor/pkg/test/testutil"
    44  	"github.com/SagerNet/gvisor/pkg/urpc"
    45  	"github.com/SagerNet/gvisor/runsc/boot/platforms"
    46  	"github.com/SagerNet/gvisor/runsc/config"
    47  	"github.com/SagerNet/gvisor/runsc/specutils"
    48  )
    49  
    50  func TestMain(m *testing.M) {
    51  	log.SetLevel(log.Debug)
    52  	flag.Parse()
    53  	if err := testutil.ConfigureExePath(); err != nil {
    54  		panic(err.Error())
    55  	}
    56  	specutils.MaybeRunAsRoot()
    57  	os.Exit(m.Run())
    58  }
    59  
    60  func execute(cont *Container, name string, arg ...string) (unix.WaitStatus, error) {
    61  	args := &control.ExecArgs{
    62  		Filename: name,
    63  		Argv:     append([]string{name}, arg...),
    64  	}
    65  	return cont.executeSync(args)
    66  }
    67  
    68  func executeCombinedOutput(cont *Container, name string, arg ...string) ([]byte, error) {
    69  	r, w, err := os.Pipe()
    70  	if err != nil {
    71  		return nil, err
    72  	}
    73  	defer r.Close()
    74  
    75  	args := &control.ExecArgs{
    76  		Filename:    name,
    77  		Argv:        append([]string{name}, arg...),
    78  		FilePayload: urpc.FilePayload{Files: []*os.File{os.Stdin, w, w}},
    79  	}
    80  	ws, err := cont.executeSync(args)
    81  	w.Close()
    82  	if err != nil {
    83  		return nil, err
    84  	}
    85  	if ws != 0 {
    86  		return nil, fmt.Errorf("exec failed, status: %v", ws)
    87  	}
    88  
    89  	out, err := ioutil.ReadAll(r)
    90  	return out, err
    91  }
    92  
    93  // executeSync synchronously executes a new process.
    94  func (c *Container) executeSync(args *control.ExecArgs) (unix.WaitStatus, error) {
    95  	pid, err := c.Execute(args)
    96  	if err != nil {
    97  		return 0, fmt.Errorf("error executing: %v", err)
    98  	}
    99  	ws, err := c.WaitPID(pid)
   100  	if err != nil {
   101  		return 0, fmt.Errorf("error waiting: %v", err)
   102  	}
   103  	return ws, nil
   104  }
   105  
   106  // waitForProcessList waits for the given process list to show up in the container.
   107  func waitForProcessList(cont *Container, want []*control.Process) error {
   108  	cb := func() error {
   109  		got, err := cont.Processes()
   110  		if err != nil {
   111  			err = fmt.Errorf("error getting process data from container: %w", err)
   112  			return &backoff.PermanentError{Err: err}
   113  		}
   114  		if !procListsEqual(got, want) {
   115  			return fmt.Errorf("container got process list: %s, want: %s", procListToString(got), procListToString(want))
   116  		}
   117  		return nil
   118  	}
   119  	// Gives plenty of time as tests can run slow under --race.
   120  	return testutil.Poll(cb, 30*time.Second)
   121  }
   122  
   123  // waitForProcess waits for the given process to show up in the container.
   124  func waitForProcess(cont *Container, want *control.Process) error {
   125  	cb := func() error {
   126  		gots, err := cont.Processes()
   127  		if err != nil {
   128  			err = fmt.Errorf("error getting process data from container: %w", err)
   129  			return &backoff.PermanentError{Err: err}
   130  		}
   131  		for _, got := range gots {
   132  			if procEqual(got, want) {
   133  				return nil
   134  			}
   135  		}
   136  		return fmt.Errorf("container got process list: %s, want: %+v", procListToString(gots), want)
   137  	}
   138  	// Gives plenty of time as tests can run slow under --race.
   139  	return testutil.Poll(cb, 30*time.Second)
   140  }
   141  
   142  func waitForProcessCount(cont *Container, want int) error {
   143  	cb := func() error {
   144  		pss, err := cont.Processes()
   145  		if err != nil {
   146  			err = fmt.Errorf("error getting process data from container: %w", err)
   147  			return &backoff.PermanentError{Err: err}
   148  		}
   149  		if got := len(pss); got != want {
   150  			log.Infof("Waiting for process count to reach %d. Current: %d", want, got)
   151  			return fmt.Errorf("wrong process count, got: %d, want: %d", got, want)
   152  		}
   153  		return nil
   154  	}
   155  	// Gives plenty of time as tests can run slow under --race.
   156  	return testutil.Poll(cb, 30*time.Second)
   157  }
   158  
   159  func blockUntilWaitable(pid int) error {
   160  	_, _, err := specutils.RetryEintr(func() (uintptr, uintptr, error) {
   161  		var err error
   162  		_, _, err1 := unix.Syscall6(unix.SYS_WAITID, 1, uintptr(pid), 0, unix.WEXITED|unix.WNOWAIT, 0, 0)
   163  		if err1 != 0 {
   164  			err = err1
   165  		}
   166  		return 0, 0, err
   167  	})
   168  	return err
   169  }
   170  
   171  // execPS executes `ps` inside the container and return the processes.
   172  func execPS(c *Container) ([]*control.Process, error) {
   173  	out, err := executeCombinedOutput(c, "/bin/ps", "-e")
   174  	if err != nil {
   175  		return nil, err
   176  	}
   177  	lines := strings.Split(string(out), "\n")
   178  	if len(lines) < 1 {
   179  		return nil, fmt.Errorf("missing header: %q", lines)
   180  	}
   181  	procs := make([]*control.Process, 0, len(lines)-1)
   182  	for _, line := range lines[1:] {
   183  		if len(line) == 0 {
   184  			continue
   185  		}
   186  		fields := strings.Fields(line)
   187  		if len(fields) != 4 {
   188  			return nil, fmt.Errorf("malformed line: %s", line)
   189  		}
   190  		pid, err := strconv.Atoi(fields[0])
   191  		if err != nil {
   192  			return nil, err
   193  		}
   194  		cmd := fields[3]
   195  		// Fill only the fields we need thus far.
   196  		procs = append(procs, &control.Process{
   197  			PID: kernel.ThreadID(pid),
   198  			Cmd: cmd,
   199  		})
   200  	}
   201  	return procs, nil
   202  }
   203  
   204  // procListsEqual is used to check whether 2 Process lists are equal. Fields
   205  // set to -1 in wants are ignored. Timestamp and threads fields are always
   206  // ignored.
   207  func procListsEqual(gots, wants []*control.Process) bool {
   208  	if len(gots) != len(wants) {
   209  		return false
   210  	}
   211  	for i := range gots {
   212  		if !procEqual(gots[i], wants[i]) {
   213  			return false
   214  		}
   215  	}
   216  	return true
   217  }
   218  
   219  func procEqual(got, want *control.Process) bool {
   220  	if want.UID != math.MaxUint32 && want.UID != got.UID {
   221  		return false
   222  	}
   223  	if want.PID != -1 && want.PID != got.PID {
   224  		return false
   225  	}
   226  	if want.PPID != -1 && want.PPID != got.PPID {
   227  		return false
   228  	}
   229  	if len(want.TTY) != 0 && want.TTY != got.TTY {
   230  		return false
   231  	}
   232  	if len(want.Cmd) != 0 && want.Cmd != got.Cmd {
   233  		return false
   234  	}
   235  	return true
   236  }
   237  
   238  type processBuilder struct {
   239  	process control.Process
   240  }
   241  
   242  func newProcessBuilder() *processBuilder {
   243  	return &processBuilder{
   244  		process: control.Process{
   245  			UID:  math.MaxUint32,
   246  			PID:  -1,
   247  			PPID: -1,
   248  		},
   249  	}
   250  }
   251  
   252  func (p *processBuilder) Cmd(cmd string) *processBuilder {
   253  	p.process.Cmd = cmd
   254  	return p
   255  }
   256  
   257  func (p *processBuilder) PID(pid kernel.ThreadID) *processBuilder {
   258  	p.process.PID = pid
   259  	return p
   260  }
   261  
   262  func (p *processBuilder) PPID(ppid kernel.ThreadID) *processBuilder {
   263  	p.process.PPID = ppid
   264  	return p
   265  }
   266  
   267  func (p *processBuilder) UID(uid auth.KUID) *processBuilder {
   268  	p.process.UID = uid
   269  	return p
   270  }
   271  
   272  func (p *processBuilder) Process() *control.Process {
   273  	return &p.process
   274  }
   275  
   276  func procListToString(pl []*control.Process) string {
   277  	strs := make([]string, 0, len(pl))
   278  	for _, p := range pl {
   279  		strs = append(strs, fmt.Sprintf("%+v", p))
   280  	}
   281  	return fmt.Sprintf("[%s]", strings.Join(strs, ","))
   282  }
   283  
   284  // createWriteableOutputFile creates an output file that can be read and
   285  // written to in the sandbox.
   286  func createWriteableOutputFile(path string) (*os.File, error) {
   287  	outputFile, err := os.OpenFile(path, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666)
   288  	if err != nil {
   289  		return nil, fmt.Errorf("error creating file: %q, %v", path, err)
   290  	}
   291  
   292  	// Chmod to allow writing after umask.
   293  	if err := outputFile.Chmod(0666); err != nil {
   294  		return nil, fmt.Errorf("error chmoding file: %q, %v", path, err)
   295  	}
   296  	return outputFile, nil
   297  }
   298  
   299  func waitForFileNotEmpty(f *os.File) error {
   300  	op := func() error {
   301  		fi, err := f.Stat()
   302  		if err != nil {
   303  			return err
   304  		}
   305  		if fi.Size() == 0 {
   306  			return fmt.Errorf("file %q is empty", f.Name())
   307  		}
   308  		return nil
   309  	}
   310  
   311  	return testutil.Poll(op, 30*time.Second)
   312  }
   313  
   314  func waitForFileExist(path string) error {
   315  	op := func() error {
   316  		if _, err := os.Stat(path); os.IsNotExist(err) {
   317  			return err
   318  		}
   319  		return nil
   320  	}
   321  
   322  	return testutil.Poll(op, 30*time.Second)
   323  }
   324  
   325  // readOutputNum reads a file at given filepath and returns the int at the
   326  // requested position.
   327  func readOutputNum(file string, position int) (int, error) {
   328  	f, err := os.Open(file)
   329  	if err != nil {
   330  		return 0, fmt.Errorf("error opening file: %q, %v", file, err)
   331  	}
   332  
   333  	// Ensure that there is content in output file.
   334  	if err := waitForFileNotEmpty(f); err != nil {
   335  		return 0, fmt.Errorf("error waiting for output file: %v", err)
   336  	}
   337  
   338  	b, err := ioutil.ReadAll(f)
   339  	if err != nil {
   340  		return 0, fmt.Errorf("error reading file: %v", err)
   341  	}
   342  	if len(b) == 0 {
   343  		return 0, fmt.Errorf("error no content was read")
   344  	}
   345  
   346  	// Strip leading null bytes caused by file offset not being 0 upon restore.
   347  	b = bytes.Trim(b, "\x00")
   348  	nums := strings.Split(string(b), "\n")
   349  
   350  	if position >= len(nums) {
   351  		return 0, fmt.Errorf("position %v is not within the length of content %v", position, nums)
   352  	}
   353  	if position == -1 {
   354  		// Expectation of newline at the end of last position.
   355  		position = len(nums) - 2
   356  	}
   357  	num, err := strconv.Atoi(nums[position])
   358  	if err != nil {
   359  		return 0, fmt.Errorf("error getting number from file: %v", err)
   360  	}
   361  	return num, nil
   362  }
   363  
   364  // run starts the sandbox and waits for it to exit, checking that the
   365  // application succeeded.
   366  func run(spec *specs.Spec, conf *config.Config) error {
   367  	_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
   368  	if err != nil {
   369  		return fmt.Errorf("error setting up container: %v", err)
   370  	}
   371  	defer cleanup()
   372  
   373  	// Create, start and wait for the container.
   374  	args := Args{
   375  		ID:        testutil.RandomContainerID(),
   376  		Spec:      spec,
   377  		BundleDir: bundleDir,
   378  		Attached:  true,
   379  	}
   380  	ws, err := Run(conf, args)
   381  	if err != nil {
   382  		return fmt.Errorf("running container: %v", err)
   383  	}
   384  	if !ws.Exited() || ws.ExitStatus() != 0 {
   385  		return fmt.Errorf("container failed, waitStatus: %v", ws)
   386  	}
   387  	return nil
   388  }
   389  
   390  type configOption int
   391  
   392  const (
   393  	overlay configOption = iota
   394  	ptrace
   395  	kvm
   396  	nonExclusiveFS
   397  )
   398  
   399  var (
   400  	noOverlay = append(platformOptions, nonExclusiveFS)
   401  	all       = append(noOverlay, overlay)
   402  )
   403  
   404  func configsHelper(t *testing.T, opts ...configOption) map[string]*config.Config {
   405  	// Always load the default config.
   406  	cs := make(map[string]*config.Config)
   407  	testutil.TestConfig(t)
   408  	for _, o := range opts {
   409  		c := testutil.TestConfig(t)
   410  		switch o {
   411  		case overlay:
   412  			c.Overlay = true
   413  			cs["overlay"] = c
   414  		case ptrace:
   415  			c.Platform = platforms.Ptrace
   416  			cs["ptrace"] = c
   417  		case kvm:
   418  			c.Platform = platforms.KVM
   419  			cs["kvm"] = c
   420  		case nonExclusiveFS:
   421  			c.FileAccess = config.FileAccessShared
   422  			cs["non-exclusive"] = c
   423  		default:
   424  			panic(fmt.Sprintf("unknown config option %v", o))
   425  		}
   426  	}
   427  	return cs
   428  }
   429  
   430  // configs generates different configurations to run tests.
   431  //
   432  // TODO(github.com/SagerNet/issue/1624): Remove VFS1 dimension.
   433  func configs(t *testing.T, opts ...configOption) map[string]*config.Config {
   434  	all := configsHelper(t, opts...)
   435  	for key, value := range configsHelper(t, opts...) {
   436  		value.VFS2 = true
   437  		all[key+"VFS2"] = value
   438  	}
   439  	return all
   440  }
   441  
   442  // TestLifecycle tests the basic Create/Start/Signal/Destroy container lifecycle.
   443  // It verifies after each step that the container can be loaded from disk, and
   444  // has the correct status.
   445  func TestLifecycle(t *testing.T) {
   446  	// Start the child reaper.
   447  	childReaper := &testutil.Reaper{}
   448  	childReaper.Start()
   449  	defer childReaper.Stop()
   450  
   451  	for name, conf := range configs(t, all...) {
   452  		t.Run(name, func(t *testing.T) {
   453  			// The container will just sleep for a long time.  We will kill it before
   454  			// it finishes sleeping.
   455  			spec := testutil.NewSpecWithArgs("sleep", "100")
   456  
   457  			rootDir, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
   458  			if err != nil {
   459  				t.Fatalf("error setting up container: %v", err)
   460  			}
   461  			defer cleanup()
   462  
   463  			// expectedPL lists the expected process state of the container.
   464  			expectedPL := []*control.Process{
   465  				newProcessBuilder().Cmd("sleep").Process(),
   466  			}
   467  			// Create the container.
   468  			args := Args{
   469  				ID:        testutil.RandomContainerID(),
   470  				Spec:      spec,
   471  				BundleDir: bundleDir,
   472  			}
   473  			c, err := New(conf, args)
   474  			if err != nil {
   475  				t.Fatalf("error creating container: %v", err)
   476  			}
   477  			defer c.Destroy()
   478  
   479  			// Load the container from disk and check the status.
   480  			c, err = Load(rootDir, FullID{ContainerID: args.ID}, LoadOpts{})
   481  			if err != nil {
   482  				t.Fatalf("error loading container: %v", err)
   483  			}
   484  			if got, want := c.Status, Created; got != want {
   485  				t.Errorf("container status got %v, want %v", got, want)
   486  			}
   487  
   488  			// List should return the container id.
   489  			ids, err := List(rootDir)
   490  			if err != nil {
   491  				t.Fatalf("error listing containers: %v", err)
   492  			}
   493  			fullID := FullID{
   494  				SandboxID:   args.ID,
   495  				ContainerID: args.ID,
   496  			}
   497  			if got, want := ids, []FullID{fullID}; !reflect.DeepEqual(got, want) {
   498  				t.Errorf("container list got %v, want %v", got, want)
   499  			}
   500  
   501  			// Start the container.
   502  			if err := c.Start(conf); err != nil {
   503  				t.Fatalf("error starting container: %v", err)
   504  			}
   505  
   506  			// Load the container from disk and check the status.
   507  			c, err = Load(rootDir, fullID, LoadOpts{Exact: true})
   508  			if err != nil {
   509  				t.Fatalf("error loading container: %v", err)
   510  			}
   511  			if got, want := c.Status, Running; got != want {
   512  				t.Errorf("container status got %v, want %v", got, want)
   513  			}
   514  
   515  			// Verify that "sleep 100" is running.
   516  			if err := waitForProcessList(c, expectedPL); err != nil {
   517  				t.Error(err)
   518  			}
   519  
   520  			// Wait on the container.
   521  			ch := make(chan error)
   522  			go func() {
   523  				ws, err := c.Wait()
   524  				if err != nil {
   525  					ch <- err
   526  				}
   527  				if got, want := ws.Signal(), unix.SIGTERM; got != want {
   528  					ch <- fmt.Errorf("got signal %v, want %v", got, want)
   529  				}
   530  				ch <- nil
   531  			}()
   532  
   533  			// Wait a bit to ensure that we've started waiting on
   534  			// the container before we signal.
   535  			time.Sleep(time.Second)
   536  
   537  			// Send the container a SIGTERM which will cause it to stop.
   538  			if err := c.SignalContainer(unix.SIGTERM, false); err != nil {
   539  				t.Fatalf("error sending signal %v to container: %v", unix.SIGTERM, err)
   540  			}
   541  
   542  			// Wait for it to die.
   543  			if err := <-ch; err != nil {
   544  				t.Fatalf("error waiting for container: %v", err)
   545  			}
   546  
   547  			// Load the container from disk and check the status.
   548  			c, err = Load(rootDir, fullID, LoadOpts{Exact: true})
   549  			if err != nil {
   550  				t.Fatalf("error loading container: %v", err)
   551  			}
   552  			if got, want := c.Status, Stopped; got != want {
   553  				t.Errorf("container status got %v, want %v", got, want)
   554  			}
   555  
   556  			// Destroy the container.
   557  			if err := c.Destroy(); err != nil {
   558  				t.Fatalf("error destroying container: %v", err)
   559  			}
   560  
   561  			// List should not return the container id.
   562  			ids, err = List(rootDir)
   563  			if err != nil {
   564  				t.Fatalf("error listing containers: %v", err)
   565  			}
   566  			if len(ids) != 0 {
   567  				t.Errorf("expected container list to be empty, but got %v", ids)
   568  			}
   569  
   570  			// Loading the container by id should fail.
   571  			if _, err = Load(rootDir, fullID, LoadOpts{Exact: true}); err == nil {
   572  				t.Errorf("expected loading destroyed container to fail, but it did not")
   573  			}
   574  		})
   575  	}
   576  }
   577  
   578  // Test the we can execute the application with different path formats.
   579  func TestExePath(t *testing.T) {
   580  	// Create two directories that will be prepended to PATH.
   581  	firstPath, err := ioutil.TempDir(testutil.TmpDir(), "first")
   582  	if err != nil {
   583  		t.Fatalf("error creating temporary directory: %v", err)
   584  	}
   585  	defer os.RemoveAll(firstPath)
   586  	secondPath, err := ioutil.TempDir(testutil.TmpDir(), "second")
   587  	if err != nil {
   588  		t.Fatalf("error creating temporary directory: %v", err)
   589  	}
   590  	defer os.RemoveAll(secondPath)
   591  
   592  	// Create two minimal executables in the second path, two of which
   593  	// will be masked by files in first path.
   594  	for _, p := range []string{"unmasked", "masked1", "masked2"} {
   595  		path := filepath.Join(secondPath, p)
   596  		f, err := os.OpenFile(path, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0777)
   597  		if err != nil {
   598  			t.Fatalf("error opening path: %v", err)
   599  		}
   600  		defer f.Close()
   601  		if _, err := io.WriteString(f, "#!/bin/true\n"); err != nil {
   602  			t.Fatalf("error writing contents: %v", err)
   603  		}
   604  	}
   605  
   606  	// Create a non-executable file in the first path which masks a healthy
   607  	// executable in the second.
   608  	nonExecutable := filepath.Join(firstPath, "masked1")
   609  	f2, err := os.OpenFile(nonExecutable, os.O_CREATE|os.O_EXCL, 0666)
   610  	if err != nil {
   611  		t.Fatalf("error opening file: %v", err)
   612  	}
   613  	f2.Close()
   614  
   615  	// Create a non-regular file in the first path which masks a healthy
   616  	// executable in the second.
   617  	nonRegular := filepath.Join(firstPath, "masked2")
   618  	if err := os.Mkdir(nonRegular, 0777); err != nil {
   619  		t.Fatalf("error making directory: %v", err)
   620  	}
   621  
   622  	for name, conf := range configs(t, all...) {
   623  		t.Run(name, func(t *testing.T) {
   624  			for _, test := range []struct {
   625  				path    string
   626  				success bool
   627  			}{
   628  				{path: "true", success: true},
   629  				{path: "bin/true", success: true},
   630  				{path: "/bin/true", success: true},
   631  				{path: "thisfiledoesntexit", success: false},
   632  				{path: "bin/thisfiledoesntexit", success: false},
   633  				{path: "/bin/thisfiledoesntexit", success: false},
   634  
   635  				{path: "unmasked", success: true},
   636  				{path: filepath.Join(firstPath, "unmasked"), success: false},
   637  				{path: filepath.Join(secondPath, "unmasked"), success: true},
   638  
   639  				{path: "masked1", success: true},
   640  				{path: filepath.Join(firstPath, "masked1"), success: false},
   641  				{path: filepath.Join(secondPath, "masked1"), success: true},
   642  
   643  				{path: "masked2", success: true},
   644  				{path: filepath.Join(firstPath, "masked2"), success: false},
   645  				{path: filepath.Join(secondPath, "masked2"), success: true},
   646  			} {
   647  				t.Run(fmt.Sprintf("path=%s,success=%t", test.path, test.success), func(t *testing.T) {
   648  					spec := testutil.NewSpecWithArgs(test.path)
   649  					spec.Process.Env = []string{
   650  						fmt.Sprintf("PATH=%s:%s:%s", firstPath, secondPath, os.Getenv("PATH")),
   651  					}
   652  
   653  					_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
   654  					if err != nil {
   655  						t.Fatalf("exec: error setting up container: %v", err)
   656  					}
   657  					defer cleanup()
   658  
   659  					args := Args{
   660  						ID:        testutil.RandomContainerID(),
   661  						Spec:      spec,
   662  						BundleDir: bundleDir,
   663  						Attached:  true,
   664  					}
   665  					ws, err := Run(conf, args)
   666  
   667  					if test.success {
   668  						if err != nil {
   669  							t.Errorf("exec: error running container: %v", err)
   670  						}
   671  						if ws.ExitStatus() != 0 {
   672  							t.Errorf("exec: got exit status %v want %v", ws.ExitStatus(), 0)
   673  						}
   674  					} else {
   675  						if err == nil {
   676  							t.Errorf("exec: got: no error, want: error")
   677  						}
   678  					}
   679  				})
   680  			}
   681  		})
   682  	}
   683  }
   684  
   685  // Test the we can retrieve the application exit status from the container.
   686  func TestAppExitStatus(t *testing.T) {
   687  	doAppExitStatus(t, false)
   688  }
   689  
   690  // This is TestAppExitStatus for VFSv2.
   691  func TestAppExitStatusVFS2(t *testing.T) {
   692  	doAppExitStatus(t, true)
   693  }
   694  
   695  func doAppExitStatus(t *testing.T, vfs2 bool) {
   696  	// First container will succeed.
   697  	succSpec := testutil.NewSpecWithArgs("true")
   698  	conf := testutil.TestConfig(t)
   699  	conf.VFS2 = vfs2
   700  	_, bundleDir, cleanup, err := testutil.SetupContainer(succSpec, conf)
   701  	if err != nil {
   702  		t.Fatalf("error setting up container: %v", err)
   703  	}
   704  	defer cleanup()
   705  
   706  	args := Args{
   707  		ID:        testutil.RandomContainerID(),
   708  		Spec:      succSpec,
   709  		BundleDir: bundleDir,
   710  		Attached:  true,
   711  	}
   712  	ws, err := Run(conf, args)
   713  	if err != nil {
   714  		t.Fatalf("error running container: %v", err)
   715  	}
   716  	if ws.ExitStatus() != 0 {
   717  		t.Errorf("got exit status %v want %v", ws.ExitStatus(), 0)
   718  	}
   719  
   720  	// Second container exits with non-zero status.
   721  	wantStatus := 123
   722  	errSpec := testutil.NewSpecWithArgs("bash", "-c", fmt.Sprintf("exit %d", wantStatus))
   723  
   724  	_, bundleDir2, cleanup2, err := testutil.SetupContainer(errSpec, conf)
   725  	if err != nil {
   726  		t.Fatalf("error setting up container: %v", err)
   727  	}
   728  	defer cleanup2()
   729  
   730  	args2 := Args{
   731  		ID:        testutil.RandomContainerID(),
   732  		Spec:      errSpec,
   733  		BundleDir: bundleDir2,
   734  		Attached:  true,
   735  	}
   736  	ws, err = Run(conf, args2)
   737  	if err != nil {
   738  		t.Fatalf("error running container: %v", err)
   739  	}
   740  	if ws.ExitStatus() != wantStatus {
   741  		t.Errorf("got exit status %v want %v", ws.ExitStatus(), wantStatus)
   742  	}
   743  }
   744  
   745  // TestExec verifies that a container can exec a new program.
   746  func TestExec(t *testing.T) {
   747  	for name, conf := range configs(t, all...) {
   748  		t.Run(name, func(t *testing.T) {
   749  			dir, err := ioutil.TempDir(testutil.TmpDir(), "exec-test")
   750  			if err != nil {
   751  				t.Fatalf("error creating temporary directory: %v", err)
   752  			}
   753  			// Note that some shells may exec the final command in a sequence as
   754  			// an optimization. We avoid this here by adding the exit 0.
   755  			cmd := fmt.Sprintf("ln -s /bin/true %q/symlink && sleep 100 && exit 0", dir)
   756  			spec := testutil.NewSpecWithArgs("sh", "-c", cmd)
   757  
   758  			_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
   759  			if err != nil {
   760  				t.Fatalf("error setting up container: %v", err)
   761  			}
   762  			defer cleanup()
   763  
   764  			// Create and start the container.
   765  			args := Args{
   766  				ID:        testutil.RandomContainerID(),
   767  				Spec:      spec,
   768  				BundleDir: bundleDir,
   769  			}
   770  			cont, err := New(conf, args)
   771  			if err != nil {
   772  				t.Fatalf("error creating container: %v", err)
   773  			}
   774  			defer cont.Destroy()
   775  			if err := cont.Start(conf); err != nil {
   776  				t.Fatalf("error starting container: %v", err)
   777  			}
   778  
   779  			// Wait until sleep is running to ensure the symlink was created.
   780  			expectedPL := []*control.Process{
   781  				newProcessBuilder().Cmd("sh").Process(),
   782  				newProcessBuilder().Cmd("sleep").Process(),
   783  			}
   784  			if err := waitForProcessList(cont, expectedPL); err != nil {
   785  				t.Fatalf("waitForProcessList: %v", err)
   786  			}
   787  
   788  			for _, tc := range []struct {
   789  				name string
   790  				args control.ExecArgs
   791  			}{
   792  				{
   793  					name: "complete",
   794  					args: control.ExecArgs{
   795  						Filename: "/bin/true",
   796  						Argv:     []string{"/bin/true"},
   797  					},
   798  				},
   799  				{
   800  					name: "filename",
   801  					args: control.ExecArgs{
   802  						Filename: "/bin/true",
   803  					},
   804  				},
   805  				{
   806  					name: "argv",
   807  					args: control.ExecArgs{
   808  						Argv: []string{"/bin/true"},
   809  					},
   810  				},
   811  				{
   812  					name: "filename resolution",
   813  					args: control.ExecArgs{
   814  						Filename: "true",
   815  						Envv:     []string{"PATH=/bin"},
   816  					},
   817  				},
   818  				{
   819  					name: "argv resolution",
   820  					args: control.ExecArgs{
   821  						Argv: []string{"true"},
   822  						Envv: []string{"PATH=/bin"},
   823  					},
   824  				},
   825  				{
   826  					name: "argv symlink",
   827  					args: control.ExecArgs{
   828  						Argv: []string{filepath.Join(dir, "symlink")},
   829  					},
   830  				},
   831  				{
   832  					name: "working dir",
   833  					args: control.ExecArgs{
   834  						Argv:             []string{"/bin/sh", "-c", `if [[ "${PWD}" != "/tmp" ]]; then exit 1; fi`},
   835  						WorkingDirectory: "/tmp",
   836  					},
   837  				},
   838  				{
   839  					name: "user",
   840  					args: control.ExecArgs{
   841  						Argv: []string{"/bin/sh", "-c", `if [[ "$(id -u)" != "343" ]]; then exit 1; fi`},
   842  						KUID: 343,
   843  					},
   844  				},
   845  				{
   846  					name: "group",
   847  					args: control.ExecArgs{
   848  						Argv: []string{"/bin/sh", "-c", `if [[ "$(id -g)" != "343" ]]; then exit 1; fi`},
   849  						KGID: 343,
   850  					},
   851  				},
   852  				{
   853  					name: "env",
   854  					args: control.ExecArgs{
   855  						Argv: []string{"/bin/sh", "-c", `if [[ "${FOO}" != "123" ]]; then exit 1; fi`},
   856  						Envv: []string{"FOO=123"},
   857  					},
   858  				},
   859  			} {
   860  				t.Run(tc.name, func(t *testing.T) {
   861  					// t.Parallel()
   862  					if ws, err := cont.executeSync(&tc.args); err != nil {
   863  						t.Fatalf("executeAsync(%+v): %v", tc.args, err)
   864  					} else if ws != 0 {
   865  						t.Fatalf("executeAsync(%+v) failed with exit: %v", tc.args, ws)
   866  					}
   867  				})
   868  			}
   869  
   870  			// Test for exec failure with an non-existent file.
   871  			t.Run("nonexist", func(t *testing.T) {
   872  				// b/179114837 found by Syzkaller that causes nil pointer panic when
   873  				// trying to dec-ref an unix socket FD.
   874  				fds, err := unix.Socketpair(unix.AF_UNIX, unix.SOCK_STREAM, 0)
   875  				if err != nil {
   876  					t.Fatal(err)
   877  				}
   878  				defer unix.Close(fds[0])
   879  
   880  				_, err = cont.executeSync(&control.ExecArgs{
   881  					Argv: []string{"/nonexist"},
   882  					FilePayload: urpc.FilePayload{
   883  						Files: []*os.File{os.NewFile(uintptr(fds[1]), "sock")},
   884  					},
   885  				})
   886  				want := "failed to load /nonexist"
   887  				if err == nil || !strings.Contains(err.Error(), want) {
   888  					t.Errorf("executeSync: want err containing %q; got err = %q", want, err)
   889  				}
   890  			})
   891  		})
   892  	}
   893  }
   894  
   895  // TestExecProcList verifies that a container can exec a new program and it
   896  // shows correcly in the process list.
   897  func TestExecProcList(t *testing.T) {
   898  	for name, conf := range configs(t, all...) {
   899  		t.Run(name, func(t *testing.T) {
   900  			const uid = 343
   901  			spec := testutil.NewSpecWithArgs("sleep", "100")
   902  
   903  			_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
   904  			if err != nil {
   905  				t.Fatalf("error setting up container: %v", err)
   906  			}
   907  			defer cleanup()
   908  
   909  			// Create and start the container.
   910  			args := Args{
   911  				ID:        testutil.RandomContainerID(),
   912  				Spec:      spec,
   913  				BundleDir: bundleDir,
   914  			}
   915  			cont, err := New(conf, args)
   916  			if err != nil {
   917  				t.Fatalf("error creating container: %v", err)
   918  			}
   919  			defer cont.Destroy()
   920  			if err := cont.Start(conf); err != nil {
   921  				t.Fatalf("error starting container: %v", err)
   922  			}
   923  
   924  			execArgs := &control.ExecArgs{
   925  				Filename:         "/bin/sleep",
   926  				Argv:             []string{"/bin/sleep", "5"},
   927  				WorkingDirectory: "/",
   928  				KUID:             uid,
   929  			}
   930  
   931  			// Verify that "sleep 100" and "sleep 5" are running after exec. First,
   932  			// start running exec (which blocks).
   933  			ch := make(chan error)
   934  			go func() {
   935  				exitStatus, err := cont.executeSync(execArgs)
   936  				if err != nil {
   937  					ch <- err
   938  				} else if exitStatus != 0 {
   939  					ch <- fmt.Errorf("failed with exit status: %v", exitStatus)
   940  				} else {
   941  					ch <- nil
   942  				}
   943  			}()
   944  
   945  			// expectedPL lists the expected process state of the container.
   946  			expectedPL := []*control.Process{
   947  				newProcessBuilder().PID(1).PPID(0).Cmd("sleep").UID(0).Process(),
   948  				newProcessBuilder().PID(2).PPID(0).Cmd("sleep").UID(uid).Process(),
   949  			}
   950  			if err := waitForProcessList(cont, expectedPL); err != nil {
   951  				t.Fatalf("error waiting for processes: %v", err)
   952  			}
   953  
   954  			// Ensure that exec finished without error.
   955  			select {
   956  			case <-time.After(10 * time.Second):
   957  				t.Fatalf("container timed out waiting for exec to finish.")
   958  			case err := <-ch:
   959  				if err != nil {
   960  					t.Errorf("container failed to exec %v: %v", args, err)
   961  				}
   962  			}
   963  		})
   964  	}
   965  }
   966  
   967  // TestKillPid verifies that we can signal individual exec'd processes.
   968  func TestKillPid(t *testing.T) {
   969  	for name, conf := range configs(t, all...) {
   970  		t.Run(name, func(t *testing.T) {
   971  			app, err := testutil.FindFile("test/cmd/test_app/test_app")
   972  			if err != nil {
   973  				t.Fatal("error finding test_app:", err)
   974  			}
   975  
   976  			const nProcs = 4
   977  			spec := testutil.NewSpecWithArgs(app, "task-tree", "--depth", strconv.Itoa(nProcs-1), "--width=1", "--pause=true")
   978  			_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
   979  			if err != nil {
   980  				t.Fatalf("error setting up container: %v", err)
   981  			}
   982  			defer cleanup()
   983  
   984  			// Create and start the container.
   985  			args := Args{
   986  				ID:        testutil.RandomContainerID(),
   987  				Spec:      spec,
   988  				BundleDir: bundleDir,
   989  			}
   990  			cont, err := New(conf, args)
   991  			if err != nil {
   992  				t.Fatalf("error creating container: %v", err)
   993  			}
   994  			defer cont.Destroy()
   995  			if err := cont.Start(conf); err != nil {
   996  				t.Fatalf("error starting container: %v", err)
   997  			}
   998  
   999  			// Verify that all processes are running.
  1000  			if err := waitForProcessCount(cont, nProcs); err != nil {
  1001  				t.Fatalf("timed out waiting for processes to start: %v", err)
  1002  			}
  1003  
  1004  			// Kill the child process with the largest PID.
  1005  			procs, err := cont.Processes()
  1006  			if err != nil {
  1007  				t.Fatalf("failed to get process list: %v", err)
  1008  			}
  1009  			var pid int32
  1010  			for _, p := range procs {
  1011  				if pid < int32(p.PID) {
  1012  					pid = int32(p.PID)
  1013  				}
  1014  			}
  1015  			if err := cont.SignalProcess(unix.SIGKILL, pid); err != nil {
  1016  				t.Fatalf("failed to signal process %d: %v", pid, err)
  1017  			}
  1018  
  1019  			// Verify that one process is gone.
  1020  			if err := waitForProcessCount(cont, nProcs-1); err != nil {
  1021  				t.Fatalf("error waiting for processes: %v", err)
  1022  			}
  1023  
  1024  			procs, err = cont.Processes()
  1025  			if err != nil {
  1026  				t.Fatalf("failed to get process list: %v", err)
  1027  			}
  1028  			for _, p := range procs {
  1029  				if pid == int32(p.PID) {
  1030  					t.Fatalf("pid %d is still alive, which should be killed", pid)
  1031  				}
  1032  			}
  1033  		})
  1034  	}
  1035  }
  1036  
  1037  // TestCheckpointRestore creates a container that continuously writes successive
  1038  // integers to a file. To test checkpoint and restore functionality, the
  1039  // container is checkpointed and the last number printed to the file is
  1040  // recorded. Then, it is restored in two new containers and the first number
  1041  // printed from these containers is checked. Both should be the next consecutive
  1042  // number after the last number from the checkpointed container.
  1043  func TestCheckpointRestore(t *testing.T) {
  1044  	// Skip overlay because test requires writing to host file.
  1045  	for name, conf := range configs(t, noOverlay...) {
  1046  		t.Run(name, func(t *testing.T) {
  1047  			dir, err := ioutil.TempDir(testutil.TmpDir(), "checkpoint-test")
  1048  			if err != nil {
  1049  				t.Fatalf("ioutil.TempDir failed: %v", err)
  1050  			}
  1051  			defer os.RemoveAll(dir)
  1052  			if err := os.Chmod(dir, 0777); err != nil {
  1053  				t.Fatalf("error chmoding file: %q, %v", dir, err)
  1054  			}
  1055  
  1056  			outputPath := filepath.Join(dir, "output")
  1057  			outputFile, err := createWriteableOutputFile(outputPath)
  1058  			if err != nil {
  1059  				t.Fatalf("error creating output file: %v", err)
  1060  			}
  1061  			defer outputFile.Close()
  1062  
  1063  			script := fmt.Sprintf("for ((i=0; ;i++)); do echo $i >> %q; sleep 1; done", outputPath)
  1064  			spec := testutil.NewSpecWithArgs("bash", "-c", script)
  1065  			_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  1066  			if err != nil {
  1067  				t.Fatalf("error setting up container: %v", err)
  1068  			}
  1069  			defer cleanup()
  1070  
  1071  			// Create and start the container.
  1072  			args := Args{
  1073  				ID:        testutil.RandomContainerID(),
  1074  				Spec:      spec,
  1075  				BundleDir: bundleDir,
  1076  			}
  1077  			cont, err := New(conf, args)
  1078  			if err != nil {
  1079  				t.Fatalf("error creating container: %v", err)
  1080  			}
  1081  			defer cont.Destroy()
  1082  			if err := cont.Start(conf); err != nil {
  1083  				t.Fatalf("error starting container: %v", err)
  1084  			}
  1085  
  1086  			// Set the image path, which is where the checkpoint image will be saved.
  1087  			imagePath := filepath.Join(dir, "test-image-file")
  1088  
  1089  			// Create the image file and open for writing.
  1090  			file, err := os.OpenFile(imagePath, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0644)
  1091  			if err != nil {
  1092  				t.Fatalf("error opening new file at imagePath: %v", err)
  1093  			}
  1094  			defer file.Close()
  1095  
  1096  			// Wait until application has ran.
  1097  			if err := waitForFileNotEmpty(outputFile); err != nil {
  1098  				t.Fatalf("Failed to wait for output file: %v", err)
  1099  			}
  1100  
  1101  			// Checkpoint running container; save state into new file.
  1102  			if err := cont.Checkpoint(file); err != nil {
  1103  				t.Fatalf("error checkpointing container to empty file: %v", err)
  1104  			}
  1105  			defer os.RemoveAll(imagePath)
  1106  
  1107  			lastNum, err := readOutputNum(outputPath, -1)
  1108  			if err != nil {
  1109  				t.Fatalf("error with outputFile: %v", err)
  1110  			}
  1111  
  1112  			// Delete and recreate file before restoring.
  1113  			if err := os.Remove(outputPath); err != nil {
  1114  				t.Fatalf("error removing file")
  1115  			}
  1116  			outputFile2, err := createWriteableOutputFile(outputPath)
  1117  			if err != nil {
  1118  				t.Fatalf("error creating output file: %v", err)
  1119  			}
  1120  			defer outputFile2.Close()
  1121  
  1122  			// Restore into a new container.
  1123  			args2 := Args{
  1124  				ID:        testutil.RandomContainerID(),
  1125  				Spec:      spec,
  1126  				BundleDir: bundleDir,
  1127  			}
  1128  			cont2, err := New(conf, args2)
  1129  			if err != nil {
  1130  				t.Fatalf("error creating container: %v", err)
  1131  			}
  1132  			defer cont2.Destroy()
  1133  
  1134  			if err := cont2.Restore(spec, conf, imagePath); err != nil {
  1135  				t.Fatalf("error restoring container: %v", err)
  1136  			}
  1137  
  1138  			// Wait until application has ran.
  1139  			if err := waitForFileNotEmpty(outputFile2); err != nil {
  1140  				t.Fatalf("Failed to wait for output file: %v", err)
  1141  			}
  1142  
  1143  			firstNum, err := readOutputNum(outputPath, 0)
  1144  			if err != nil {
  1145  				t.Fatalf("error with outputFile: %v", err)
  1146  			}
  1147  
  1148  			// Check that lastNum is one less than firstNum and that the container picks
  1149  			// up from where it left off.
  1150  			if lastNum+1 != firstNum {
  1151  				t.Errorf("error numbers not in order, previous: %d, next: %d", lastNum, firstNum)
  1152  			}
  1153  			cont2.Destroy()
  1154  
  1155  			// Restore into another container!
  1156  			// Delete and recreate file before restoring.
  1157  			if err := os.Remove(outputPath); err != nil {
  1158  				t.Fatalf("error removing file")
  1159  			}
  1160  			outputFile3, err := createWriteableOutputFile(outputPath)
  1161  			if err != nil {
  1162  				t.Fatalf("error creating output file: %v", err)
  1163  			}
  1164  			defer outputFile3.Close()
  1165  
  1166  			// Restore into a new container.
  1167  			args3 := Args{
  1168  				ID:        testutil.RandomContainerID(),
  1169  				Spec:      spec,
  1170  				BundleDir: bundleDir,
  1171  			}
  1172  			cont3, err := New(conf, args3)
  1173  			if err != nil {
  1174  				t.Fatalf("error creating container: %v", err)
  1175  			}
  1176  			defer cont3.Destroy()
  1177  
  1178  			if err := cont3.Restore(spec, conf, imagePath); err != nil {
  1179  				t.Fatalf("error restoring container: %v", err)
  1180  			}
  1181  
  1182  			// Wait until application has ran.
  1183  			if err := waitForFileNotEmpty(outputFile3); err != nil {
  1184  				t.Fatalf("Failed to wait for output file: %v", err)
  1185  			}
  1186  
  1187  			firstNum2, err := readOutputNum(outputPath, 0)
  1188  			if err != nil {
  1189  				t.Fatalf("error with outputFile: %v", err)
  1190  			}
  1191  
  1192  			// Check that lastNum is one less than firstNum and that the container picks
  1193  			// up from where it left off.
  1194  			if lastNum+1 != firstNum2 {
  1195  				t.Errorf("error numbers not in order, previous: %d, next: %d", lastNum, firstNum2)
  1196  			}
  1197  			cont3.Destroy()
  1198  		})
  1199  	}
  1200  }
  1201  
  1202  // TestUnixDomainSockets checks that Checkpoint/Restore works in cases
  1203  // with filesystem Unix Domain Socket use.
  1204  func TestUnixDomainSockets(t *testing.T) {
  1205  	// Skip overlay because test requires writing to host file.
  1206  	for name, conf := range configs(t, noOverlay...) {
  1207  		t.Run(name, func(t *testing.T) {
  1208  			// UDS path is limited to 108 chars for compatibility with older systems.
  1209  			// Use '/tmp' (instead of testutil.TmpDir) to ensure the size limit is
  1210  			// not exceeded. Assumes '/tmp' exists in the system.
  1211  			dir, err := ioutil.TempDir("/tmp", "uds-test")
  1212  			if err != nil {
  1213  				t.Fatalf("ioutil.TempDir failed: %v", err)
  1214  			}
  1215  			defer os.RemoveAll(dir)
  1216  
  1217  			outputPath := filepath.Join(dir, "uds_output")
  1218  			outputFile, err := os.OpenFile(outputPath, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666)
  1219  			if err != nil {
  1220  				t.Fatalf("error creating output file: %v", err)
  1221  			}
  1222  			defer outputFile.Close()
  1223  
  1224  			app, err := testutil.FindFile("test/cmd/test_app/test_app")
  1225  			if err != nil {
  1226  				t.Fatal("error finding test_app:", err)
  1227  			}
  1228  
  1229  			socketPath := filepath.Join(dir, "uds_socket")
  1230  			defer os.Remove(socketPath)
  1231  
  1232  			spec := testutil.NewSpecWithArgs(app, "uds", "--file", outputPath, "--socket", socketPath)
  1233  			spec.Process.User = specs.User{
  1234  				UID: uint32(os.Getuid()),
  1235  				GID: uint32(os.Getgid()),
  1236  			}
  1237  			spec.Mounts = []specs.Mount{{
  1238  				Type:        "bind",
  1239  				Destination: dir,
  1240  				Source:      dir,
  1241  			}}
  1242  
  1243  			_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  1244  			if err != nil {
  1245  				t.Fatalf("error setting up container: %v", err)
  1246  			}
  1247  			defer cleanup()
  1248  
  1249  			// Create and start the container.
  1250  			args := Args{
  1251  				ID:        testutil.RandomContainerID(),
  1252  				Spec:      spec,
  1253  				BundleDir: bundleDir,
  1254  			}
  1255  			cont, err := New(conf, args)
  1256  			if err != nil {
  1257  				t.Fatalf("error creating container: %v", err)
  1258  			}
  1259  			defer cont.Destroy()
  1260  			if err := cont.Start(conf); err != nil {
  1261  				t.Fatalf("error starting container: %v", err)
  1262  			}
  1263  
  1264  			// Set the image path, the location where the checkpoint image will be saved.
  1265  			imagePath := filepath.Join(dir, "test-image-file")
  1266  
  1267  			// Create the image file and open for writing.
  1268  			file, err := os.OpenFile(imagePath, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0644)
  1269  			if err != nil {
  1270  				t.Fatalf("error opening new file at imagePath: %v", err)
  1271  			}
  1272  			defer file.Close()
  1273  			defer os.RemoveAll(imagePath)
  1274  
  1275  			// Wait until application has ran.
  1276  			if err := waitForFileNotEmpty(outputFile); err != nil {
  1277  				t.Fatalf("Failed to wait for output file: %v", err)
  1278  			}
  1279  
  1280  			// Checkpoint running container; save state into new file.
  1281  			if err := cont.Checkpoint(file); err != nil {
  1282  				t.Fatalf("error checkpointing container to empty file: %v", err)
  1283  			}
  1284  
  1285  			// Read last number outputted before checkpoint.
  1286  			lastNum, err := readOutputNum(outputPath, -1)
  1287  			if err != nil {
  1288  				t.Fatalf("error with outputFile: %v", err)
  1289  			}
  1290  
  1291  			// Delete and recreate file before restoring.
  1292  			if err := os.Remove(outputPath); err != nil {
  1293  				t.Fatalf("error removing file")
  1294  			}
  1295  			outputFile2, err := os.OpenFile(outputPath, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666)
  1296  			if err != nil {
  1297  				t.Fatalf("error creating output file: %v", err)
  1298  			}
  1299  			defer outputFile2.Close()
  1300  
  1301  			// Restore into a new container.
  1302  			argsRestore := Args{
  1303  				ID:        testutil.RandomContainerID(),
  1304  				Spec:      spec,
  1305  				BundleDir: bundleDir,
  1306  			}
  1307  			contRestore, err := New(conf, argsRestore)
  1308  			if err != nil {
  1309  				t.Fatalf("error creating container: %v", err)
  1310  			}
  1311  			defer contRestore.Destroy()
  1312  
  1313  			if err := contRestore.Restore(spec, conf, imagePath); err != nil {
  1314  				t.Fatalf("error restoring container: %v", err)
  1315  			}
  1316  
  1317  			// Wait until application has ran.
  1318  			if err := waitForFileNotEmpty(outputFile2); err != nil {
  1319  				t.Fatalf("Failed to wait for output file: %v", err)
  1320  			}
  1321  
  1322  			// Read first number outputted after restore.
  1323  			firstNum, err := readOutputNum(outputPath, 0)
  1324  			if err != nil {
  1325  				t.Fatalf("error with outputFile: %v", err)
  1326  			}
  1327  
  1328  			// Check that lastNum is one less than firstNum.
  1329  			if lastNum+1 != firstNum {
  1330  				t.Errorf("error numbers not consecutive, previous: %d, next: %d", lastNum, firstNum)
  1331  			}
  1332  			contRestore.Destroy()
  1333  		})
  1334  	}
  1335  }
  1336  
  1337  // TestPauseResume tests that we can successfully pause and resume a container.
  1338  // The container will keep touching a file to indicate it's running. The test
  1339  // pauses the container, removes the file, and checks that it doesn't get
  1340  // recreated. Then it resumes the container, verify that the file gets created
  1341  // again.
  1342  func TestPauseResume(t *testing.T) {
  1343  	for name, conf := range configs(t, noOverlay...) {
  1344  		t.Run(name, func(t *testing.T) {
  1345  			tmpDir, err := ioutil.TempDir(testutil.TmpDir(), "lock")
  1346  			if err != nil {
  1347  				t.Fatalf("error creating temp dir: %v", err)
  1348  			}
  1349  			defer os.RemoveAll(tmpDir)
  1350  
  1351  			running := path.Join(tmpDir, "running")
  1352  			script := fmt.Sprintf("while [[ true ]]; do touch %q; sleep 0.1; done", running)
  1353  			spec := testutil.NewSpecWithArgs("/bin/bash", "-c", script)
  1354  
  1355  			_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  1356  			if err != nil {
  1357  				t.Fatalf("error setting up container: %v", err)
  1358  			}
  1359  			defer cleanup()
  1360  
  1361  			// Create and start the container.
  1362  			args := Args{
  1363  				ID:        testutil.RandomContainerID(),
  1364  				Spec:      spec,
  1365  				BundleDir: bundleDir,
  1366  			}
  1367  			cont, err := New(conf, args)
  1368  			if err != nil {
  1369  				t.Fatalf("error creating container: %v", err)
  1370  			}
  1371  			defer cont.Destroy()
  1372  			if err := cont.Start(conf); err != nil {
  1373  				t.Fatalf("error starting container: %v", err)
  1374  			}
  1375  
  1376  			// Wait until container starts running, observed by the existence of running
  1377  			// file.
  1378  			if err := waitForFileExist(running); err != nil {
  1379  				t.Errorf("error waiting for container to start: %v", err)
  1380  			}
  1381  
  1382  			// Pause the running container.
  1383  			if err := cont.Pause(); err != nil {
  1384  				t.Errorf("error pausing container: %v", err)
  1385  			}
  1386  			if got, want := cont.Status, Paused; got != want {
  1387  				t.Errorf("container status got %v, want %v", got, want)
  1388  			}
  1389  
  1390  			if err := os.Remove(running); err != nil {
  1391  				t.Fatalf("os.Remove(%q) failed: %v", running, err)
  1392  			}
  1393  			// Script touches the file every 100ms. Give a bit a time for it to run to
  1394  			// catch the case that pause didn't work.
  1395  			time.Sleep(200 * time.Millisecond)
  1396  			if _, err := os.Stat(running); !os.IsNotExist(err) {
  1397  				t.Fatalf("container did not pause: file exist check: %v", err)
  1398  			}
  1399  
  1400  			// Resume the running container.
  1401  			if err := cont.Resume(); err != nil {
  1402  				t.Errorf("error pausing container: %v", err)
  1403  			}
  1404  			if got, want := cont.Status, Running; got != want {
  1405  				t.Errorf("container status got %v, want %v", got, want)
  1406  			}
  1407  
  1408  			// Verify that the file is once again created by container.
  1409  			if err := waitForFileExist(running); err != nil {
  1410  				t.Fatalf("error resuming container: file exist check: %v", err)
  1411  			}
  1412  		})
  1413  	}
  1414  }
  1415  
  1416  // TestPauseResumeStatus makes sure that the statuses are set correctly
  1417  // with calls to pause and resume and that pausing and resuming only
  1418  // occurs given the correct state.
  1419  func TestPauseResumeStatus(t *testing.T) {
  1420  	spec := testutil.NewSpecWithArgs("sleep", "20")
  1421  	conf := testutil.TestConfig(t)
  1422  	_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  1423  	if err != nil {
  1424  		t.Fatalf("error setting up container: %v", err)
  1425  	}
  1426  	defer cleanup()
  1427  
  1428  	// Create and start the container.
  1429  	args := Args{
  1430  		ID:        testutil.RandomContainerID(),
  1431  		Spec:      spec,
  1432  		BundleDir: bundleDir,
  1433  	}
  1434  	cont, err := New(conf, args)
  1435  	if err != nil {
  1436  		t.Fatalf("error creating container: %v", err)
  1437  	}
  1438  	defer cont.Destroy()
  1439  	if err := cont.Start(conf); err != nil {
  1440  		t.Fatalf("error starting container: %v", err)
  1441  	}
  1442  
  1443  	// Pause the running container.
  1444  	if err := cont.Pause(); err != nil {
  1445  		t.Errorf("error pausing container: %v", err)
  1446  	}
  1447  	if got, want := cont.Status, Paused; got != want {
  1448  		t.Errorf("container status got %v, want %v", got, want)
  1449  	}
  1450  
  1451  	// Try to Pause again. Should cause error.
  1452  	if err := cont.Pause(); err == nil {
  1453  		t.Errorf("error pausing container that was already paused: %v", err)
  1454  	}
  1455  	if got, want := cont.Status, Paused; got != want {
  1456  		t.Errorf("container status got %v, want %v", got, want)
  1457  	}
  1458  
  1459  	// Resume the running container.
  1460  	if err := cont.Resume(); err != nil {
  1461  		t.Errorf("error resuming container: %v", err)
  1462  	}
  1463  	if got, want := cont.Status, Running; got != want {
  1464  		t.Errorf("container status got %v, want %v", got, want)
  1465  	}
  1466  
  1467  	// Try to resume again. Should cause error.
  1468  	if err := cont.Resume(); err == nil {
  1469  		t.Errorf("error resuming container already running: %v", err)
  1470  	}
  1471  	if got, want := cont.Status, Running; got != want {
  1472  		t.Errorf("container status got %v, want %v", got, want)
  1473  	}
  1474  }
  1475  
  1476  // TestCapabilities verifies that:
  1477  // - Running exec as non-root UID and GID will result in an error (because the
  1478  //   executable file can't be read).
  1479  // - Running exec as non-root with CAP_DAC_OVERRIDE succeeds because it skips
  1480  //   this check.
  1481  func TestCapabilities(t *testing.T) {
  1482  	// Pick uid/gid different than ours.
  1483  	uid := auth.KUID(os.Getuid() + 1)
  1484  	gid := auth.KGID(os.Getgid() + 1)
  1485  
  1486  	for name, conf := range configs(t, all...) {
  1487  		t.Run(name, func(t *testing.T) {
  1488  			spec := testutil.NewSpecWithArgs("sleep", "100")
  1489  			rootDir, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  1490  			if err != nil {
  1491  				t.Fatalf("error setting up container: %v", err)
  1492  			}
  1493  			defer cleanup()
  1494  
  1495  			// Create and start the container.
  1496  			args := Args{
  1497  				ID:        testutil.RandomContainerID(),
  1498  				Spec:      spec,
  1499  				BundleDir: bundleDir,
  1500  			}
  1501  			cont, err := New(conf, args)
  1502  			if err != nil {
  1503  				t.Fatalf("error creating container: %v", err)
  1504  			}
  1505  			defer cont.Destroy()
  1506  			if err := cont.Start(conf); err != nil {
  1507  				t.Fatalf("error starting container: %v", err)
  1508  			}
  1509  
  1510  			// expectedPL lists the expected process state of the container.
  1511  			expectedPL := []*control.Process{
  1512  				newProcessBuilder().Cmd("sleep").Process(),
  1513  			}
  1514  			if err := waitForProcessList(cont, expectedPL); err != nil {
  1515  				t.Fatalf("Failed to wait for sleep to start, err: %v", err)
  1516  			}
  1517  
  1518  			// Create an executable that can't be run with the specified UID:GID.
  1519  			// This shouldn't be callable within the container until we add the
  1520  			// CAP_DAC_OVERRIDE capability to skip the access check.
  1521  			exePath := filepath.Join(rootDir, "exe")
  1522  			if err := ioutil.WriteFile(exePath, []byte("#!/bin/sh\necho hello"), 0770); err != nil {
  1523  				t.Fatalf("couldn't create executable: %v", err)
  1524  			}
  1525  			defer os.Remove(exePath)
  1526  
  1527  			// Need to traverse the intermediate directory.
  1528  			os.Chmod(rootDir, 0755)
  1529  
  1530  			execArgs := &control.ExecArgs{
  1531  				Filename:         exePath,
  1532  				Argv:             []string{exePath},
  1533  				WorkingDirectory: "/",
  1534  				KUID:             uid,
  1535  				KGID:             gid,
  1536  				Capabilities:     &auth.TaskCapabilities{},
  1537  			}
  1538  
  1539  			// "exe" should fail because we don't have the necessary permissions.
  1540  			if _, err := cont.executeSync(execArgs); err == nil {
  1541  				t.Fatalf("container executed without error, but an error was expected")
  1542  			}
  1543  
  1544  			// Now we run with the capability enabled and should succeed.
  1545  			execArgs.Capabilities = &auth.TaskCapabilities{
  1546  				EffectiveCaps: auth.CapabilitySetOf(linux.CAP_DAC_OVERRIDE),
  1547  			}
  1548  			// "exe" should not fail this time.
  1549  			if _, err := cont.executeSync(execArgs); err != nil {
  1550  				t.Fatalf("container failed to exec %v: %v", args, err)
  1551  			}
  1552  		})
  1553  	}
  1554  }
  1555  
  1556  // TestRunNonRoot checks that sandbox can be configured when running as
  1557  // non-privileged user.
  1558  func TestRunNonRoot(t *testing.T) {
  1559  	for name, conf := range configs(t, noOverlay...) {
  1560  		t.Run(name, func(t *testing.T) {
  1561  			spec := testutil.NewSpecWithArgs("/bin/true")
  1562  
  1563  			// Set a random user/group with no access to "blocked" dir.
  1564  			spec.Process.User.UID = 343
  1565  			spec.Process.User.GID = 2401
  1566  			spec.Process.Capabilities = nil
  1567  
  1568  			// User running inside container can't list '$TMP/blocked' and would fail to
  1569  			// mount it.
  1570  			dir, err := ioutil.TempDir(testutil.TmpDir(), "blocked")
  1571  			if err != nil {
  1572  				t.Fatalf("ioutil.TempDir() failed: %v", err)
  1573  			}
  1574  			if err := os.Chmod(dir, 0700); err != nil {
  1575  				t.Fatalf("os.MkDir(%q) failed: %v", dir, err)
  1576  			}
  1577  			dir = path.Join(dir, "test")
  1578  			if err := os.Mkdir(dir, 0755); err != nil {
  1579  				t.Fatalf("os.MkDir(%q) failed: %v", dir, err)
  1580  			}
  1581  
  1582  			src, err := ioutil.TempDir(testutil.TmpDir(), "src")
  1583  			if err != nil {
  1584  				t.Fatalf("ioutil.TempDir() failed: %v", err)
  1585  			}
  1586  
  1587  			spec.Mounts = append(spec.Mounts, specs.Mount{
  1588  				Destination: dir,
  1589  				Source:      src,
  1590  				Type:        "bind",
  1591  			})
  1592  
  1593  			if err := run(spec, conf); err != nil {
  1594  				t.Fatalf("error running sandbox: %v", err)
  1595  			}
  1596  		})
  1597  	}
  1598  }
  1599  
  1600  // TestMountNewDir checks that runsc will create destination directory if it
  1601  // doesn't exit.
  1602  func TestMountNewDir(t *testing.T) {
  1603  	for name, conf := range configs(t, all...) {
  1604  		t.Run(name, func(t *testing.T) {
  1605  			root, err := ioutil.TempDir(testutil.TmpDir(), "root")
  1606  			if err != nil {
  1607  				t.Fatal("ioutil.TempDir() failed:", err)
  1608  			}
  1609  
  1610  			srcDir := path.Join(root, "src", "dir", "anotherdir")
  1611  			if err := os.MkdirAll(srcDir, 0755); err != nil {
  1612  				t.Fatalf("os.MkDir(%q) failed: %v", srcDir, err)
  1613  			}
  1614  
  1615  			mountDir := path.Join(root, "dir", "anotherdir")
  1616  
  1617  			spec := testutil.NewSpecWithArgs("/bin/ls", mountDir)
  1618  			spec.Mounts = append(spec.Mounts, specs.Mount{
  1619  				Destination: mountDir,
  1620  				Source:      srcDir,
  1621  				Type:        "bind",
  1622  			})
  1623  			// Extra points for creating the mount with a readonly root.
  1624  			spec.Root.Readonly = true
  1625  
  1626  			if err := run(spec, conf); err != nil {
  1627  				t.Fatalf("error running sandbox: %v", err)
  1628  			}
  1629  		})
  1630  	}
  1631  }
  1632  
  1633  func TestReadonlyRoot(t *testing.T) {
  1634  	for name, conf := range configs(t, all...) {
  1635  		t.Run(name, func(t *testing.T) {
  1636  			spec := testutil.NewSpecWithArgs("sleep", "100")
  1637  			spec.Root.Readonly = true
  1638  
  1639  			_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  1640  			if err != nil {
  1641  				t.Fatalf("error setting up container: %v", err)
  1642  			}
  1643  			defer cleanup()
  1644  
  1645  			args := Args{
  1646  				ID:        testutil.RandomContainerID(),
  1647  				Spec:      spec,
  1648  				BundleDir: bundleDir,
  1649  			}
  1650  			c, err := New(conf, args)
  1651  			if err != nil {
  1652  				t.Fatalf("error creating container: %v", err)
  1653  			}
  1654  			defer c.Destroy()
  1655  			if err := c.Start(conf); err != nil {
  1656  				t.Fatalf("error starting container: %v", err)
  1657  			}
  1658  
  1659  			// Read mounts to check that root is readonly.
  1660  			out, err := executeCombinedOutput(c, "/bin/sh", "-c", "mount | grep ' / ' | grep -o -e '(.*)'")
  1661  			if err != nil {
  1662  				t.Fatalf("exec failed: %v", err)
  1663  			}
  1664  			t.Logf("root mount options: %q", out)
  1665  			if !strings.Contains(string(out), "ro") {
  1666  				t.Errorf("root not mounted readonly: %q", out)
  1667  			}
  1668  
  1669  			// Check that file cannot be created.
  1670  			ws, err := execute(c, "/bin/touch", "/foo")
  1671  			if err != nil {
  1672  				t.Fatalf("touch file in ro mount: %v", err)
  1673  			}
  1674  			if !ws.Exited() || unix.Errno(ws.ExitStatus()) != unix.EPERM {
  1675  				t.Fatalf("wrong waitStatus: %v", ws)
  1676  			}
  1677  		})
  1678  	}
  1679  }
  1680  
  1681  func TestReadonlyMount(t *testing.T) {
  1682  	for name, conf := range configs(t, all...) {
  1683  		t.Run(name, func(t *testing.T) {
  1684  			dir, err := ioutil.TempDir(testutil.TmpDir(), "ro-mount")
  1685  			if err != nil {
  1686  				t.Fatalf("ioutil.TempDir() failed: %v", err)
  1687  			}
  1688  			spec := testutil.NewSpecWithArgs("sleep", "100")
  1689  			spec.Mounts = append(spec.Mounts, specs.Mount{
  1690  				Destination: dir,
  1691  				Source:      dir,
  1692  				Type:        "bind",
  1693  				Options:     []string{"ro"},
  1694  			})
  1695  			spec.Root.Readonly = false
  1696  
  1697  			_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  1698  			if err != nil {
  1699  				t.Fatalf("error setting up container: %v", err)
  1700  			}
  1701  			defer cleanup()
  1702  
  1703  			args := Args{
  1704  				ID:        testutil.RandomContainerID(),
  1705  				Spec:      spec,
  1706  				BundleDir: bundleDir,
  1707  			}
  1708  			c, err := New(conf, args)
  1709  			if err != nil {
  1710  				t.Fatalf("error creating container: %v", err)
  1711  			}
  1712  			defer c.Destroy()
  1713  			if err := c.Start(conf); err != nil {
  1714  				t.Fatalf("error starting container: %v", err)
  1715  			}
  1716  
  1717  			// Read mounts to check that volume is readonly.
  1718  			cmd := fmt.Sprintf("mount | grep ' %s ' | grep -o -e '(.*)'", dir)
  1719  			out, err := executeCombinedOutput(c, "/bin/sh", "-c", cmd)
  1720  			if err != nil {
  1721  				t.Fatalf("exec failed, err: %v", err)
  1722  			}
  1723  			t.Logf("mount options: %q", out)
  1724  			if !strings.Contains(string(out), "ro") {
  1725  				t.Errorf("volume not mounted readonly: %q", out)
  1726  			}
  1727  
  1728  			// Check that file cannot be created.
  1729  			ws, err := execute(c, "/bin/touch", path.Join(dir, "file"))
  1730  			if err != nil {
  1731  				t.Fatalf("touch file in ro mount: %v", err)
  1732  			}
  1733  			if !ws.Exited() || unix.Errno(ws.ExitStatus()) != unix.EPERM {
  1734  				t.Fatalf("wrong WaitStatus: %v", ws)
  1735  			}
  1736  		})
  1737  	}
  1738  }
  1739  
  1740  func TestUIDMap(t *testing.T) {
  1741  	for name, conf := range configs(t, noOverlay...) {
  1742  		t.Run(name, func(t *testing.T) {
  1743  			testDir, err := ioutil.TempDir(testutil.TmpDir(), "test-mount")
  1744  			if err != nil {
  1745  				t.Fatalf("ioutil.TempDir() failed: %v", err)
  1746  			}
  1747  			defer os.RemoveAll(testDir)
  1748  			testFile := path.Join(testDir, "testfile")
  1749  
  1750  			spec := testutil.NewSpecWithArgs("touch", "/tmp/testfile")
  1751  			uid := os.Getuid()
  1752  			gid := os.Getgid()
  1753  			spec.Linux = &specs.Linux{
  1754  				Namespaces: []specs.LinuxNamespace{
  1755  					{Type: specs.UserNamespace},
  1756  					{Type: specs.PIDNamespace},
  1757  					{Type: specs.MountNamespace},
  1758  				},
  1759  				UIDMappings: []specs.LinuxIDMapping{
  1760  					{
  1761  						ContainerID: 0,
  1762  						HostID:      uint32(uid),
  1763  						Size:        1,
  1764  					},
  1765  				},
  1766  				GIDMappings: []specs.LinuxIDMapping{
  1767  					{
  1768  						ContainerID: 0,
  1769  						HostID:      uint32(gid),
  1770  						Size:        1,
  1771  					},
  1772  				},
  1773  			}
  1774  
  1775  			spec.Mounts = append(spec.Mounts, specs.Mount{
  1776  				Destination: "/tmp",
  1777  				Source:      testDir,
  1778  				Type:        "bind",
  1779  			})
  1780  
  1781  			_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  1782  			if err != nil {
  1783  				t.Fatalf("error setting up container: %v", err)
  1784  			}
  1785  			defer cleanup()
  1786  
  1787  			// Create, start and wait for the container.
  1788  			args := Args{
  1789  				ID:        testutil.RandomContainerID(),
  1790  				Spec:      spec,
  1791  				BundleDir: bundleDir,
  1792  			}
  1793  			c, err := New(conf, args)
  1794  			if err != nil {
  1795  				t.Fatalf("error creating container: %v", err)
  1796  			}
  1797  			defer c.Destroy()
  1798  			if err := c.Start(conf); err != nil {
  1799  				t.Fatalf("error starting container: %v", err)
  1800  			}
  1801  
  1802  			ws, err := c.Wait()
  1803  			if err != nil {
  1804  				t.Fatalf("error waiting on container: %v", err)
  1805  			}
  1806  			if !ws.Exited() || ws.ExitStatus() != 0 {
  1807  				t.Fatalf("container failed, waitStatus: %v", ws)
  1808  			}
  1809  			st := unix.Stat_t{}
  1810  			if err := unix.Stat(testFile, &st); err != nil {
  1811  				t.Fatalf("error stat /testfile: %v", err)
  1812  			}
  1813  
  1814  			if st.Uid != uint32(uid) || st.Gid != uint32(gid) {
  1815  				t.Fatalf("UID: %d (%d) GID: %d (%d)", st.Uid, uid, st.Gid, gid)
  1816  			}
  1817  		})
  1818  	}
  1819  }
  1820  
  1821  // TestAbbreviatedIDs checks that runsc supports using abbreviated container
  1822  // IDs in place of full IDs.
  1823  func TestAbbreviatedIDs(t *testing.T) {
  1824  	doAbbreviatedIDsTest(t, false)
  1825  }
  1826  
  1827  func TestAbbreviatedIDsVFS2(t *testing.T) {
  1828  	doAbbreviatedIDsTest(t, true)
  1829  }
  1830  
  1831  func doAbbreviatedIDsTest(t *testing.T, vfs2 bool) {
  1832  	rootDir, cleanup, err := testutil.SetupRootDir()
  1833  	if err != nil {
  1834  		t.Fatalf("error creating root dir: %v", err)
  1835  	}
  1836  	defer cleanup()
  1837  
  1838  	conf := testutil.TestConfig(t)
  1839  	conf.RootDir = rootDir
  1840  	conf.VFS2 = vfs2
  1841  
  1842  	cids := []string{
  1843  		"foo-" + testutil.RandomContainerID(),
  1844  		"bar-" + testutil.RandomContainerID(),
  1845  		"baz-" + testutil.RandomContainerID(),
  1846  	}
  1847  	for _, cid := range cids {
  1848  		spec := testutil.NewSpecWithArgs("sleep", "100")
  1849  		bundleDir, cleanup, err := testutil.SetupBundleDir(spec)
  1850  		if err != nil {
  1851  			t.Fatalf("error setting up container: %v", err)
  1852  		}
  1853  		defer cleanup()
  1854  
  1855  		// Create and start the container.
  1856  		args := Args{
  1857  			ID:        cid,
  1858  			Spec:      spec,
  1859  			BundleDir: bundleDir,
  1860  		}
  1861  		cont, err := New(conf, args)
  1862  		if err != nil {
  1863  			t.Fatalf("error creating container: %v", err)
  1864  		}
  1865  		defer cont.Destroy()
  1866  	}
  1867  
  1868  	// These should all be unambigious.
  1869  	unambiguous := map[string]string{
  1870  		"f":     cids[0],
  1871  		cids[0]: cids[0],
  1872  		"bar":   cids[1],
  1873  		cids[1]: cids[1],
  1874  		"baz":   cids[2],
  1875  		cids[2]: cids[2],
  1876  	}
  1877  	for shortid, longid := range unambiguous {
  1878  		if _, err := Load(rootDir, FullID{ContainerID: shortid}, LoadOpts{}); err != nil {
  1879  			t.Errorf("%q should resolve to %q: %v", shortid, longid, err)
  1880  		}
  1881  	}
  1882  
  1883  	// These should be ambiguous.
  1884  	ambiguous := []string{
  1885  		"b",
  1886  		"ba",
  1887  	}
  1888  	for _, shortid := range ambiguous {
  1889  		if s, err := Load(rootDir, FullID{ContainerID: shortid}, LoadOpts{}); err == nil {
  1890  			t.Errorf("%q should be ambiguous, but resolved to %q", shortid, s.ID)
  1891  		}
  1892  	}
  1893  }
  1894  
  1895  func TestGoferExits(t *testing.T) {
  1896  	doGoferExitTest(t, false)
  1897  }
  1898  
  1899  func TestGoferExitsVFS2(t *testing.T) {
  1900  	doGoferExitTest(t, true)
  1901  }
  1902  
  1903  func doGoferExitTest(t *testing.T, vfs2 bool) {
  1904  	spec := testutil.NewSpecWithArgs("/bin/sleep", "10000")
  1905  	conf := testutil.TestConfig(t)
  1906  	conf.VFS2 = vfs2
  1907  	_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  1908  
  1909  	if err != nil {
  1910  		t.Fatalf("error setting up container: %v", err)
  1911  	}
  1912  	defer cleanup()
  1913  
  1914  	// Create and start the container.
  1915  	args := Args{
  1916  		ID:        testutil.RandomContainerID(),
  1917  		Spec:      spec,
  1918  		BundleDir: bundleDir,
  1919  	}
  1920  	c, err := New(conf, args)
  1921  	if err != nil {
  1922  		t.Fatalf("error creating container: %v", err)
  1923  	}
  1924  	defer c.Destroy()
  1925  	if err := c.Start(conf); err != nil {
  1926  		t.Fatalf("error starting container: %v", err)
  1927  	}
  1928  
  1929  	// Kill sandbox and expect gofer to exit on its own.
  1930  	sandboxProc, err := os.FindProcess(c.Sandbox.Pid)
  1931  	if err != nil {
  1932  		t.Fatalf("error finding sandbox process: %v", err)
  1933  	}
  1934  	if err := sandboxProc.Kill(); err != nil {
  1935  		t.Fatalf("error killing sandbox process: %v", err)
  1936  	}
  1937  
  1938  	err = blockUntilWaitable(c.GoferPid)
  1939  	if err != nil && err != unix.ECHILD {
  1940  		t.Errorf("error waiting for gofer to exit: %v", err)
  1941  	}
  1942  }
  1943  
  1944  func TestRootNotMount(t *testing.T) {
  1945  	appSym, err := testutil.FindFile("test/cmd/test_app/test_app")
  1946  	if err != nil {
  1947  		t.Fatal("error finding test_app:", err)
  1948  	}
  1949  
  1950  	app, err := filepath.EvalSymlinks(appSym)
  1951  	if err != nil {
  1952  		t.Fatalf("error resolving %q symlink: %v", appSym, err)
  1953  	}
  1954  	log.Infof("App path %q is a symlink to %q", appSym, app)
  1955  
  1956  	static, err := testutil.IsStatic(app)
  1957  	if err != nil {
  1958  		t.Fatalf("error reading application binary: %v", err)
  1959  	}
  1960  	if !static {
  1961  		// This happens during race builds; we cannot map in shared
  1962  		// libraries also, so we need to skip the test.
  1963  		t.Skip()
  1964  	}
  1965  
  1966  	root := filepath.Dir(app)
  1967  	exe := "/" + filepath.Base(app)
  1968  	log.Infof("Executing %q in %q", exe, root)
  1969  
  1970  	spec := testutil.NewSpecWithArgs(exe, "help")
  1971  	spec.Root.Path = root
  1972  	spec.Root.Readonly = true
  1973  	spec.Mounts = nil
  1974  
  1975  	conf := testutil.TestConfig(t)
  1976  	if err := run(spec, conf); err != nil {
  1977  		t.Fatalf("error running sandbox: %v", err)
  1978  	}
  1979  }
  1980  
  1981  func TestUserLog(t *testing.T) {
  1982  	app, err := testutil.FindFile("test/cmd/test_app/test_app")
  1983  	if err != nil {
  1984  		t.Fatal("error finding test_app:", err)
  1985  	}
  1986  
  1987  	// sched_rr_get_interval - not implemented in gvisor.
  1988  	num := strconv.Itoa(unix.SYS_SCHED_RR_GET_INTERVAL)
  1989  	spec := testutil.NewSpecWithArgs(app, "syscall", "--syscall="+num)
  1990  	conf := testutil.TestConfig(t)
  1991  	_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  1992  	if err != nil {
  1993  		t.Fatalf("error setting up container: %v", err)
  1994  	}
  1995  	defer cleanup()
  1996  
  1997  	dir, err := ioutil.TempDir(testutil.TmpDir(), "user_log_test")
  1998  	if err != nil {
  1999  		t.Fatalf("error creating tmp dir: %v", err)
  2000  	}
  2001  	userLog := filepath.Join(dir, "user.log")
  2002  
  2003  	// Create, start and wait for the container.
  2004  	args := Args{
  2005  		ID:        testutil.RandomContainerID(),
  2006  		Spec:      spec,
  2007  		BundleDir: bundleDir,
  2008  		UserLog:   userLog,
  2009  		Attached:  true,
  2010  	}
  2011  	ws, err := Run(conf, args)
  2012  	if err != nil {
  2013  		t.Fatalf("error running container: %v", err)
  2014  	}
  2015  	if !ws.Exited() || ws.ExitStatus() != 0 {
  2016  		t.Fatalf("container failed, waitStatus: %v", ws)
  2017  	}
  2018  
  2019  	out, err := ioutil.ReadFile(userLog)
  2020  	if err != nil {
  2021  		t.Fatalf("error opening user log file %q: %v", userLog, err)
  2022  	}
  2023  	if want := "Unsupported syscall sched_rr_get_interval("; !strings.Contains(string(out), want) {
  2024  		t.Errorf("user log file doesn't contain %q, out: %s", want, string(out))
  2025  	}
  2026  }
  2027  
  2028  func TestWaitOnExitedSandbox(t *testing.T) {
  2029  	for name, conf := range configs(t, all...) {
  2030  		t.Run(name, func(t *testing.T) {
  2031  			// Run a shell that sleeps for 1 second and then exits with a
  2032  			// non-zero code.
  2033  			const wantExit = 17
  2034  			cmd := fmt.Sprintf("sleep 1; exit %d", wantExit)
  2035  			spec := testutil.NewSpecWithArgs("/bin/sh", "-c", cmd)
  2036  			_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  2037  			if err != nil {
  2038  				t.Fatalf("error setting up container: %v", err)
  2039  			}
  2040  			defer cleanup()
  2041  
  2042  			// Create and Start the container.
  2043  			args := Args{
  2044  				ID:        testutil.RandomContainerID(),
  2045  				Spec:      spec,
  2046  				BundleDir: bundleDir,
  2047  			}
  2048  			c, err := New(conf, args)
  2049  			if err != nil {
  2050  				t.Fatalf("error creating container: %v", err)
  2051  			}
  2052  			defer c.Destroy()
  2053  			if err := c.Start(conf); err != nil {
  2054  				t.Fatalf("error starting container: %v", err)
  2055  			}
  2056  
  2057  			// Wait on the sandbox. This will make an RPC to the sandbox
  2058  			// and get the actual exit status of the application.
  2059  			ws, err := c.Wait()
  2060  			if err != nil {
  2061  				t.Fatalf("error waiting on container: %v", err)
  2062  			}
  2063  			if got := ws.ExitStatus(); got != wantExit {
  2064  				t.Errorf("got exit status %d, want %d", got, wantExit)
  2065  			}
  2066  
  2067  			// Now the sandbox has exited, but the zombie sandbox process
  2068  			// still exists. Calling Wait() now will return the sandbox
  2069  			// exit status.
  2070  			ws, err = c.Wait()
  2071  			if err != nil {
  2072  				t.Fatalf("error waiting on container: %v", err)
  2073  			}
  2074  			if got := ws.ExitStatus(); got != wantExit {
  2075  				t.Errorf("got exit status %d, want %d", got, wantExit)
  2076  			}
  2077  		})
  2078  	}
  2079  }
  2080  
  2081  func TestDestroyNotStarted(t *testing.T) {
  2082  	doDestroyNotStartedTest(t, false)
  2083  }
  2084  
  2085  func TestDestroyNotStartedVFS2(t *testing.T) {
  2086  	doDestroyNotStartedTest(t, true)
  2087  }
  2088  
  2089  func doDestroyNotStartedTest(t *testing.T, vfs2 bool) {
  2090  	spec := testutil.NewSpecWithArgs("/bin/sleep", "100")
  2091  	conf := testutil.TestConfig(t)
  2092  	conf.VFS2 = vfs2
  2093  	_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  2094  	if err != nil {
  2095  		t.Fatalf("error setting up container: %v", err)
  2096  	}
  2097  	defer cleanup()
  2098  
  2099  	// Create the container and check that it can be destroyed.
  2100  	args := Args{
  2101  		ID:        testutil.RandomContainerID(),
  2102  		Spec:      spec,
  2103  		BundleDir: bundleDir,
  2104  	}
  2105  	c, err := New(conf, args)
  2106  	if err != nil {
  2107  		t.Fatalf("error creating container: %v", err)
  2108  	}
  2109  	if err := c.Destroy(); err != nil {
  2110  		t.Fatalf("deleting non-started container failed: %v", err)
  2111  	}
  2112  }
  2113  
  2114  // TestDestroyStarting attempts to force a race between start and destroy.
  2115  func TestDestroyStarting(t *testing.T) {
  2116  	doDestroyStartingTest(t, false)
  2117  }
  2118  
  2119  func TestDestroyStartedVFS2(t *testing.T) {
  2120  	doDestroyStartingTest(t, true)
  2121  }
  2122  
  2123  func doDestroyStartingTest(t *testing.T, vfs2 bool) {
  2124  	for i := 0; i < 10; i++ {
  2125  		spec := testutil.NewSpecWithArgs("/bin/sleep", "100")
  2126  		conf := testutil.TestConfig(t)
  2127  		conf.VFS2 = vfs2
  2128  		rootDir, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  2129  		if err != nil {
  2130  			t.Fatalf("error setting up container: %v", err)
  2131  		}
  2132  		defer cleanup()
  2133  
  2134  		// Create the container and check that it can be destroyed.
  2135  		args := Args{
  2136  			ID:        testutil.RandomContainerID(),
  2137  			Spec:      spec,
  2138  			BundleDir: bundleDir,
  2139  		}
  2140  		c, err := New(conf, args)
  2141  		if err != nil {
  2142  			t.Fatalf("error creating container: %v", err)
  2143  		}
  2144  
  2145  		// Container is not thread safe, so load another instance to run in
  2146  		// concurrently.
  2147  		startCont, err := Load(rootDir, FullID{ContainerID: args.ID}, LoadOpts{})
  2148  		if err != nil {
  2149  			t.Fatalf("error loading container: %v", err)
  2150  		}
  2151  		wg := sync.WaitGroup{}
  2152  		wg.Add(1)
  2153  		go func() {
  2154  			defer wg.Done()
  2155  			// Ignore failures, start can fail if destroy runs first.
  2156  			startCont.Start(conf)
  2157  		}()
  2158  
  2159  		wg.Add(1)
  2160  		go func() {
  2161  			defer wg.Done()
  2162  			if err := c.Destroy(); err != nil {
  2163  				t.Errorf("deleting non-started container failed: %v", err)
  2164  			}
  2165  		}()
  2166  		wg.Wait()
  2167  	}
  2168  }
  2169  
  2170  func TestCreateWorkingDir(t *testing.T) {
  2171  	for name, conf := range configs(t, all...) {
  2172  		t.Run(name, func(t *testing.T) {
  2173  			tmpDir, err := ioutil.TempDir(testutil.TmpDir(), "cwd-create")
  2174  			if err != nil {
  2175  				t.Fatalf("ioutil.TempDir() failed: %v", err)
  2176  			}
  2177  			dir := path.Join(tmpDir, "new/working/dir")
  2178  
  2179  			// touch will fail if the directory doesn't exist.
  2180  			spec := testutil.NewSpecWithArgs("/bin/touch", path.Join(dir, "file"))
  2181  			spec.Process.Cwd = dir
  2182  			spec.Root.Readonly = true
  2183  
  2184  			if err := run(spec, conf); err != nil {
  2185  				t.Fatalf("Error running container: %v", err)
  2186  			}
  2187  		})
  2188  	}
  2189  }
  2190  
  2191  // TestMountPropagation verifies that mount propagates to slave but not to
  2192  // private mounts.
  2193  func TestMountPropagation(t *testing.T) {
  2194  	// Setup dir structure:
  2195  	//   - src: is mounted as shared and is used as source for both private and
  2196  	//     slave mounts
  2197  	//   - dir: will be bind mounted inside src and should propagate to slave
  2198  	tmpDir, err := ioutil.TempDir(testutil.TmpDir(), "mount")
  2199  	if err != nil {
  2200  		t.Fatalf("ioutil.TempDir() failed: %v", err)
  2201  	}
  2202  	src := filepath.Join(tmpDir, "src")
  2203  	srcMnt := filepath.Join(src, "mnt")
  2204  	dir := filepath.Join(tmpDir, "dir")
  2205  	for _, path := range []string{src, srcMnt, dir} {
  2206  		if err := os.MkdirAll(path, 0777); err != nil {
  2207  			t.Fatalf("MkdirAll(%q): %v", path, err)
  2208  		}
  2209  	}
  2210  	dirFile := filepath.Join(dir, "file")
  2211  	f, err := os.Create(dirFile)
  2212  	if err != nil {
  2213  		t.Fatalf("os.Create(%q): %v", dirFile, err)
  2214  	}
  2215  	f.Close()
  2216  
  2217  	// Setup src as a shared mount.
  2218  	if err := unix.Mount(src, src, "bind", unix.MS_BIND, ""); err != nil {
  2219  		t.Fatalf("mount(%q, %q, MS_BIND): %v", dir, srcMnt, err)
  2220  	}
  2221  	if err := unix.Mount("", src, "", unix.MS_SHARED, ""); err != nil {
  2222  		t.Fatalf("mount(%q, MS_SHARED): %v", srcMnt, err)
  2223  	}
  2224  
  2225  	spec := testutil.NewSpecWithArgs("sleep", "1000")
  2226  
  2227  	priv := filepath.Join(tmpDir, "priv")
  2228  	slave := filepath.Join(tmpDir, "slave")
  2229  	spec.Mounts = []specs.Mount{
  2230  		{
  2231  			Source:      src,
  2232  			Destination: priv,
  2233  			Type:        "bind",
  2234  			Options:     []string{"private"},
  2235  		},
  2236  		{
  2237  			Source:      src,
  2238  			Destination: slave,
  2239  			Type:        "bind",
  2240  			Options:     []string{"slave"},
  2241  		},
  2242  	}
  2243  
  2244  	conf := testutil.TestConfig(t)
  2245  	_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  2246  	if err != nil {
  2247  		t.Fatalf("error setting up container: %v", err)
  2248  	}
  2249  	defer cleanup()
  2250  
  2251  	args := Args{
  2252  		ID:        testutil.RandomContainerID(),
  2253  		Spec:      spec,
  2254  		BundleDir: bundleDir,
  2255  	}
  2256  	cont, err := New(conf, args)
  2257  	if err != nil {
  2258  		t.Fatalf("creating container: %v", err)
  2259  	}
  2260  	defer cont.Destroy()
  2261  
  2262  	if err := cont.Start(conf); err != nil {
  2263  		t.Fatalf("starting container: %v", err)
  2264  	}
  2265  
  2266  	// After the container is started, mount dir inside source and check what
  2267  	// happens to both destinations.
  2268  	if err := unix.Mount(dir, srcMnt, "bind", unix.MS_BIND, ""); err != nil {
  2269  		t.Fatalf("mount(%q, %q, MS_BIND): %v", dir, srcMnt, err)
  2270  	}
  2271  
  2272  	// Check that mount didn't propagate to private mount.
  2273  	privFile := filepath.Join(priv, "mnt", "file")
  2274  	if ws, err := execute(cont, "/usr/bin/test", "!", "-f", privFile); err != nil || ws != 0 {
  2275  		t.Fatalf("exec: test ! -f %q, ws: %v, err: %v", privFile, ws, err)
  2276  	}
  2277  
  2278  	// Check that mount propagated to slave mount.
  2279  	slaveFile := filepath.Join(slave, "mnt", "file")
  2280  	if ws, err := execute(cont, "/usr/bin/test", "-f", slaveFile); err != nil || ws != 0 {
  2281  		t.Fatalf("exec: test -f %q, ws: %v, err: %v", privFile, ws, err)
  2282  	}
  2283  }
  2284  
  2285  func TestMountSymlink(t *testing.T) {
  2286  	for name, conf := range configs(t, all...) {
  2287  		t.Run(name, func(t *testing.T) {
  2288  			dir, err := ioutil.TempDir(testutil.TmpDir(), "mount-symlink")
  2289  			if err != nil {
  2290  				t.Fatalf("ioutil.TempDir() failed: %v", err)
  2291  			}
  2292  			defer os.RemoveAll(dir)
  2293  
  2294  			source := path.Join(dir, "source")
  2295  			target := path.Join(dir, "target")
  2296  			for _, path := range []string{source, target} {
  2297  				if err := os.MkdirAll(path, 0777); err != nil {
  2298  					t.Fatalf("os.MkdirAll(): %v", err)
  2299  				}
  2300  			}
  2301  			f, err := os.Create(path.Join(source, "file"))
  2302  			if err != nil {
  2303  				t.Fatalf("os.Create(): %v", err)
  2304  			}
  2305  			f.Close()
  2306  
  2307  			link := path.Join(dir, "link")
  2308  			if err := os.Symlink(target, link); err != nil {
  2309  				t.Fatalf("os.Symlink(%q, %q): %v", target, link, err)
  2310  			}
  2311  
  2312  			spec := testutil.NewSpecWithArgs("/bin/sleep", "1000")
  2313  
  2314  			// Mount to a symlink to ensure the mount code will follow it and mount
  2315  			// at the symlink target.
  2316  			spec.Mounts = append(spec.Mounts, specs.Mount{
  2317  				Type:        "bind",
  2318  				Destination: link,
  2319  				Source:      source,
  2320  			})
  2321  
  2322  			_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  2323  			if err != nil {
  2324  				t.Fatalf("error setting up container: %v", err)
  2325  			}
  2326  			defer cleanup()
  2327  
  2328  			args := Args{
  2329  				ID:        testutil.RandomContainerID(),
  2330  				Spec:      spec,
  2331  				BundleDir: bundleDir,
  2332  			}
  2333  			cont, err := New(conf, args)
  2334  			if err != nil {
  2335  				t.Fatalf("creating container: %v", err)
  2336  			}
  2337  			defer cont.Destroy()
  2338  
  2339  			if err := cont.Start(conf); err != nil {
  2340  				t.Fatalf("starting container: %v", err)
  2341  			}
  2342  
  2343  			// Check that symlink was resolved and mount was created where the symlink
  2344  			// is pointing to.
  2345  			file := path.Join(target, "file")
  2346  			if ws, err := execute(cont, "/usr/bin/test", "-f", file); err != nil || ws != 0 {
  2347  				t.Fatalf("exec: test -f %q, ws: %v, err: %v", file, ws, err)
  2348  			}
  2349  		})
  2350  	}
  2351  }
  2352  
  2353  // Check that --net-raw disables the CAP_NET_RAW capability.
  2354  func TestNetRaw(t *testing.T) {
  2355  	capNetRaw := strconv.FormatUint(bits.MaskOf64(int(linux.CAP_NET_RAW)), 10)
  2356  	app, err := testutil.FindFile("test/cmd/test_app/test_app")
  2357  	if err != nil {
  2358  		t.Fatal("error finding test_app:", err)
  2359  	}
  2360  
  2361  	for _, enableRaw := range []bool{true, false} {
  2362  		conf := testutil.TestConfig(t)
  2363  		conf.EnableRaw = enableRaw
  2364  
  2365  		test := "--enabled"
  2366  		if !enableRaw {
  2367  			test = "--disabled"
  2368  		}
  2369  
  2370  		spec := testutil.NewSpecWithArgs(app, "capability", test, capNetRaw)
  2371  		if err := run(spec, conf); err != nil {
  2372  			t.Fatalf("Error running container: %v", err)
  2373  		}
  2374  	}
  2375  }
  2376  
  2377  // TestTTYField checks TTY field returned by container.Processes().
  2378  func TestTTYField(t *testing.T) {
  2379  	stop := testutil.StartReaper()
  2380  	defer stop()
  2381  
  2382  	testApp, err := testutil.FindFile("test/cmd/test_app/test_app")
  2383  	if err != nil {
  2384  		t.Fatal("error finding test_app:", err)
  2385  	}
  2386  
  2387  	testCases := []struct {
  2388  		name         string
  2389  		useTTY       bool
  2390  		wantTTYField string
  2391  	}{
  2392  		{
  2393  			name:         "no tty",
  2394  			useTTY:       false,
  2395  			wantTTYField: "?",
  2396  		},
  2397  		{
  2398  			name:         "tty used",
  2399  			useTTY:       true,
  2400  			wantTTYField: "pts/0",
  2401  		},
  2402  	}
  2403  
  2404  	for _, test := range testCases {
  2405  		for _, vfs2 := range []bool{false, true} {
  2406  			name := test.name
  2407  			if vfs2 {
  2408  				name += "-vfs2"
  2409  			}
  2410  			t.Run(name, func(t *testing.T) {
  2411  				conf := testutil.TestConfig(t)
  2412  				conf.VFS2 = vfs2
  2413  
  2414  				// We will run /bin/sleep, possibly with an open TTY.
  2415  				cmd := []string{"/bin/sleep", "10000"}
  2416  				if test.useTTY {
  2417  					// Run inside the "pty-runner".
  2418  					cmd = append([]string{testApp, "pty-runner"}, cmd...)
  2419  				}
  2420  
  2421  				spec := testutil.NewSpecWithArgs(cmd...)
  2422  				_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  2423  				if err != nil {
  2424  					t.Fatalf("error setting up container: %v", err)
  2425  				}
  2426  				defer cleanup()
  2427  
  2428  				// Create and start the container.
  2429  				args := Args{
  2430  					ID:        testutil.RandomContainerID(),
  2431  					Spec:      spec,
  2432  					BundleDir: bundleDir,
  2433  				}
  2434  				c, err := New(conf, args)
  2435  				if err != nil {
  2436  					t.Fatalf("error creating container: %v", err)
  2437  				}
  2438  				defer c.Destroy()
  2439  				if err := c.Start(conf); err != nil {
  2440  					t.Fatalf("error starting container: %v", err)
  2441  				}
  2442  
  2443  				// Wait for sleep to be running, and check the TTY
  2444  				// field.
  2445  				var gotTTYField string
  2446  				cb := func() error {
  2447  					ps, err := c.Processes()
  2448  					if err != nil {
  2449  						err = fmt.Errorf("error getting process data from container: %v", err)
  2450  						return &backoff.PermanentError{Err: err}
  2451  					}
  2452  					for _, p := range ps {
  2453  						if strings.Contains(p.Cmd, "sleep") {
  2454  							gotTTYField = p.TTY
  2455  							return nil
  2456  						}
  2457  					}
  2458  					return fmt.Errorf("sleep not running")
  2459  				}
  2460  				if err := testutil.Poll(cb, 30*time.Second); err != nil {
  2461  					t.Fatalf("error waiting for sleep process: %v", err)
  2462  				}
  2463  
  2464  				if gotTTYField != test.wantTTYField {
  2465  					t.Errorf("tty field got %q, want %q", gotTTYField, test.wantTTYField)
  2466  				}
  2467  			})
  2468  		}
  2469  	}
  2470  }
  2471  
  2472  // Test that container can run even when there are corrupt state files in the
  2473  // root directiry.
  2474  func TestCreateWithCorruptedStateFile(t *testing.T) {
  2475  	conf := testutil.TestConfig(t)
  2476  	spec := testutil.NewSpecWithArgs("/bin/true")
  2477  	_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  2478  	if err != nil {
  2479  		t.Fatalf("error setting up container: %v", err)
  2480  	}
  2481  	defer cleanup()
  2482  
  2483  	// Create corrupted state file.
  2484  	corruptID := testutil.RandomContainerID()
  2485  	corruptState := buildPath(conf.RootDir, FullID{SandboxID: corruptID, ContainerID: corruptID}, stateFileExtension)
  2486  	if err := ioutil.WriteFile(corruptState, []byte("this{file(is;not[valid.json"), 0777); err != nil {
  2487  		t.Fatalf("createCorruptStateFile(): %v", err)
  2488  	}
  2489  	defer os.Remove(corruptState)
  2490  
  2491  	if _, err := Load(conf.RootDir, FullID{ContainerID: corruptID}, LoadOpts{SkipCheck: true}); err == nil {
  2492  		t.Fatalf("loading corrupted state file should have failed")
  2493  	}
  2494  
  2495  	args := Args{
  2496  		ID:        testutil.RandomContainerID(),
  2497  		Spec:      spec,
  2498  		BundleDir: bundleDir,
  2499  		Attached:  true,
  2500  	}
  2501  	if ws, err := Run(conf, args); err != nil {
  2502  		t.Errorf("running container: %v", err)
  2503  	} else if !ws.Exited() || ws.ExitStatus() != 0 {
  2504  		t.Errorf("container failed, waitStatus: %v", ws)
  2505  	}
  2506  }
  2507  
  2508  func TestBindMountByOption(t *testing.T) {
  2509  	for name, conf := range configs(t, all...) {
  2510  		t.Run(name, func(t *testing.T) {
  2511  			dir, err := ioutil.TempDir(testutil.TmpDir(), "bind-mount")
  2512  			spec := testutil.NewSpecWithArgs("/bin/touch", path.Join(dir, "file"))
  2513  			if err != nil {
  2514  				t.Fatalf("ioutil.TempDir(): %v", err)
  2515  			}
  2516  			spec.Mounts = append(spec.Mounts, specs.Mount{
  2517  				Destination: dir,
  2518  				Source:      dir,
  2519  				Type:        "none",
  2520  				Options:     []string{"rw", "bind"},
  2521  			})
  2522  			if err := run(spec, conf); err != nil {
  2523  				t.Fatalf("error running sandbox: %v", err)
  2524  			}
  2525  		})
  2526  	}
  2527  }
  2528  
  2529  // TestRlimits sets limit to number of open files and checks that the limit
  2530  // is propagated to the container.
  2531  func TestRlimits(t *testing.T) {
  2532  	file, err := ioutil.TempFile(testutil.TmpDir(), "ulimit")
  2533  	if err != nil {
  2534  		t.Fatal(err)
  2535  	}
  2536  	cmd := fmt.Sprintf("ulimit -n > %q", file.Name())
  2537  
  2538  	spec := testutil.NewSpecWithArgs("sh", "-c", cmd)
  2539  	spec.Process.Rlimits = []specs.POSIXRlimit{
  2540  		{Type: "RLIMIT_NOFILE", Hard: 1000, Soft: 100},
  2541  	}
  2542  
  2543  	conf := testutil.TestConfig(t)
  2544  	if err := run(spec, conf); err != nil {
  2545  		t.Fatalf("Error running container: %v", err)
  2546  	}
  2547  	got, err := ioutil.ReadFile(file.Name())
  2548  	if err != nil {
  2549  		t.Fatal(err)
  2550  	}
  2551  	if want := "100\n"; string(got) != want {
  2552  		t.Errorf("ulimit result, got: %q, want: %q", got, want)
  2553  	}
  2554  }
  2555  
  2556  // TestRlimitsExec sets limit to number of open files and checks that the limit
  2557  // is propagated to exec'd processes.
  2558  func TestRlimitsExec(t *testing.T) {
  2559  	spec := testutil.NewSpecWithArgs("sleep", "100")
  2560  	spec.Process.Rlimits = []specs.POSIXRlimit{
  2561  		{Type: "RLIMIT_NOFILE", Hard: 1000, Soft: 100},
  2562  	}
  2563  
  2564  	conf := testutil.TestConfig(t)
  2565  	_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  2566  	if err != nil {
  2567  		t.Fatalf("error setting up container: %v", err)
  2568  	}
  2569  	defer cleanup()
  2570  
  2571  	args := Args{
  2572  		ID:        testutil.RandomContainerID(),
  2573  		Spec:      spec,
  2574  		BundleDir: bundleDir,
  2575  	}
  2576  	cont, err := New(conf, args)
  2577  	if err != nil {
  2578  		t.Fatalf("error creating container: %v", err)
  2579  	}
  2580  	defer cont.Destroy()
  2581  	if err := cont.Start(conf); err != nil {
  2582  		t.Fatalf("error starting container: %v", err)
  2583  	}
  2584  
  2585  	got, err := executeCombinedOutput(cont, "/bin/sh", "-c", "ulimit -n")
  2586  	if err != nil {
  2587  		t.Fatal(err)
  2588  	}
  2589  	if want := "100\n"; string(got) != want {
  2590  		t.Errorf("ulimit result, got: %q, want: %q", got, want)
  2591  	}
  2592  }