gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/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  	"fmt"
    20  	"io"
    21  	"io/ioutil"
    22  	"math"
    23  	"math/rand"
    24  	"os"
    25  	"os/exec"
    26  	"path"
    27  	"path/filepath"
    28  	"reflect"
    29  	"runtime"
    30  	"slices"
    31  	"strconv"
    32  	"strings"
    33  	"testing"
    34  	"time"
    35  
    36  	"github.com/cenkalti/backoff"
    37  	specs "github.com/opencontainers/runtime-spec/specs-go"
    38  	"golang.org/x/sys/unix"
    39  	"gvisor.dev/gvisor/pkg/abi/linux"
    40  	"gvisor.dev/gvisor/pkg/bits"
    41  	"gvisor.dev/gvisor/pkg/log"
    42  	"gvisor.dev/gvisor/pkg/sentry/control"
    43  	"gvisor.dev/gvisor/pkg/sentry/fsimpl/erofs"
    44  	"gvisor.dev/gvisor/pkg/sentry/kernel"
    45  	"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
    46  	"gvisor.dev/gvisor/pkg/sentry/pgalloc"
    47  	"gvisor.dev/gvisor/pkg/sentry/platform"
    48  	"gvisor.dev/gvisor/pkg/state/statefile"
    49  	"gvisor.dev/gvisor/pkg/sync"
    50  	"gvisor.dev/gvisor/pkg/test/testutil"
    51  	"gvisor.dev/gvisor/runsc/boot"
    52  	"gvisor.dev/gvisor/runsc/cgroup"
    53  	"gvisor.dev/gvisor/runsc/config"
    54  	"gvisor.dev/gvisor/runsc/flag"
    55  	"gvisor.dev/gvisor/runsc/specutils"
    56  )
    57  
    58  func TestMain(m *testing.M) {
    59  	config.RegisterFlags(flag.CommandLine)
    60  	log.SetLevel(log.Debug)
    61  	if err := testutil.ConfigureExePath(); err != nil {
    62  		panic(err.Error())
    63  	}
    64  	if err := specutils.MaybeRunAsRoot(); err != nil {
    65  		fmt.Fprintf(os.Stderr, "Error running as root: %v", err)
    66  		os.Exit(123)
    67  	}
    68  	os.Exit(m.Run())
    69  }
    70  
    71  func execute(conf *config.Config, cont *Container, name string, arg ...string) (unix.WaitStatus, error) {
    72  	args := &control.ExecArgs{
    73  		Filename: name,
    74  		Argv:     append([]string{name}, arg...),
    75  	}
    76  	return cont.executeSync(conf, args)
    77  }
    78  
    79  // executeCombinedOutput executes a process in the container and captures
    80  // stdout and stderr. If execFile is supplied, a host file will be executed.
    81  // Otherwise, the name argument is used to resolve the executable in the guest.
    82  func executeCombinedOutput(conf *config.Config, cont *Container, execFile *os.File, name string, arg ...string) ([]byte, error) {
    83  	r, w, err := os.Pipe()
    84  	if err != nil {
    85  		return nil, err
    86  	}
    87  	defer r.Close()
    88  
    89  	// Unset the filename when we execute via FD.
    90  	if execFile != nil {
    91  		name = ""
    92  	}
    93  	args := &control.ExecArgs{
    94  		Filename: name,
    95  		Argv:     append([]string{name}, arg...),
    96  		FilePayload: control.NewFilePayload(map[int]*os.File{
    97  			0: os.Stdin, 1: w, 2: w,
    98  		}, execFile),
    99  	}
   100  	ws, err := cont.executeSync(conf, args)
   101  	w.Close()
   102  	if err != nil {
   103  		return nil, err
   104  	}
   105  	out, err := ioutil.ReadAll(r)
   106  	switch {
   107  	case ws != 0 && err != nil:
   108  		err = fmt.Errorf("exec failed, status: %v, ioutil.ReadAll failed: %v", ws, err)
   109  	case ws != 0:
   110  		err = fmt.Errorf("exec failed, status: %v", ws)
   111  	}
   112  	return out, err
   113  }
   114  
   115  // executeSync synchronously executes a new process.
   116  func (c *Container) executeSync(conf *config.Config, args *control.ExecArgs) (unix.WaitStatus, error) {
   117  	pid, err := c.Execute(conf, args)
   118  	if err != nil {
   119  		return 0, fmt.Errorf("error executing: %v", err)
   120  	}
   121  	ws, err := c.WaitPID(pid)
   122  	if err != nil {
   123  		return 0, fmt.Errorf("error waiting: %v", err)
   124  	}
   125  	return ws, nil
   126  }
   127  
   128  // waitForProcessList waits for the given process list to show up in the container.
   129  func waitForProcessList(cont *Container, want []*control.Process) error {
   130  	cb := func() error {
   131  		got, err := cont.Processes()
   132  		if err != nil {
   133  			err = fmt.Errorf("error getting process data from container: %w", err)
   134  			return &backoff.PermanentError{Err: err}
   135  		}
   136  		if !procListsEqual(got, want) {
   137  			return fmt.Errorf("container got process list: %s, want: %s", procListToString(got), procListToString(want))
   138  		}
   139  		return nil
   140  	}
   141  	// Gives plenty of time as tests can run slow under --race.
   142  	return testutil.Poll(cb, 30*time.Second)
   143  }
   144  
   145  // waitForProcess waits for the given process to show up in the container.
   146  func waitForProcess(cont *Container, want *control.Process) error {
   147  	cb := func() error {
   148  		gots, err := cont.Processes()
   149  		if err != nil {
   150  			err = fmt.Errorf("error getting process data from container: %w", err)
   151  			return &backoff.PermanentError{Err: err}
   152  		}
   153  		for _, got := range gots {
   154  			if procEqual(got, want) {
   155  				return nil
   156  			}
   157  		}
   158  		return fmt.Errorf("container got process list: %s, want: %+v", procListToString(gots), want)
   159  	}
   160  	// Gives plenty of time as tests can run slow under --race.
   161  	return testutil.Poll(cb, 30*time.Second)
   162  }
   163  
   164  func waitForProcessCount(cont *Container, want int) error {
   165  	cb := func() error {
   166  		pss, err := cont.Processes()
   167  		if err != nil {
   168  			err = fmt.Errorf("error getting process data from container: %w", err)
   169  			return &backoff.PermanentError{Err: err}
   170  		}
   171  		if got := len(pss); got != want {
   172  			log.Infof("Waiting for process count to reach %d. Current: %d", want, got)
   173  			return fmt.Errorf("wrong process count, got: %d, want: %d", got, want)
   174  		}
   175  		return nil
   176  	}
   177  	// Gives plenty of time as tests can run slow under --race.
   178  	return testutil.Poll(cb, 30*time.Second)
   179  }
   180  
   181  func blockUntilWaitable(pid int) error {
   182  	_, _, err := specutils.RetryEintr(func() (uintptr, uintptr, error) {
   183  		var err error
   184  		_, _, err1 := unix.Syscall6(unix.SYS_WAITID, 1, uintptr(pid), 0, unix.WEXITED|unix.WNOWAIT, 0, 0)
   185  		if err1 != 0 {
   186  			err = err1
   187  		}
   188  		return 0, 0, err
   189  	})
   190  	return err
   191  }
   192  
   193  // execPS executes `ps` inside the container and return the processes.
   194  func execPS(conf *config.Config, c *Container) ([]*control.Process, error) {
   195  	out, err := executeCombinedOutput(conf, c, nil, "/bin/ps", "-e")
   196  	if err != nil {
   197  		return nil, err
   198  	}
   199  	lines := strings.Split(string(out), "\n")
   200  	if len(lines) < 1 {
   201  		return nil, fmt.Errorf("missing header: %q", lines)
   202  	}
   203  	procs := make([]*control.Process, 0, len(lines)-1)
   204  	for _, line := range lines[1:] {
   205  		if len(line) == 0 {
   206  			continue
   207  		}
   208  		fields := strings.Fields(line)
   209  		if len(fields) != 4 {
   210  			return nil, fmt.Errorf("malformed line: %s", line)
   211  		}
   212  		pid, err := strconv.Atoi(fields[0])
   213  		if err != nil {
   214  			return nil, err
   215  		}
   216  		cmd := fields[3]
   217  		// Fill only the fields we need thus far.
   218  		procs = append(procs, &control.Process{
   219  			PID: kernel.ThreadID(pid),
   220  			Cmd: cmd,
   221  		})
   222  	}
   223  	return procs, nil
   224  }
   225  
   226  // procListsEqual is used to check whether 2 Process lists are equal. Fields
   227  // set to -1 in wants are ignored. Timestamp and threads fields are always
   228  // ignored.
   229  func procListsEqual(gots, wants []*control.Process) bool {
   230  	if len(gots) != len(wants) {
   231  		return false
   232  	}
   233  	for i := range gots {
   234  		if !procEqual(gots[i], wants[i]) {
   235  			return false
   236  		}
   237  	}
   238  	return true
   239  }
   240  
   241  func procEqual(got, want *control.Process) bool {
   242  	if want.UID != math.MaxUint32 && want.UID != got.UID {
   243  		return false
   244  	}
   245  	if want.PID != -1 && want.PID != got.PID {
   246  		return false
   247  	}
   248  	if want.PPID != -1 && want.PPID != got.PPID {
   249  		return false
   250  	}
   251  	if len(want.TTY) != 0 && want.TTY != got.TTY {
   252  		return false
   253  	}
   254  	if len(want.Cmd) != 0 && want.Cmd != got.Cmd {
   255  		return false
   256  	}
   257  	return true
   258  }
   259  
   260  type processBuilder struct {
   261  	process control.Process
   262  }
   263  
   264  func newProcessBuilder() *processBuilder {
   265  	return &processBuilder{
   266  		process: control.Process{
   267  			UID:  math.MaxUint32,
   268  			PID:  -1,
   269  			PPID: -1,
   270  		},
   271  	}
   272  }
   273  
   274  func (p *processBuilder) Cmd(cmd string) *processBuilder {
   275  	p.process.Cmd = cmd
   276  	return p
   277  }
   278  
   279  func (p *processBuilder) PID(pid kernel.ThreadID) *processBuilder {
   280  	p.process.PID = pid
   281  	return p
   282  }
   283  
   284  func (p *processBuilder) PPID(ppid kernel.ThreadID) *processBuilder {
   285  	p.process.PPID = ppid
   286  	return p
   287  }
   288  
   289  func (p *processBuilder) UID(uid auth.KUID) *processBuilder {
   290  	p.process.UID = uid
   291  	return p
   292  }
   293  
   294  func (p *processBuilder) Process() *control.Process {
   295  	return &p.process
   296  }
   297  
   298  func procListToString(pl []*control.Process) string {
   299  	strs := make([]string, 0, len(pl))
   300  	for _, p := range pl {
   301  		strs = append(strs, fmt.Sprintf("%+v", p))
   302  	}
   303  	return fmt.Sprintf("[%s]", strings.Join(strs, ","))
   304  }
   305  
   306  // createWriteableOutputFile creates an output file that can be read and
   307  // written to in the sandbox.
   308  func createWriteableOutputFile(path string) (*os.File, error) {
   309  	outputFile, err := os.OpenFile(path, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666)
   310  	if err != nil {
   311  		return nil, fmt.Errorf("error creating file: %q, %v", path, err)
   312  	}
   313  
   314  	// Chmod to allow writing after umask.
   315  	if err := outputFile.Chmod(0666); err != nil {
   316  		return nil, fmt.Errorf("error chmoding file: %q, %v", path, err)
   317  	}
   318  	return outputFile, nil
   319  }
   320  
   321  func waitForFileNotEmpty(f *os.File) error {
   322  	op := func() error {
   323  		fi, err := f.Stat()
   324  		if err != nil {
   325  			return err
   326  		}
   327  		if fi.Size() == 0 {
   328  			return fmt.Errorf("file %q is empty", f.Name())
   329  		}
   330  		return nil
   331  	}
   332  
   333  	return testutil.Poll(op, 30*time.Second)
   334  }
   335  
   336  func waitForFileExist(path string) error {
   337  	op := func() error {
   338  		if _, err := os.Stat(path); os.IsNotExist(err) {
   339  			return err
   340  		}
   341  		return nil
   342  	}
   343  
   344  	return testutil.Poll(op, 30*time.Second)
   345  }
   346  
   347  // readOutputNum reads a file at given filepath and returns the int at the
   348  // requested position.
   349  func readOutputNum(file string, position int) (int, error) {
   350  	f, err := os.Open(file)
   351  	if err != nil {
   352  		return 0, fmt.Errorf("error opening file: %q, %v", file, err)
   353  	}
   354  
   355  	// Ensure that there is content in output file.
   356  	if err := waitForFileNotEmpty(f); err != nil {
   357  		return 0, fmt.Errorf("error waiting for output file: %v", err)
   358  	}
   359  
   360  	b, err := ioutil.ReadAll(f)
   361  	if err != nil {
   362  		return 0, fmt.Errorf("error reading file: %v", err)
   363  	}
   364  	if len(b) == 0 {
   365  		return 0, fmt.Errorf("error no content was read")
   366  	}
   367  
   368  	// Strip leading null bytes caused by file offset not being 0 upon restore.
   369  	b = bytes.Trim(b, "\x00")
   370  	nums := strings.Split(string(b), "\n")
   371  
   372  	if position >= len(nums) {
   373  		return 0, fmt.Errorf("position %v is not within the length of content %v", position, nums)
   374  	}
   375  	if position == -1 {
   376  		// Expectation of newline at the end of last position.
   377  		position = len(nums) - 2
   378  	}
   379  	num, err := strconv.Atoi(nums[position])
   380  	if err != nil {
   381  		return 0, fmt.Errorf("error getting number from file: %v", err)
   382  	}
   383  	return num, nil
   384  }
   385  
   386  // run starts the sandbox and waits for it to exit, checking that the
   387  // application succeeded.
   388  func run(spec *specs.Spec, conf *config.Config) error {
   389  	_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
   390  	if err != nil {
   391  		return fmt.Errorf("error setting up container: %v", err)
   392  	}
   393  	defer cleanup()
   394  
   395  	// Create, start and wait for the container.
   396  	args := Args{
   397  		ID:        testutil.RandomContainerID(),
   398  		Spec:      spec,
   399  		BundleDir: bundleDir,
   400  		Attached:  true,
   401  	}
   402  	ws, err := Run(conf, args)
   403  	if err != nil {
   404  		return fmt.Errorf("running container: %v", err)
   405  	}
   406  	if !ws.Exited() || ws.ExitStatus() != 0 {
   407  		return fmt.Errorf("container failed, waitStatus: %v", ws)
   408  	}
   409  	return nil
   410  }
   411  
   412  // platforms must be provided by the BUILD rule, or all platforms are included.
   413  var platforms = flag.String("test_platforms", os.Getenv("TEST_PLATFORMS"), "Platforms to test with.")
   414  
   415  // configs generates different configurations to run tests.
   416  func configs(t *testing.T, noOverlay bool) map[string]*config.Config {
   417  	var ps []string
   418  	if *platforms == "" {
   419  		ps = platform.List()
   420  	} else {
   421  		ps = strings.Split(*platforms, ",")
   422  	}
   423  
   424  	// Non-overlay versions.
   425  	cs := make(map[string]*config.Config)
   426  	for _, p := range ps {
   427  		c := testutil.TestConfig(t)
   428  		c.Overlay2.Set("none")
   429  		c.Platform = p
   430  		cs[p] = c
   431  	}
   432  
   433  	// Overlay versions.
   434  	if !noOverlay {
   435  		for _, p := range ps {
   436  			c := testutil.TestConfig(t)
   437  			c.Platform = p
   438  			c.Overlay2.Set("all:memory")
   439  			cs[p+"-overlay"] = c
   440  		}
   441  	}
   442  
   443  	return cs
   444  }
   445  
   446  // sleepSpec generates a spec with sleep 1000 and a conf.
   447  func sleepSpecConf(t *testing.T) (*specs.Spec, *config.Config) {
   448  	return testutil.NewSpecWithArgs("sleep", "1000"), testutil.TestConfig(t)
   449  }
   450  
   451  // TestLifecycle tests the basic Create/Start/Signal/Destroy container lifecycle.
   452  // It verifies after each step that the container can be loaded from disk, and
   453  // has the correct status.
   454  func TestLifecycle(t *testing.T) {
   455  	// Start the child reaper.
   456  	childReaper := &testutil.Reaper{}
   457  	childReaper.Start()
   458  	defer childReaper.Stop()
   459  
   460  	for name, conf := range configs(t, false /* noOverlay */) {
   461  		t.Run(name, func(t *testing.T) {
   462  			// The container will just sleep for a long time.  We will kill it before
   463  			// it finishes sleeping.
   464  			spec, _ := sleepSpecConf(t)
   465  
   466  			rootDir, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
   467  			if err != nil {
   468  				t.Fatalf("error setting up container: %v", err)
   469  			}
   470  			defer cleanup()
   471  
   472  			// expectedPL lists the expected process state of the container.
   473  			expectedPL := []*control.Process{
   474  				newProcessBuilder().Cmd("sleep").Process(),
   475  			}
   476  			// Create the container.
   477  			args := Args{
   478  				ID:        testutil.RandomContainerID(),
   479  				Spec:      spec,
   480  				BundleDir: bundleDir,
   481  			}
   482  			c, err := New(conf, args)
   483  			if err != nil {
   484  				t.Fatalf("error creating container: %v", err)
   485  			}
   486  			defer c.Destroy()
   487  
   488  			// Load the container from disk and check the status.
   489  			c, err = Load(rootDir, FullID{ContainerID: args.ID}, LoadOpts{})
   490  			if err != nil {
   491  				t.Fatalf("error loading container: %v", err)
   492  			}
   493  			if got, want := c.Status, Created; got != want {
   494  				t.Errorf("container status got %v, want %v", got, want)
   495  			}
   496  
   497  			// List should return the container id.
   498  			ids, err := List(rootDir)
   499  			if err != nil {
   500  				t.Fatalf("error listing containers: %v", err)
   501  			}
   502  			fullID := FullID{
   503  				SandboxID:   args.ID,
   504  				ContainerID: args.ID,
   505  			}
   506  			if got, want := ids, []FullID{fullID}; !slices.Equal(got, want) {
   507  				t.Errorf("container list got %v, want %v", got, want)
   508  			}
   509  
   510  			// Start the container.
   511  			if err := c.Start(conf); err != nil {
   512  				t.Fatalf("error starting container: %v", err)
   513  			}
   514  
   515  			// Load the container from disk and check the status.
   516  			c, err = Load(rootDir, fullID, LoadOpts{Exact: true})
   517  			if err != nil {
   518  				t.Fatalf("error loading container: %v", err)
   519  			}
   520  			if got, want := c.Status, Running; got != want {
   521  				t.Errorf("container status got %v, want %v", got, want)
   522  			}
   523  
   524  			// Verify that "sleep 100" is running.
   525  			if err := waitForProcessList(c, expectedPL); err != nil {
   526  				t.Error(err)
   527  			}
   528  
   529  			// Wait on the container.
   530  			ch := make(chan error)
   531  			go func() {
   532  				ws, err := c.Wait()
   533  				if err != nil {
   534  					ch <- err
   535  					return
   536  				}
   537  				if got, want := ws.Signal(), unix.SIGTERM; got != want {
   538  					ch <- fmt.Errorf("got signal %v, want %v", got, want)
   539  					return
   540  				}
   541  				ch <- nil
   542  			}()
   543  
   544  			// Wait a bit to ensure that we've started waiting on
   545  			// the container before we signal.
   546  			time.Sleep(time.Second)
   547  
   548  			// Send the container a SIGTERM which will cause it to stop.
   549  			if err := c.SignalContainer(unix.SIGTERM, false); err != nil {
   550  				t.Fatalf("error sending signal %v to container: %v", unix.SIGTERM, err)
   551  			}
   552  
   553  			// Wait for it to die.
   554  			if err := <-ch; err != nil {
   555  				t.Fatalf("error waiting for container: %v", err)
   556  			}
   557  
   558  			// Load the container from disk and check the status.
   559  			c, err = Load(rootDir, fullID, LoadOpts{Exact: true})
   560  			if err != nil {
   561  				t.Fatalf("error loading container: %v", err)
   562  			}
   563  			if got, want := c.Status, Stopped; got != want {
   564  				t.Errorf("container status got %v, want %v", got, want)
   565  			}
   566  
   567  			// Destroy the container.
   568  			if err := c.Destroy(); err != nil {
   569  				t.Fatalf("error destroying container: %v", err)
   570  			}
   571  
   572  			// List should not return the container id.
   573  			ids, err = List(rootDir)
   574  			if err != nil {
   575  				t.Fatalf("error listing containers: %v", err)
   576  			}
   577  			if len(ids) != 0 {
   578  				t.Errorf("expected container list to be empty, but got %v", ids)
   579  			}
   580  
   581  			// Loading the container by id should fail.
   582  			if _, err = Load(rootDir, fullID, LoadOpts{Exact: true}); err == nil {
   583  				t.Errorf("expected loading destroyed container to fail, but it did not")
   584  			}
   585  		})
   586  	}
   587  }
   588  
   589  // Test the we can execute the application with different path formats.
   590  func TestExePath(t *testing.T) {
   591  	// Create two directories that will be prepended to PATH.
   592  	firstPath, err := ioutil.TempDir(testutil.TmpDir(), "first")
   593  	if err != nil {
   594  		t.Fatalf("error creating temporary directory: %v", err)
   595  	}
   596  	defer os.RemoveAll(firstPath)
   597  	secondPath, err := ioutil.TempDir(testutil.TmpDir(), "second")
   598  	if err != nil {
   599  		t.Fatalf("error creating temporary directory: %v", err)
   600  	}
   601  	defer os.RemoveAll(secondPath)
   602  
   603  	// Create two minimal executables in the second path, two of which
   604  	// will be masked by files in first path.
   605  	for _, p := range []string{"unmasked", "masked1", "masked2"} {
   606  		path := filepath.Join(secondPath, p)
   607  		f, err := os.OpenFile(path, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0777)
   608  		if err != nil {
   609  			t.Fatalf("error opening path: %v", err)
   610  		}
   611  		defer f.Close()
   612  		if _, err := io.WriteString(f, "#!/bin/true\n"); err != nil {
   613  			t.Fatalf("error writing contents: %v", err)
   614  		}
   615  	}
   616  
   617  	// Create a non-executable file in the first path which masks a healthy
   618  	// executable in the second.
   619  	nonExecutable := filepath.Join(firstPath, "masked1")
   620  	f2, err := os.OpenFile(nonExecutable, os.O_CREATE|os.O_EXCL, 0666)
   621  	if err != nil {
   622  		t.Fatalf("error opening file: %v", err)
   623  	}
   624  	f2.Close()
   625  
   626  	// Create a non-regular file in the first path which masks a healthy
   627  	// executable in the second.
   628  	nonRegular := filepath.Join(firstPath, "masked2")
   629  	if err := os.Mkdir(nonRegular, 0777); err != nil {
   630  		t.Fatalf("error making directory: %v", err)
   631  	}
   632  
   633  	defaultConf := testutil.TestConfig(t)
   634  	defaultConf.Overlay2.Set("none")
   635  	overlayConf := testutil.TestConfig(t)
   636  	overlayConf.Overlay2.Set("all:memory")
   637  	configs := map[string]*config.Config{
   638  		"default": defaultConf,
   639  		"overlay": overlayConf,
   640  	}
   641  
   642  	for name, conf := range configs {
   643  		t.Run(name, func(t *testing.T) {
   644  			for _, test := range []struct {
   645  				path    string
   646  				success bool
   647  			}{
   648  				{path: "true", success: true},
   649  				{path: "bin/true", success: true},
   650  				{path: "/bin/true", success: true},
   651  				{path: "thisfiledoesntexit", success: false},
   652  				{path: "bin/thisfiledoesntexit", success: false},
   653  				{path: "/bin/thisfiledoesntexit", success: false},
   654  
   655  				{path: "unmasked", success: true},
   656  				{path: filepath.Join(firstPath, "unmasked"), success: false},
   657  				{path: filepath.Join(secondPath, "unmasked"), success: true},
   658  
   659  				{path: "masked1", success: true},
   660  				{path: filepath.Join(firstPath, "masked1"), success: false},
   661  				{path: filepath.Join(secondPath, "masked1"), success: true},
   662  
   663  				{path: "masked2", success: true},
   664  				{path: filepath.Join(firstPath, "masked2"), success: false},
   665  				{path: filepath.Join(secondPath, "masked2"), success: true},
   666  			} {
   667  				name := fmt.Sprintf("path=%s,success=%t", test.path, test.success)
   668  				t.Run(name, func(t *testing.T) {
   669  					spec := testutil.NewSpecWithArgs(test.path)
   670  					spec.Process.Env = []string{
   671  						fmt.Sprintf("PATH=%s:%s:%s", firstPath, secondPath, os.Getenv("PATH")),
   672  					}
   673  
   674  					err := run(spec, conf)
   675  					if test.success {
   676  						if err != nil {
   677  							t.Errorf("exec: error running container: %v", err)
   678  						}
   679  					} else if err == nil {
   680  						t.Errorf("exec: got: no error, want: error")
   681  					}
   682  				})
   683  			}
   684  		})
   685  	}
   686  }
   687  
   688  // Test the we can retrieve the application exit status from the container.
   689  func TestAppExitStatus(t *testing.T) {
   690  	// First container will succeed.
   691  	succSpec := testutil.NewSpecWithArgs("true")
   692  	conf := testutil.TestConfig(t)
   693  	_, bundleDir, cleanup, err := testutil.SetupContainer(succSpec, conf)
   694  	if err != nil {
   695  		t.Fatalf("error setting up container: %v", err)
   696  	}
   697  	defer cleanup()
   698  
   699  	args := Args{
   700  		ID:        testutil.RandomContainerID(),
   701  		Spec:      succSpec,
   702  		BundleDir: bundleDir,
   703  		Attached:  true,
   704  	}
   705  	ws, err := Run(conf, args)
   706  	if err != nil {
   707  		t.Fatalf("error running container: %v", err)
   708  	}
   709  	if ws.ExitStatus() != 0 {
   710  		t.Errorf("got exit status %v want %v", ws.ExitStatus(), 0)
   711  	}
   712  
   713  	// Second container exits with non-zero status.
   714  	wantStatus := 123
   715  	errSpec := testutil.NewSpecWithArgs("bash", "-c", fmt.Sprintf("exit %d", wantStatus))
   716  
   717  	_, bundleDir2, cleanup2, err := testutil.SetupContainer(errSpec, conf)
   718  	if err != nil {
   719  		t.Fatalf("error setting up container: %v", err)
   720  	}
   721  	defer cleanup2()
   722  
   723  	args2 := Args{
   724  		ID:        testutil.RandomContainerID(),
   725  		Spec:      errSpec,
   726  		BundleDir: bundleDir2,
   727  		Attached:  true,
   728  	}
   729  	ws, err = Run(conf, args2)
   730  	if err != nil {
   731  		t.Fatalf("error running container: %v", err)
   732  	}
   733  	if ws.ExitStatus() != wantStatus {
   734  		t.Errorf("got exit status %v want %v", ws.ExitStatus(), wantStatus)
   735  	}
   736  }
   737  
   738  // TestExec verifies that a container can exec a new program.
   739  func TestExec(t *testing.T) {
   740  	for name, conf := range configs(t, false /* noOverlay */) {
   741  		t.Run(name, func(t *testing.T) {
   742  			dir, err := ioutil.TempDir(testutil.TmpDir(), "exec-test")
   743  			if err != nil {
   744  				t.Fatalf("error creating temporary directory: %v", err)
   745  			}
   746  			// Note that some shells may exec the final command in a sequence as
   747  			// an optimization. We avoid this here by adding the exit 0.
   748  			cmd := fmt.Sprintf("ln -s /bin/true %q/symlink && sleep 100 && exit 0", dir)
   749  			spec := testutil.NewSpecWithArgs("sh", "-c", cmd)
   750  
   751  			_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
   752  			if err != nil {
   753  				t.Fatalf("error setting up container: %v", err)
   754  			}
   755  			defer cleanup()
   756  
   757  			// Create and start the container.
   758  			args := Args{
   759  				ID:        testutil.RandomContainerID(),
   760  				Spec:      spec,
   761  				BundleDir: bundleDir,
   762  			}
   763  			cont, err := New(conf, args)
   764  			if err != nil {
   765  				t.Fatalf("error creating container: %v", err)
   766  			}
   767  			defer cont.Destroy()
   768  			if err := cont.Start(conf); err != nil {
   769  				t.Fatalf("error starting container: %v", err)
   770  			}
   771  
   772  			// Wait until sleep is running to ensure the symlink was created.
   773  			expectedPL := []*control.Process{
   774  				newProcessBuilder().Cmd("sh").Process(),
   775  				newProcessBuilder().Cmd("sleep").Process(),
   776  			}
   777  			if err := waitForProcessList(cont, expectedPL); err != nil {
   778  				t.Fatalf("waitForProcessList: %v", err)
   779  			}
   780  
   781  			for _, tc := range []struct {
   782  				name string
   783  				args control.ExecArgs
   784  			}{
   785  				{
   786  					name: "complete",
   787  					args: control.ExecArgs{
   788  						Filename: "/bin/true",
   789  						Argv:     []string{"/bin/true"},
   790  					},
   791  				},
   792  				{
   793  					name: "filename",
   794  					args: control.ExecArgs{
   795  						Filename: "/bin/true",
   796  					},
   797  				},
   798  				{
   799  					name: "argv",
   800  					args: control.ExecArgs{
   801  						Argv: []string{"/bin/true"},
   802  					},
   803  				},
   804  				{
   805  					name: "filename resolution",
   806  					args: control.ExecArgs{
   807  						Filename: "true",
   808  						Envv:     []string{"PATH=/bin"},
   809  					},
   810  				},
   811  				{
   812  					name: "argv resolution",
   813  					args: control.ExecArgs{
   814  						Argv: []string{"true"},
   815  						Envv: []string{"PATH=/bin"},
   816  					},
   817  				},
   818  				{
   819  					name: "argv symlink",
   820  					args: control.ExecArgs{
   821  						Argv: []string{filepath.Join(dir, "symlink")},
   822  					},
   823  				},
   824  				{
   825  					name: "working dir",
   826  					args: control.ExecArgs{
   827  						Argv:             []string{"/bin/sh", "-c", `if [[ "${PWD}" != "/tmp" ]]; then exit 1; fi`},
   828  						WorkingDirectory: "/tmp",
   829  					},
   830  				},
   831  				{
   832  					name: "user",
   833  					args: control.ExecArgs{
   834  						Argv: []string{"/bin/sh", "-c", `if [[ "$(id -u)" != "343" ]]; then exit 1; fi`},
   835  						KUID: 343,
   836  					},
   837  				},
   838  				{
   839  					name: "group",
   840  					args: control.ExecArgs{
   841  						Argv: []string{"/bin/sh", "-c", `if [[ "$(id -g)" != "343" ]]; then exit 1; fi`},
   842  						KGID: 343,
   843  					},
   844  				},
   845  				{
   846  					name: "env",
   847  					args: control.ExecArgs{
   848  						Argv: []string{"/bin/sh", "-c", `if [[ "${FOO}" != "123" ]]; then exit 1; fi`},
   849  						Envv: []string{"FOO=123"},
   850  					},
   851  				},
   852  			} {
   853  				t.Run(tc.name, func(t *testing.T) {
   854  					// t.Parallel()
   855  					if ws, err := cont.executeSync(conf, &tc.args); err != nil {
   856  						t.Fatalf("executeAsync(%+v): %v", tc.args, err)
   857  					} else if ws != 0 {
   858  						t.Fatalf("executeAsync(%+v) failed with exit: %v", tc.args, ws)
   859  					}
   860  				})
   861  			}
   862  
   863  			// Test for exec failure with an non-existent file.
   864  			t.Run("nonexist", func(t *testing.T) {
   865  				// b/179114837 found by Syzkaller that causes nil pointer panic when
   866  				// trying to dec-ref an unix socket FD.
   867  				fds, err := unix.Socketpair(unix.AF_UNIX, unix.SOCK_STREAM, 0)
   868  				if err != nil {
   869  					t.Fatal(err)
   870  				}
   871  				defer unix.Close(fds[0])
   872  
   873  				_, err = cont.executeSync(conf, &control.ExecArgs{
   874  					Argv: []string{"/nonexist"},
   875  					FilePayload: control.NewFilePayload(map[int]*os.File{
   876  						0: os.NewFile(uintptr(fds[1]), "sock"),
   877  					}, nil),
   878  				})
   879  				want := "failed to load /nonexist"
   880  				if err == nil || !strings.Contains(err.Error(), want) {
   881  					t.Errorf("executeSync: want err containing %q; got err = %q", want, err)
   882  				}
   883  			})
   884  		})
   885  	}
   886  }
   887  
   888  // TestExecProcList verifies that a container can exec a new program and it
   889  // shows correcly in the process list.
   890  func TestExecProcList(t *testing.T) {
   891  	for name, conf := range configs(t, false /* noOverlay */) {
   892  		t.Run(name, func(t *testing.T) {
   893  			const uid = 343
   894  			spec, _ := sleepSpecConf(t)
   895  
   896  			_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
   897  			if err != nil {
   898  				t.Fatalf("error setting up container: %v", err)
   899  			}
   900  			defer cleanup()
   901  
   902  			// Create and start the container.
   903  			args := Args{
   904  				ID:        testutil.RandomContainerID(),
   905  				Spec:      spec,
   906  				BundleDir: bundleDir,
   907  			}
   908  			cont, err := New(conf, args)
   909  			if err != nil {
   910  				t.Fatalf("error creating container: %v", err)
   911  			}
   912  			defer cont.Destroy()
   913  			if err := cont.Start(conf); err != nil {
   914  				t.Fatalf("error starting container: %v", err)
   915  			}
   916  
   917  			execArgs := &control.ExecArgs{
   918  				Filename:         "/bin/sleep",
   919  				Argv:             []string{"/bin/sleep", "5"},
   920  				WorkingDirectory: "/",
   921  				KUID:             uid,
   922  			}
   923  
   924  			// Verify that "sleep 100" and "sleep 5" are running after exec. First,
   925  			// start running exec (which blocks).
   926  			ch := make(chan error)
   927  			go func() {
   928  				exitStatus, err := cont.executeSync(conf, execArgs)
   929  				if err != nil {
   930  					ch <- err
   931  				} else if exitStatus != 0 {
   932  					ch <- fmt.Errorf("failed with exit status: %v", exitStatus)
   933  				} else {
   934  					ch <- nil
   935  				}
   936  			}()
   937  
   938  			// expectedPL lists the expected process state of the container.
   939  			expectedPL := []*control.Process{
   940  				newProcessBuilder().PID(1).PPID(0).Cmd("sleep").UID(0).Process(),
   941  				newProcessBuilder().PID(2).PPID(0).Cmd("sleep").UID(uid).Process(),
   942  			}
   943  			if err := waitForProcessList(cont, expectedPL); err != nil {
   944  				t.Fatalf("error waiting for processes: %v", err)
   945  			}
   946  		})
   947  	}
   948  }
   949  
   950  // TestKillPid verifies that we can signal individual exec'd processes.
   951  func TestKillPid(t *testing.T) {
   952  	for name, conf := range configs(t, false /* noOverlay */) {
   953  		t.Run(name, func(t *testing.T) {
   954  			app, err := testutil.FindFile("test/cmd/test_app/test_app")
   955  			if err != nil {
   956  				t.Fatal("error finding test_app:", err)
   957  			}
   958  
   959  			const nProcs = 4
   960  			spec := testutil.NewSpecWithArgs(app, "task-tree", "--depth", strconv.Itoa(nProcs-1), "--width=1", "--pause=true")
   961  			_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
   962  			if err != nil {
   963  				t.Fatalf("error setting up container: %v", err)
   964  			}
   965  			defer cleanup()
   966  
   967  			// Create and start the container.
   968  			args := Args{
   969  				ID:        testutil.RandomContainerID(),
   970  				Spec:      spec,
   971  				BundleDir: bundleDir,
   972  			}
   973  			cont, err := New(conf, args)
   974  			if err != nil {
   975  				t.Fatalf("error creating container: %v", err)
   976  			}
   977  			defer cont.Destroy()
   978  			if err := cont.Start(conf); err != nil {
   979  				t.Fatalf("error starting container: %v", err)
   980  			}
   981  
   982  			// Verify that all processes are running.
   983  			if err := waitForProcessCount(cont, nProcs); err != nil {
   984  				t.Fatalf("timed out waiting for processes to start: %v", err)
   985  			}
   986  
   987  			// Kill the child process with the largest PID.
   988  			procs, err := cont.Processes()
   989  			if err != nil {
   990  				t.Fatalf("failed to get process list: %v", err)
   991  			}
   992  			t.Logf("current process list: %v", procs)
   993  			var pid int32
   994  			for _, p := range procs {
   995  				if pid < int32(p.PID) {
   996  					pid = int32(p.PID)
   997  				}
   998  			}
   999  			if err := cont.SignalProcess(unix.SIGKILL, pid); err != nil {
  1000  				t.Fatalf("failed to signal process %d: %v", pid, err)
  1001  			}
  1002  
  1003  			// Verify that one process is gone.
  1004  			if err := waitForProcessCount(cont, nProcs-1); err != nil {
  1005  				procs, procsErr := cont.Processes()
  1006  				t.Fatalf("error waiting for processes: %v; current processes: %v / %v", err, procs, procsErr)
  1007  			}
  1008  
  1009  			procs, err = cont.Processes()
  1010  			if err != nil {
  1011  				t.Fatalf("failed to get process list: %v", err)
  1012  			}
  1013  			for _, p := range procs {
  1014  				if pid == int32(p.PID) {
  1015  					t.Fatalf("pid %d is still alive, which should be killed", pid)
  1016  				}
  1017  			}
  1018  		})
  1019  	}
  1020  }
  1021  
  1022  // testCheckpointRestore creates a container that continuously writes successive
  1023  // integers to a file. To test checkpoint and restore functionality, the
  1024  // container is checkpointed and the last number printed to the file is
  1025  // recorded. Then, it is restored in two new containers and the first number
  1026  // printed from these containers is checked. Both should be the next consecutive
  1027  // number after the last number from the checkpointed container.
  1028  func testCheckpointRestore(t *testing.T, conf *config.Config, compression statefile.CompressionLevel, newSpecWithScript func(string) *specs.Spec) {
  1029  	dir, err := ioutil.TempDir(testutil.TmpDir(), "checkpoint-test")
  1030  	if err != nil {
  1031  		t.Fatalf("ioutil.TempDir failed: %v", err)
  1032  	}
  1033  	defer os.RemoveAll(dir)
  1034  	if err := os.Chmod(dir, 0777); err != nil {
  1035  		t.Fatalf("error chmoding file: %q, %v", dir, err)
  1036  	}
  1037  
  1038  	outputPath := filepath.Join(dir, "output")
  1039  	outputFile, err := createWriteableOutputFile(outputPath)
  1040  	if err != nil {
  1041  		t.Fatalf("error creating output file: %v", err)
  1042  	}
  1043  	defer outputFile.Close()
  1044  
  1045  	script := fmt.Sprintf("i=0; while true; do echo $i >> %q; sleep 1; i=$((i+1)); done", outputPath)
  1046  	spec := newSpecWithScript(script)
  1047  	_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  1048  	if err != nil {
  1049  		t.Fatalf("error setting up container: %v", err)
  1050  	}
  1051  	defer cleanup()
  1052  
  1053  	// Create and start the container.
  1054  	args := Args{
  1055  		ID:        testutil.RandomContainerID(),
  1056  		Spec:      spec,
  1057  		BundleDir: bundleDir,
  1058  	}
  1059  	cont, err := New(conf, args)
  1060  	if err != nil {
  1061  		t.Fatalf("error creating container: %v", err)
  1062  	}
  1063  	defer cont.Destroy()
  1064  	if err := cont.Start(conf); err != nil {
  1065  		t.Fatalf("error starting container: %v", err)
  1066  	}
  1067  
  1068  	// Wait until application has ran.
  1069  	if err := waitForFileNotEmpty(outputFile); err != nil {
  1070  		t.Fatalf("Failed to wait for output file: %v", err)
  1071  	}
  1072  
  1073  	// Checkpoint running container; save state into new file.
  1074  	if err := cont.Checkpoint(dir, false /* direct */, statefile.Options{Compression: compression}, pgalloc.SaveOpts{}); err != nil {
  1075  		t.Fatalf("error checkpointing container to empty file: %v", err)
  1076  	}
  1077  
  1078  	lastNum, err := readOutputNum(outputPath, -1)
  1079  	if err != nil {
  1080  		t.Fatalf("error with outputFile: %v", err)
  1081  	}
  1082  
  1083  	// Delete and recreate file before restoring.
  1084  	if err := os.Remove(outputPath); err != nil {
  1085  		t.Fatalf("error removing file")
  1086  	}
  1087  	outputFile2, err := createWriteableOutputFile(outputPath)
  1088  	if err != nil {
  1089  		t.Fatalf("error creating output file: %v", err)
  1090  	}
  1091  	defer outputFile2.Close()
  1092  
  1093  	// Restore into a new container with different ID (e.g. clone). Keep the
  1094  	// initial container running to ensure no conflict with it.
  1095  	args2 := Args{
  1096  		ID:        testutil.RandomContainerID(),
  1097  		Spec:      spec,
  1098  		BundleDir: bundleDir,
  1099  	}
  1100  	cont2, err := New(conf, args2)
  1101  	if err != nil {
  1102  		t.Fatalf("error creating container: %v", err)
  1103  	}
  1104  	defer cont2.Destroy()
  1105  
  1106  	if err := cont2.Restore(conf, dir, false /* direct */); err != nil {
  1107  		t.Fatalf("error restoring container: %v", err)
  1108  	}
  1109  
  1110  	// Wait until application has ran.
  1111  	if err := waitForFileNotEmpty(outputFile2); err != nil {
  1112  		t.Fatalf("Failed to wait for output file: %v", err)
  1113  	}
  1114  
  1115  	firstNum, err := readOutputNum(outputPath, 0)
  1116  	if err != nil {
  1117  		t.Fatalf("error with outputFile: %v", err)
  1118  	}
  1119  
  1120  	// Check that lastNum is one less than firstNum and that the container
  1121  	// picks up from where it left off.
  1122  	if lastNum+1 != firstNum {
  1123  		t.Errorf("error numbers not in order, previous: %d, next: %d", lastNum, firstNum)
  1124  	}
  1125  	cont2.Destroy()
  1126  	cont2 = nil
  1127  
  1128  	// Restore into a container using the same ID (e.g. save/resume). It requires
  1129  	// the original container to cease to exist because they share the same identity.
  1130  	cont.Destroy()
  1131  	cont = nil
  1132  
  1133  	// Delete and recreate file before restoring.
  1134  	if err := os.Remove(outputPath); err != nil {
  1135  		t.Fatalf("error removing file")
  1136  	}
  1137  	outputFile3, err := createWriteableOutputFile(outputPath)
  1138  	if err != nil {
  1139  		t.Fatalf("error creating output file: %v", err)
  1140  	}
  1141  	defer outputFile3.Close()
  1142  
  1143  	cont3, err := New(conf, args)
  1144  	if err != nil {
  1145  		t.Fatalf("error creating container: %v", err)
  1146  	}
  1147  	defer cont3.Destroy()
  1148  
  1149  	if err := cont3.Restore(conf, dir, false /* direct */); err != nil {
  1150  		t.Fatalf("error restoring container: %v", err)
  1151  	}
  1152  
  1153  	// Wait until application has ran.
  1154  	if err := waitForFileNotEmpty(outputFile3); err != nil {
  1155  		t.Fatalf("Failed to wait for output file: %v", err)
  1156  	}
  1157  
  1158  	firstNum2, err := readOutputNum(outputPath, 0)
  1159  	if err != nil {
  1160  		t.Fatalf("error with outputFile: %v", err)
  1161  	}
  1162  
  1163  	// Check that lastNum is one less than firstNum and that the container
  1164  	// picks up from where it left off.
  1165  	if lastNum+1 != firstNum2 {
  1166  		t.Errorf("error numbers not in order, previous: %d, next: %d", lastNum, firstNum2)
  1167  	}
  1168  	cont3.Destroy()
  1169  }
  1170  
  1171  // TestCheckpointRestore does the checkpoint/restore test on each platform.
  1172  func TestCheckpointRestore(t *testing.T) {
  1173  	// Skip overlay because test requires writing to host file.
  1174  	for name, conf := range configs(t, true /* noOverlay */) {
  1175  		t.Run(name, func(t *testing.T) {
  1176  			compressionLevels := []statefile.CompressionLevel{
  1177  				statefile.CompressionLevelNone,
  1178  				statefile.CompressionLevelFlateBestSpeed,
  1179  			}
  1180  			for _, compression := range compressionLevels {
  1181  				t.Run(string(compression), func(t *testing.T) {
  1182  					testCheckpointRestore(t, conf, compression, func(script string) *specs.Spec {
  1183  						return testutil.NewSpecWithArgs("bash", "-c", script)
  1184  					})
  1185  				})
  1186  			}
  1187  		})
  1188  	}
  1189  }
  1190  
  1191  // TestCheckpointRestoreExecKilled checks that exec'd processes are killed
  1192  // after the container is restored.
  1193  func TestCheckpointRestoreExecKilled(t *testing.T) {
  1194  	spec, conf := sleepSpecConf(t)
  1195  	_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  1196  	if err != nil {
  1197  		t.Fatalf("error setting up container: %v", err)
  1198  	}
  1199  	defer cleanup()
  1200  
  1201  	// Create and start the container.
  1202  	args := Args{
  1203  		ID:        testutil.RandomContainerID(),
  1204  		Spec:      spec,
  1205  		BundleDir: bundleDir,
  1206  	}
  1207  	cont, err := New(conf, args)
  1208  	if err != nil {
  1209  		t.Fatalf("error creating container: %v", err)
  1210  	}
  1211  	defer cont.Destroy()
  1212  	if err := cont.Start(conf); err != nil {
  1213  		t.Fatalf("error starting container: %v", err)
  1214  	}
  1215  
  1216  	execArgs := &control.ExecArgs{
  1217  		Filename: "/bin/sleep",
  1218  		Argv:     []string{"/bin/sleep", "10000"},
  1219  	}
  1220  	pid1, err := cont.Execute(conf, execArgs)
  1221  	if err != nil {
  1222  		t.Fatalf("error executing in container: %v", err)
  1223  	}
  1224  	pid2, err := cont.Execute(conf, execArgs)
  1225  	if err != nil {
  1226  		t.Fatalf("error executing in container: %v", err)
  1227  	}
  1228  
  1229  	// Since both share the same process name, ensure that the exec'd process
  1230  	// has a different PID than the init process.
  1231  	if pid1 == 1 || pid2 == 1 {
  1232  		t.Fatalf("exec'd PID cannot be 1")
  1233  	}
  1234  	// Wait until the init process and exec'd processes are present.
  1235  	expectedPL := []*control.Process{
  1236  		newProcessBuilder().Cmd("sleep").PID(1).Process(),
  1237  		newProcessBuilder().Cmd("sleep").PID(kernel.ThreadID(pid1)).Process(),
  1238  		newProcessBuilder().Cmd("sleep").PID(kernel.ThreadID(pid2)).Process(),
  1239  	}
  1240  	if err := waitForProcessList(cont, expectedPL); err != nil {
  1241  		t.Fatalf("Failed to kill exec'ed process, err: %v", err)
  1242  	}
  1243  
  1244  	// Set the image path, which is where the checkpoint image will be saved.
  1245  	dir, err := ioutil.TempDir(testutil.TmpDir(), "checkpoint-test")
  1246  	if err != nil {
  1247  		t.Fatalf("ioutil.TempDir failed: %v", err)
  1248  	}
  1249  	defer os.RemoveAll(dir)
  1250  	if err := os.Chmod(dir, 0777); err != nil {
  1251  		t.Fatalf("error chmoding file: %q, %v", dir, err)
  1252  	}
  1253  
  1254  	// Checkpoint running container.
  1255  	if err := cont.Checkpoint(dir, false /* direct */, statefile.Options{Compression: statefile.CompressionLevelFlateBestSpeed}, pgalloc.SaveOpts{}); err != nil {
  1256  		t.Fatalf("error checkpointing container: %v", err)
  1257  	}
  1258  	cont.Destroy()
  1259  	cont = nil
  1260  
  1261  	cont2, err := New(conf, args)
  1262  	if err != nil {
  1263  		t.Fatalf("error creating container: %v", err)
  1264  	}
  1265  	defer cont2.Destroy()
  1266  
  1267  	if err := cont2.Restore(conf, dir, false /* direct */); err != nil {
  1268  		t.Fatalf("error restoring container: %v", err)
  1269  	}
  1270  
  1271  	// Check that only the init process is present and the exec'ed
  1272  	// processes were killed.
  1273  	expectedPL = []*control.Process{
  1274  		newProcessBuilder().Cmd("sleep").PID(1).Process(),
  1275  	}
  1276  	if err := waitForProcessList(cont2, expectedPL); err != nil {
  1277  		t.Fatalf("Failed to kill exec'ed process, err: %v", err)
  1278  	}
  1279  }
  1280  
  1281  // TestUnixDomainSockets checks that Checkpoint/Restore works in cases
  1282  // with filesystem Unix Domain Socket use.
  1283  func TestUnixDomainSockets(t *testing.T) {
  1284  	// Skip overlay because test requires writing to host file.
  1285  	for name, conf := range configs(t, true /* noOverlay */) {
  1286  		t.Run(name, func(t *testing.T) {
  1287  			// UDS path is limited to 108 chars for compatibility with older systems.
  1288  			// Use '/tmp' (instead of testutil.TmpDir) to ensure the size limit is
  1289  			// not exceeded. Assumes '/tmp' exists in the system.
  1290  			dir, err := ioutil.TempDir("/tmp", "uds-test")
  1291  			if err != nil {
  1292  				t.Fatalf("ioutil.TempDir failed: %v", err)
  1293  			}
  1294  			defer os.RemoveAll(dir)
  1295  
  1296  			outputPath := filepath.Join(dir, "uds_output")
  1297  			outputFile, err := os.OpenFile(outputPath, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666)
  1298  			if err != nil {
  1299  				t.Fatalf("error creating output file: %v", err)
  1300  			}
  1301  			defer outputFile.Close()
  1302  
  1303  			app, err := testutil.FindFile("test/cmd/test_app/test_app")
  1304  			if err != nil {
  1305  				t.Fatal("error finding test_app:", err)
  1306  			}
  1307  
  1308  			socketPath := filepath.Join(dir, "uds_socket")
  1309  			defer os.Remove(socketPath)
  1310  
  1311  			spec := testutil.NewSpecWithArgs(app, "uds", "--file", outputPath, "--socket", socketPath)
  1312  			spec.Process.User = specs.User{
  1313  				UID: uint32(os.Getuid()),
  1314  				GID: uint32(os.Getgid()),
  1315  			}
  1316  			spec.Mounts = []specs.Mount{{
  1317  				Type:        "bind",
  1318  				Destination: dir,
  1319  				Source:      dir,
  1320  			}}
  1321  
  1322  			_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  1323  			if err != nil {
  1324  				t.Fatalf("error setting up container: %v", err)
  1325  			}
  1326  			defer cleanup()
  1327  
  1328  			// Create and start the container.
  1329  			args := Args{
  1330  				ID:        testutil.RandomContainerID(),
  1331  				Spec:      spec,
  1332  				BundleDir: bundleDir,
  1333  			}
  1334  			cont, err := New(conf, args)
  1335  			if err != nil {
  1336  				t.Fatalf("error creating container: %v", err)
  1337  			}
  1338  			defer cont.Destroy()
  1339  			if err := cont.Start(conf); err != nil {
  1340  				t.Fatalf("error starting container: %v", err)
  1341  			}
  1342  
  1343  			// Wait until application has ran.
  1344  			if err := waitForFileNotEmpty(outputFile); err != nil {
  1345  				t.Fatalf("Failed to wait for output file: %v", err)
  1346  			}
  1347  
  1348  			// Checkpoint running container; save state into new file.
  1349  			if err := cont.Checkpoint(dir, false /* direct */, statefile.Options{Compression: statefile.CompressionLevelDefault}, pgalloc.SaveOpts{}); err != nil {
  1350  				t.Fatalf("error checkpointing container to empty file: %v", err)
  1351  			}
  1352  
  1353  			// Read last number outputted before checkpoint.
  1354  			lastNum, err := readOutputNum(outputPath, -1)
  1355  			if err != nil {
  1356  				t.Fatalf("error with outputFile: %v", err)
  1357  			}
  1358  
  1359  			// Delete and recreate file before restoring.
  1360  			if err := os.Remove(outputPath); err != nil {
  1361  				t.Fatalf("error removing file")
  1362  			}
  1363  			outputFile2, err := os.OpenFile(outputPath, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666)
  1364  			if err != nil {
  1365  				t.Fatalf("error creating output file: %v", err)
  1366  			}
  1367  			defer outputFile2.Close()
  1368  
  1369  			// Restore into a new container.
  1370  			argsRestore := Args{
  1371  				ID:        testutil.RandomContainerID(),
  1372  				Spec:      spec,
  1373  				BundleDir: bundleDir,
  1374  			}
  1375  			contRestore, err := New(conf, argsRestore)
  1376  			if err != nil {
  1377  				t.Fatalf("error creating container: %v", err)
  1378  			}
  1379  			defer contRestore.Destroy()
  1380  
  1381  			if err := contRestore.Restore(conf, dir, false /* direct */); err != nil {
  1382  				t.Fatalf("error restoring container: %v", err)
  1383  			}
  1384  
  1385  			// Wait until application has ran.
  1386  			if err := waitForFileNotEmpty(outputFile2); err != nil {
  1387  				t.Fatalf("Failed to wait for output file: %v", err)
  1388  			}
  1389  
  1390  			// Read first number outputted after restore.
  1391  			firstNum, err := readOutputNum(outputPath, 0)
  1392  			if err != nil {
  1393  				t.Fatalf("error with outputFile: %v", err)
  1394  			}
  1395  
  1396  			// Check that lastNum is one less than firstNum.
  1397  			if lastNum+1 != firstNum {
  1398  				t.Errorf("error numbers not consecutive, previous: %d, next: %d", lastNum, firstNum)
  1399  			}
  1400  			contRestore.Destroy()
  1401  		})
  1402  	}
  1403  }
  1404  
  1405  // TestPauseResume tests that we can successfully pause and resume a container.
  1406  // The container will keep touching a file to indicate it's running. The test
  1407  // pauses the container, removes the file, and checks that it doesn't get
  1408  // recreated. Then it resumes the container, verify that the file gets created
  1409  // again.
  1410  func TestPauseResume(t *testing.T) {
  1411  	for name, conf := range configs(t, true /* noOverlay */) {
  1412  		t.Run(name, func(t *testing.T) {
  1413  			tmpDir, err := ioutil.TempDir(testutil.TmpDir(), "lock")
  1414  			if err != nil {
  1415  				t.Fatalf("error creating temp dir: %v", err)
  1416  			}
  1417  			defer os.RemoveAll(tmpDir)
  1418  
  1419  			running := path.Join(tmpDir, "running")
  1420  			script := fmt.Sprintf("while [[ true ]]; do touch %q; sleep 0.1; done", running)
  1421  			spec := testutil.NewSpecWithArgs("/bin/bash", "-c", script)
  1422  
  1423  			_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  1424  			if err != nil {
  1425  				t.Fatalf("error setting up container: %v", err)
  1426  			}
  1427  			defer cleanup()
  1428  
  1429  			// Create and start the container.
  1430  			args := Args{
  1431  				ID:        testutil.RandomContainerID(),
  1432  				Spec:      spec,
  1433  				BundleDir: bundleDir,
  1434  			}
  1435  			cont, err := New(conf, args)
  1436  			if err != nil {
  1437  				t.Fatalf("error creating container: %v", err)
  1438  			}
  1439  			defer cont.Destroy()
  1440  			if err := cont.Start(conf); err != nil {
  1441  				t.Fatalf("error starting container: %v", err)
  1442  			}
  1443  
  1444  			// Wait until container starts running, observed by the existence of running
  1445  			// file.
  1446  			if err := waitForFileExist(running); err != nil {
  1447  				t.Errorf("error waiting for container to start: %v", err)
  1448  			}
  1449  
  1450  			// Pause the running container.
  1451  			if err := cont.Pause(); err != nil {
  1452  				t.Errorf("error pausing container: %v", err)
  1453  			}
  1454  			if got, want := cont.Status, Paused; got != want {
  1455  				t.Errorf("container status got %v, want %v", got, want)
  1456  			}
  1457  
  1458  			if err := os.Remove(running); err != nil {
  1459  				t.Fatalf("os.Remove(%q) failed: %v", running, err)
  1460  			}
  1461  			// Script touches the file every 100ms. Give a bit a time for it to run to
  1462  			// catch the case that pause didn't work.
  1463  			time.Sleep(200 * time.Millisecond)
  1464  			if _, err := os.Stat(running); !os.IsNotExist(err) {
  1465  				t.Fatalf("container did not pause: file exist check: %v", err)
  1466  			}
  1467  
  1468  			// Resume the running container.
  1469  			if err := cont.Resume(); err != nil {
  1470  				t.Errorf("error pausing container: %v", err)
  1471  			}
  1472  			if got, want := cont.Status, Running; got != want {
  1473  				t.Errorf("container status got %v, want %v", got, want)
  1474  			}
  1475  
  1476  			// Verify that the file is once again created by container.
  1477  			if err := waitForFileExist(running); err != nil {
  1478  				t.Fatalf("error resuming container: file exist check: %v", err)
  1479  			}
  1480  		})
  1481  	}
  1482  }
  1483  
  1484  // TestPauseResumeStatus makes sure that the statuses are set correctly
  1485  // with calls to pause and resume and that pausing and resuming only
  1486  // occurs given the correct state.
  1487  func TestPauseResumeStatus(t *testing.T) {
  1488  	spec, conf := sleepSpecConf(t)
  1489  	_, 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  	// Pause the running container.
  1511  	if err := cont.Pause(); err != nil {
  1512  		t.Errorf("error pausing container: %v", err)
  1513  	}
  1514  	if got, want := cont.Status, Paused; got != want {
  1515  		t.Errorf("container status got %v, want %v", got, want)
  1516  	}
  1517  
  1518  	// Try to Pause again. Should cause error.
  1519  	if err := cont.Pause(); err == nil {
  1520  		t.Errorf("error pausing container that was already paused: %v", err)
  1521  	}
  1522  	if got, want := cont.Status, Paused; got != want {
  1523  		t.Errorf("container status got %v, want %v", got, want)
  1524  	}
  1525  
  1526  	// Resume the running container.
  1527  	if err := cont.Resume(); err != nil {
  1528  		t.Errorf("error resuming container: %v", err)
  1529  	}
  1530  	if got, want := cont.Status, Running; got != want {
  1531  		t.Errorf("container status got %v, want %v", got, want)
  1532  	}
  1533  
  1534  	// Try to resume again. Should cause error.
  1535  	if err := cont.Resume(); err == nil {
  1536  		t.Errorf("error resuming container already running: %v", err)
  1537  	}
  1538  	if got, want := cont.Status, Running; got != want {
  1539  		t.Errorf("container status got %v, want %v", got, want)
  1540  	}
  1541  }
  1542  
  1543  // TestCapabilities verifies that:
  1544  //   - Running exec as non-root UID and GID will result in an error (because the
  1545  //     executable file can't be read).
  1546  //   - Running exec as non-root with CAP_DAC_OVERRIDE succeeds because it skips
  1547  //     this check.
  1548  func TestCapabilities(t *testing.T) {
  1549  	// Pick uid/gid different than ours.
  1550  	uid := auth.KUID(os.Getuid() + 1)
  1551  	gid := auth.KGID(os.Getgid() + 1)
  1552  
  1553  	for name, conf := range configs(t, false /* noOverlay */) {
  1554  		t.Run(name, func(t *testing.T) {
  1555  			spec, _ := sleepSpecConf(t)
  1556  			rootDir, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  1557  			if err != nil {
  1558  				t.Fatalf("error setting up container: %v", err)
  1559  			}
  1560  			defer cleanup()
  1561  
  1562  			// Create and start the container.
  1563  			args := Args{
  1564  				ID:        testutil.RandomContainerID(),
  1565  				Spec:      spec,
  1566  				BundleDir: bundleDir,
  1567  			}
  1568  			cont, err := New(conf, args)
  1569  			if err != nil {
  1570  				t.Fatalf("error creating container: %v", err)
  1571  			}
  1572  			defer cont.Destroy()
  1573  			if err := cont.Start(conf); err != nil {
  1574  				t.Fatalf("error starting container: %v", err)
  1575  			}
  1576  
  1577  			// expectedPL lists the expected process state of the container.
  1578  			expectedPL := []*control.Process{
  1579  				newProcessBuilder().Cmd("sleep").Process(),
  1580  			}
  1581  			if err := waitForProcessList(cont, expectedPL); err != nil {
  1582  				t.Fatalf("Failed to wait for sleep to start, err: %v", err)
  1583  			}
  1584  
  1585  			// Create an executable that can't be run with the specified UID:GID.
  1586  			// This shouldn't be callable within the container until we add the
  1587  			// CAP_DAC_OVERRIDE capability to skip the access check.
  1588  			exePath := filepath.Join(rootDir, "exe")
  1589  			if err := ioutil.WriteFile(exePath, []byte("#!/bin/sh\necho hello"), 0770); err != nil {
  1590  				t.Fatalf("couldn't create executable: %v", err)
  1591  			}
  1592  			defer os.Remove(exePath)
  1593  
  1594  			// Need to traverse the intermediate directory.
  1595  			if err := os.Chmod(rootDir, 0755); err != nil {
  1596  				t.Fatal(err)
  1597  			}
  1598  
  1599  			execArgs := &control.ExecArgs{
  1600  				Filename:         exePath,
  1601  				Argv:             []string{exePath},
  1602  				WorkingDirectory: "/",
  1603  				KUID:             uid,
  1604  				KGID:             gid,
  1605  				Capabilities:     &auth.TaskCapabilities{},
  1606  			}
  1607  
  1608  			// "exe" should fail because we don't have the necessary permissions.
  1609  			if _, err := cont.executeSync(conf, execArgs); err == nil {
  1610  				t.Fatalf("container executed without error, but an error was expected")
  1611  			}
  1612  
  1613  			// Now we run with the capability enabled and should succeed.
  1614  			execArgs.Capabilities = &auth.TaskCapabilities{
  1615  				EffectiveCaps: auth.CapabilitySetOf(linux.CAP_DAC_OVERRIDE),
  1616  			}
  1617  			// "exe" should not fail this time.
  1618  			if _, err := cont.executeSync(conf, execArgs); err != nil {
  1619  				t.Fatalf("container failed to exec %v: %v", args, err)
  1620  			}
  1621  		})
  1622  	}
  1623  }
  1624  
  1625  // TestRunNonRoot checks that sandbox can be configured when running as
  1626  // non-privileged user.
  1627  func TestRunNonRoot(t *testing.T) {
  1628  	for name, conf := range configs(t, true /* noOverlay */) {
  1629  		t.Run(name, func(t *testing.T) {
  1630  			spec := testutil.NewSpecWithArgs("/bin/true")
  1631  
  1632  			// Set a random user/group with no access to "blocked" dir.
  1633  			spec.Process.User.UID = 343
  1634  			spec.Process.User.GID = 2401
  1635  			spec.Process.Capabilities = nil
  1636  
  1637  			// User running inside container can't list '$TMP/blocked' and would fail to
  1638  			// mount it.
  1639  			dir, err := ioutil.TempDir(testutil.TmpDir(), "blocked")
  1640  			if err != nil {
  1641  				t.Fatalf("ioutil.TempDir() failed: %v", err)
  1642  			}
  1643  			if err := os.Chmod(dir, 0700); err != nil {
  1644  				t.Fatalf("os.MkDir(%q) failed: %v", dir, err)
  1645  			}
  1646  			dir = path.Join(dir, "test")
  1647  			if err := os.Mkdir(dir, 0755); err != nil {
  1648  				t.Fatalf("os.MkDir(%q) failed: %v", dir, err)
  1649  			}
  1650  
  1651  			src, err := ioutil.TempDir(testutil.TmpDir(), "src")
  1652  			if err != nil {
  1653  				t.Fatalf("ioutil.TempDir() failed: %v", err)
  1654  			}
  1655  
  1656  			spec.Mounts = append(spec.Mounts, specs.Mount{
  1657  				Destination: dir,
  1658  				Source:      src,
  1659  				Type:        "bind",
  1660  			})
  1661  
  1662  			if err := run(spec, conf); err != nil {
  1663  				t.Fatalf("error running sandbox: %v", err)
  1664  			}
  1665  		})
  1666  	}
  1667  }
  1668  
  1669  // TestMountNewDir checks that runsc will create destination directory if it
  1670  // doesn't exit.
  1671  func TestMountNewDir(t *testing.T) {
  1672  	for name, conf := range configs(t, false /* noOverlay */) {
  1673  		t.Run(name, func(t *testing.T) {
  1674  			root, err := ioutil.TempDir(testutil.TmpDir(), "root")
  1675  			if err != nil {
  1676  				t.Fatal("ioutil.TempDir() failed:", err)
  1677  			}
  1678  
  1679  			srcDir := path.Join(root, "src", "dir", "anotherdir")
  1680  			if err := os.MkdirAll(srcDir, 0755); err != nil {
  1681  				t.Fatalf("os.MkDir(%q) failed: %v", srcDir, err)
  1682  			}
  1683  
  1684  			mountDir := path.Join(root, "dir", "anotherdir")
  1685  
  1686  			spec := testutil.NewSpecWithArgs("/bin/ls", mountDir)
  1687  			spec.Mounts = append(spec.Mounts, specs.Mount{
  1688  				Destination: mountDir,
  1689  				Source:      srcDir,
  1690  				Type:        "bind",
  1691  			})
  1692  			// Extra points for creating the mount with a readonly root.
  1693  			spec.Root.Readonly = true
  1694  
  1695  			if err := run(spec, conf); err != nil {
  1696  				t.Fatalf("error running sandbox: %v", err)
  1697  			}
  1698  		})
  1699  	}
  1700  }
  1701  
  1702  func TestReadonlyRoot(t *testing.T) {
  1703  	for name, conf := range configs(t, false /* noOverlay */) {
  1704  		t.Run(name, func(t *testing.T) {
  1705  			spec, _ := sleepSpecConf(t)
  1706  			spec.Root.Readonly = true
  1707  
  1708  			_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  1709  			if err != nil {
  1710  				t.Fatalf("error setting up container: %v", err)
  1711  			}
  1712  			defer cleanup()
  1713  
  1714  			args := Args{
  1715  				ID:        testutil.RandomContainerID(),
  1716  				Spec:      spec,
  1717  				BundleDir: bundleDir,
  1718  			}
  1719  			c, err := New(conf, args)
  1720  			if err != nil {
  1721  				t.Fatalf("error creating container: %v", err)
  1722  			}
  1723  			defer c.Destroy()
  1724  			if err := c.Start(conf); err != nil {
  1725  				t.Fatalf("error starting container: %v", err)
  1726  			}
  1727  
  1728  			// Read mounts to check that root is readonly.
  1729  			out, err := executeCombinedOutput(conf, c, nil, "/bin/sh", "-c", "mount | grep ' / ' | grep -o -e '(.*)'")
  1730  			if err != nil {
  1731  				t.Fatalf("exec failed: %v", err)
  1732  			}
  1733  			t.Logf("root mount options: %q", out)
  1734  			if !strings.Contains(string(out), "ro") {
  1735  				t.Errorf("root not mounted readonly: %q", out)
  1736  			}
  1737  
  1738  			// Check that file cannot be created.
  1739  			ws, err := execute(conf, c, "/bin/touch", "/foo")
  1740  			if err != nil {
  1741  				t.Fatalf("touch file in ro mount: %v", err)
  1742  			}
  1743  			if !ws.Exited() || unix.Errno(ws.ExitStatus()) != unix.EPERM {
  1744  				t.Fatalf("wrong waitStatus: %v", ws)
  1745  			}
  1746  		})
  1747  	}
  1748  }
  1749  
  1750  func TestReadonlyMount(t *testing.T) {
  1751  	for name, conf := range configs(t, false /* noOverlay */) {
  1752  		t.Run(name, func(t *testing.T) {
  1753  			dir, err := ioutil.TempDir(testutil.TmpDir(), "ro-mount")
  1754  			if err != nil {
  1755  				t.Fatalf("ioutil.TempDir() failed: %v", err)
  1756  			}
  1757  			spec, _ := sleepSpecConf(t)
  1758  			spec.Mounts = append(spec.Mounts, specs.Mount{
  1759  				Destination: dir,
  1760  				Source:      dir,
  1761  				Type:        "bind",
  1762  				Options:     []string{"ro"},
  1763  			})
  1764  			spec.Root.Readonly = false
  1765  
  1766  			_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  1767  			if err != nil {
  1768  				t.Fatalf("error setting up container: %v", err)
  1769  			}
  1770  			defer cleanup()
  1771  
  1772  			args := Args{
  1773  				ID:        testutil.RandomContainerID(),
  1774  				Spec:      spec,
  1775  				BundleDir: bundleDir,
  1776  			}
  1777  			c, err := New(conf, args)
  1778  			if err != nil {
  1779  				t.Fatalf("error creating container: %v", err)
  1780  			}
  1781  			defer c.Destroy()
  1782  			if err := c.Start(conf); err != nil {
  1783  				t.Fatalf("error starting container: %v", err)
  1784  			}
  1785  
  1786  			// Read mounts to check that volume is readonly.
  1787  			cmd := fmt.Sprintf("mount | grep ' %s ' | grep -o -e '(.*)'", dir)
  1788  			out, err := executeCombinedOutput(conf, c, nil, "/bin/sh", "-c", cmd)
  1789  			if err != nil {
  1790  				t.Fatalf("exec failed, err: %v", err)
  1791  			}
  1792  			t.Logf("mount options: %q", out)
  1793  			if !strings.Contains(string(out), "ro") {
  1794  				t.Errorf("volume not mounted readonly: %q", out)
  1795  			}
  1796  
  1797  			// Check that file cannot be created.
  1798  			ws, err := execute(conf, c, "/bin/touch", path.Join(dir, "file"))
  1799  			if err != nil {
  1800  				t.Fatalf("touch file in ro mount: %v", err)
  1801  			}
  1802  			if !ws.Exited() || unix.Errno(ws.ExitStatus()) != unix.EPERM {
  1803  				t.Fatalf("wrong WaitStatus: %v", ws)
  1804  			}
  1805  		})
  1806  	}
  1807  }
  1808  
  1809  func TestUIDMap(t *testing.T) {
  1810  	for name, conf := range configs(t, true /* noOverlay */) {
  1811  		t.Run(name, func(t *testing.T) {
  1812  			testDir, err := ioutil.TempDir(testutil.TmpDir(), "test-mount")
  1813  			if err != nil {
  1814  				t.Fatalf("ioutil.TempDir() failed: %v", err)
  1815  			}
  1816  			defer os.RemoveAll(testDir)
  1817  			testFile := path.Join(testDir, "testfile")
  1818  
  1819  			spec := testutil.NewSpecWithArgs("touch", "/tmp/testfile")
  1820  			uid := os.Getuid()
  1821  			gid := os.Getgid()
  1822  			spec.Linux = &specs.Linux{
  1823  				Namespaces: []specs.LinuxNamespace{
  1824  					{Type: specs.UserNamespace},
  1825  					{Type: specs.PIDNamespace},
  1826  					{Type: specs.MountNamespace},
  1827  				},
  1828  				UIDMappings: []specs.LinuxIDMapping{
  1829  					{
  1830  						ContainerID: 0,
  1831  						HostID:      uint32(uid),
  1832  						Size:        1,
  1833  					},
  1834  				},
  1835  				GIDMappings: []specs.LinuxIDMapping{
  1836  					{
  1837  						ContainerID: 0,
  1838  						HostID:      uint32(gid),
  1839  						Size:        1,
  1840  					},
  1841  				},
  1842  			}
  1843  
  1844  			spec.Mounts = append(spec.Mounts, specs.Mount{
  1845  				Destination: "/tmp",
  1846  				Source:      testDir,
  1847  				Type:        "bind",
  1848  			})
  1849  
  1850  			_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  1851  			if err != nil {
  1852  				t.Fatalf("error setting up container: %v", err)
  1853  			}
  1854  			defer cleanup()
  1855  
  1856  			// Create, start and wait for the container.
  1857  			args := Args{
  1858  				ID:        testutil.RandomContainerID(),
  1859  				Spec:      spec,
  1860  				BundleDir: bundleDir,
  1861  			}
  1862  			c, err := New(conf, args)
  1863  			if err != nil {
  1864  				t.Fatalf("error creating container: %v", err)
  1865  			}
  1866  			defer c.Destroy()
  1867  			if err := c.Start(conf); err != nil {
  1868  				t.Fatalf("error starting container: %v", err)
  1869  			}
  1870  
  1871  			ws, err := c.Wait()
  1872  			if err != nil {
  1873  				t.Fatalf("error waiting on container: %v", err)
  1874  			}
  1875  			if !ws.Exited() || ws.ExitStatus() != 0 {
  1876  				t.Fatalf("container failed, waitStatus: %v", ws)
  1877  			}
  1878  			st := unix.Stat_t{}
  1879  			if err := unix.Stat(testFile, &st); err != nil {
  1880  				t.Fatalf("error stat /testfile: %v", err)
  1881  			}
  1882  
  1883  			if st.Uid != uint32(uid) || st.Gid != uint32(gid) {
  1884  				t.Fatalf("UID: %d (%d) GID: %d (%d)", st.Uid, uid, st.Gid, gid)
  1885  			}
  1886  		})
  1887  	}
  1888  }
  1889  
  1890  // TestAbbreviatedIDs checks that runsc supports using abbreviated container
  1891  // IDs in place of full IDs.
  1892  func TestAbbreviatedIDs(t *testing.T) {
  1893  	rootDir, cleanup, err := testutil.SetupRootDir()
  1894  	if err != nil {
  1895  		t.Fatalf("error creating root dir: %v", err)
  1896  	}
  1897  	defer cleanup()
  1898  
  1899  	conf := testutil.TestConfig(t)
  1900  	conf.RootDir = rootDir
  1901  
  1902  	cids := []string{
  1903  		"foo-" + testutil.RandomContainerID(),
  1904  		"bar-" + testutil.RandomContainerID(),
  1905  		"baz-" + testutil.RandomContainerID(),
  1906  	}
  1907  	for _, cid := range cids {
  1908  		spec, _ := sleepSpecConf(t)
  1909  		bundleDir, cleanup, err := testutil.SetupBundleDir(spec)
  1910  		if err != nil {
  1911  			t.Fatalf("error setting up container: %v", err)
  1912  		}
  1913  		defer cleanup()
  1914  
  1915  		// Create and start the container.
  1916  		args := Args{
  1917  			ID:        cid,
  1918  			Spec:      spec,
  1919  			BundleDir: bundleDir,
  1920  		}
  1921  		cont, err := New(conf, args)
  1922  		if err != nil {
  1923  			t.Fatalf("error creating container: %v", err)
  1924  		}
  1925  		defer cont.Destroy()
  1926  	}
  1927  
  1928  	// These should all be unambigious.
  1929  	unambiguous := map[string]string{
  1930  		"f":     cids[0],
  1931  		cids[0]: cids[0],
  1932  		"bar":   cids[1],
  1933  		cids[1]: cids[1],
  1934  		"baz":   cids[2],
  1935  		cids[2]: cids[2],
  1936  	}
  1937  	for shortid, longid := range unambiguous {
  1938  		if _, err := Load(rootDir, FullID{ContainerID: shortid}, LoadOpts{}); err != nil {
  1939  			t.Errorf("%q should resolve to %q: %v", shortid, longid, err)
  1940  		}
  1941  	}
  1942  
  1943  	// These should be ambiguous.
  1944  	ambiguous := []string{
  1945  		"b",
  1946  		"ba",
  1947  	}
  1948  	for _, shortid := range ambiguous {
  1949  		if s, err := Load(rootDir, FullID{ContainerID: shortid}, LoadOpts{}); err == nil {
  1950  			t.Errorf("%q should be ambiguous, but resolved to %q", shortid, s.ID)
  1951  		}
  1952  	}
  1953  }
  1954  
  1955  func TestGoferExits(t *testing.T) {
  1956  	spec, conf := sleepSpecConf(t)
  1957  	_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  1958  
  1959  	if err != nil {
  1960  		t.Fatalf("error setting up container: %v", err)
  1961  	}
  1962  	defer cleanup()
  1963  
  1964  	// Create and start the container.
  1965  	args := Args{
  1966  		ID:        testutil.RandomContainerID(),
  1967  		Spec:      spec,
  1968  		BundleDir: bundleDir,
  1969  	}
  1970  	c, err := New(conf, args)
  1971  	if err != nil {
  1972  		t.Fatalf("error creating container: %v", err)
  1973  	}
  1974  	defer c.Destroy()
  1975  	if err := c.Start(conf); err != nil {
  1976  		t.Fatalf("error starting container: %v", err)
  1977  	}
  1978  
  1979  	// Kill sandbox and expect gofer to exit on its own.
  1980  	sandboxProc, err := os.FindProcess(c.Sandbox.Getpid())
  1981  	if err != nil {
  1982  		t.Fatalf("error finding sandbox process: %v", err)
  1983  	}
  1984  	if err := sandboxProc.Kill(); err != nil {
  1985  		t.Fatalf("error killing sandbox process: %v", err)
  1986  	}
  1987  
  1988  	err = blockUntilWaitable(c.GoferPid)
  1989  	if err != nil && err != unix.ECHILD {
  1990  		t.Errorf("error waiting for gofer to exit: %v", err)
  1991  	}
  1992  }
  1993  
  1994  func TestRootNotMount(t *testing.T) {
  1995  	appSym, err := testutil.FindFile("test/cmd/test_app/test_app")
  1996  	if err != nil {
  1997  		t.Fatal("error finding test_app:", err)
  1998  	}
  1999  
  2000  	app, err := filepath.EvalSymlinks(appSym)
  2001  	if err != nil {
  2002  		t.Fatalf("error resolving %q symlink: %v", appSym, err)
  2003  	}
  2004  	log.Infof("App path %q is a symlink to %q", appSym, app)
  2005  
  2006  	static, err := testutil.IsStatic(app)
  2007  	if err != nil {
  2008  		t.Fatalf("error reading application binary: %v", err)
  2009  	}
  2010  	if !static {
  2011  		// This happens during race builds; we cannot map in shared
  2012  		// libraries also, so we need to skip the test.
  2013  		t.Skip()
  2014  	}
  2015  
  2016  	root := filepath.Dir(app)
  2017  	exe := "/" + filepath.Base(app)
  2018  	log.Infof("Executing %q in %q", exe, root)
  2019  
  2020  	spec := testutil.NewSpecWithArgs(exe, "help")
  2021  	spec.Root.Path = root
  2022  	spec.Root.Readonly = true
  2023  	spec.Mounts = nil
  2024  
  2025  	conf := testutil.TestConfig(t)
  2026  	if err := run(spec, conf); err != nil {
  2027  		t.Fatalf("error running sandbox: %v", err)
  2028  	}
  2029  }
  2030  
  2031  func TestUserLog(t *testing.T) {
  2032  	app, err := testutil.FindFile("test/cmd/test_app/test_app")
  2033  	if err != nil {
  2034  		t.Fatal("error finding test_app:", err)
  2035  	}
  2036  
  2037  	// sched_rr_get_interval - not implemented in gvisor.
  2038  	num := strconv.Itoa(unix.SYS_SCHED_RR_GET_INTERVAL)
  2039  	spec := testutil.NewSpecWithArgs(app, "syscall", "--syscall="+num)
  2040  	conf := testutil.TestConfig(t)
  2041  	_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  2042  	if err != nil {
  2043  		t.Fatalf("error setting up container: %v", err)
  2044  	}
  2045  	defer cleanup()
  2046  
  2047  	dir, err := ioutil.TempDir(testutil.TmpDir(), "user_log_test")
  2048  	if err != nil {
  2049  		t.Fatalf("error creating tmp dir: %v", err)
  2050  	}
  2051  	userLog := filepath.Join(dir, "user.log")
  2052  
  2053  	// Create, start and wait for the container.
  2054  	args := Args{
  2055  		ID:        testutil.RandomContainerID(),
  2056  		Spec:      spec,
  2057  		BundleDir: bundleDir,
  2058  		UserLog:   userLog,
  2059  		Attached:  true,
  2060  	}
  2061  	ws, err := Run(conf, args)
  2062  	if err != nil {
  2063  		t.Fatalf("error running container: %v", err)
  2064  	}
  2065  	if !ws.Exited() || ws.ExitStatus() != 0 {
  2066  		t.Fatalf("container failed, waitStatus: %v", ws)
  2067  	}
  2068  
  2069  	out, err := ioutil.ReadFile(userLog)
  2070  	if err != nil {
  2071  		t.Fatalf("error opening user log file %q: %v", userLog, err)
  2072  	}
  2073  	if want := "Unsupported syscall sched_rr_get_interval("; !strings.Contains(string(out), want) {
  2074  		t.Errorf("user log file doesn't contain %q, out: %s", want, string(out))
  2075  	}
  2076  }
  2077  
  2078  func TestWaitOnExitedSandbox(t *testing.T) {
  2079  	for name, conf := range configs(t, false /* noOverlay */) {
  2080  		t.Run(name, func(t *testing.T) {
  2081  			// Run a shell that sleeps for 1 second and then exits with a
  2082  			// non-zero code.
  2083  			const wantExit = 17
  2084  			cmd := fmt.Sprintf("sleep 1; exit %d", wantExit)
  2085  			spec := testutil.NewSpecWithArgs("/bin/sh", "-c", cmd)
  2086  			_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  2087  			if err != nil {
  2088  				t.Fatalf("error setting up container: %v", err)
  2089  			}
  2090  			defer cleanup()
  2091  
  2092  			// Create and Start the container.
  2093  			args := Args{
  2094  				ID:        testutil.RandomContainerID(),
  2095  				Spec:      spec,
  2096  				BundleDir: bundleDir,
  2097  			}
  2098  			c, err := New(conf, args)
  2099  			if err != nil {
  2100  				t.Fatalf("error creating container: %v", err)
  2101  			}
  2102  			defer c.Destroy()
  2103  			if err := c.Start(conf); err != nil {
  2104  				t.Fatalf("error starting container: %v", err)
  2105  			}
  2106  
  2107  			// Wait on the sandbox. This will make an RPC to the sandbox
  2108  			// and get the actual exit status of the application.
  2109  			ws, err := c.Wait()
  2110  			if err != nil {
  2111  				t.Fatalf("error waiting on container: %v", err)
  2112  			}
  2113  			if got := ws.ExitStatus(); got != wantExit {
  2114  				t.Errorf("got exit status %d, want %d", got, wantExit)
  2115  			}
  2116  
  2117  			// Now the sandbox has exited, but the zombie sandbox process
  2118  			// still exists. Calling Wait() now will return the sandbox
  2119  			// exit status.
  2120  			ws, err = c.Wait()
  2121  			if err != nil {
  2122  				t.Fatalf("error waiting on container: %v", err)
  2123  			}
  2124  			if got := ws.ExitStatus(); got != wantExit {
  2125  				t.Errorf("got exit status %d, want %d", got, wantExit)
  2126  			}
  2127  		})
  2128  	}
  2129  }
  2130  
  2131  func TestDestroyNotStarted(t *testing.T) {
  2132  	spec, conf := sleepSpecConf(t)
  2133  	_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  2134  	if err != nil {
  2135  		t.Fatalf("error setting up container: %v", err)
  2136  	}
  2137  	defer cleanup()
  2138  
  2139  	// Create the container and check that it can be destroyed.
  2140  	args := Args{
  2141  		ID:        testutil.RandomContainerID(),
  2142  		Spec:      spec,
  2143  		BundleDir: bundleDir,
  2144  	}
  2145  	c, err := New(conf, args)
  2146  	if err != nil {
  2147  		t.Fatalf("error creating container: %v", err)
  2148  	}
  2149  	if err := c.Destroy(); err != nil {
  2150  		t.Fatalf("deleting non-started container failed: %v", err)
  2151  	}
  2152  }
  2153  
  2154  // TestDestroyStarting attempts to force a race between start and destroy.
  2155  func TestDestroyStarting(t *testing.T) {
  2156  	for i := 0; i < 10; i++ {
  2157  		spec, conf := sleepSpecConf(t)
  2158  		rootDir, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  2159  		if err != nil {
  2160  			t.Fatalf("error setting up container: %v", err)
  2161  		}
  2162  		defer cleanup()
  2163  
  2164  		// Create the container and check that it can be destroyed.
  2165  		args := Args{
  2166  			ID:        testutil.RandomContainerID(),
  2167  			Spec:      spec,
  2168  			BundleDir: bundleDir,
  2169  		}
  2170  		c, err := New(conf, args)
  2171  		if err != nil {
  2172  			t.Fatalf("error creating container: %v", err)
  2173  		}
  2174  
  2175  		// Container is not thread safe, so load another instance to run in
  2176  		// concurrently.
  2177  		startCont, err := Load(rootDir, FullID{ContainerID: args.ID}, LoadOpts{})
  2178  		if err != nil {
  2179  			t.Fatalf("error loading container: %v", err)
  2180  		}
  2181  		wg := sync.WaitGroup{}
  2182  		wg.Add(1)
  2183  		go func() {
  2184  			defer wg.Done()
  2185  			// Ignore failures, start can fail if destroy runs first.
  2186  			_ = startCont.Start(conf)
  2187  		}()
  2188  
  2189  		wg.Add(1)
  2190  		go func() {
  2191  			defer wg.Done()
  2192  			if err := c.Destroy(); err != nil {
  2193  				t.Errorf("deleting non-started container failed: %v", err)
  2194  			}
  2195  		}()
  2196  		wg.Wait()
  2197  	}
  2198  }
  2199  
  2200  func TestCreateWorkingDir(t *testing.T) {
  2201  	for name, conf := range configs(t, false /* noOverlay */) {
  2202  		t.Run(name, func(t *testing.T) {
  2203  			tmpDir, err := ioutil.TempDir(testutil.TmpDir(), "cwd-create")
  2204  			if err != nil {
  2205  				t.Fatalf("ioutil.TempDir() failed: %v", err)
  2206  			}
  2207  			dir := path.Join(tmpDir, "new/working/dir")
  2208  
  2209  			// touch will fail if the directory doesn't exist.
  2210  			spec := testutil.NewSpecWithArgs("/bin/touch", path.Join(dir, "file"))
  2211  			spec.Process.Cwd = dir
  2212  			spec.Root.Readonly = true
  2213  
  2214  			if err := run(spec, conf); err != nil {
  2215  				t.Fatalf("Error running container: %v", err)
  2216  			}
  2217  		})
  2218  	}
  2219  }
  2220  
  2221  // TestMountPropagation verifies that mount propagates to slave but not to
  2222  // private mounts.
  2223  func TestMountPropagation(t *testing.T) {
  2224  	// Setup dir structure:
  2225  	//   - src: is mounted as shared and is used as source for both private and
  2226  	//     slave mounts
  2227  	//   - dir: will be bind mounted inside src and should propagate to slave
  2228  	tmpDir, err := ioutil.TempDir(testutil.TmpDir(), "mount")
  2229  	if err != nil {
  2230  		t.Fatalf("ioutil.TempDir() failed: %v", err)
  2231  	}
  2232  	src := filepath.Join(tmpDir, "src")
  2233  	srcMnt := filepath.Join(src, "mnt")
  2234  	dir := filepath.Join(tmpDir, "dir")
  2235  	for _, path := range []string{src, srcMnt, dir} {
  2236  		if err := os.MkdirAll(path, 0777); err != nil {
  2237  			t.Fatalf("MkdirAll(%q): %v", path, err)
  2238  		}
  2239  	}
  2240  	dirFile := filepath.Join(dir, "file")
  2241  	f, err := os.Create(dirFile)
  2242  	if err != nil {
  2243  		t.Fatalf("os.Create(%q): %v", dirFile, err)
  2244  	}
  2245  	f.Close()
  2246  
  2247  	// Setup src as a shared mount.
  2248  	if err := unix.Mount(src, src, "bind", unix.MS_BIND, ""); err != nil {
  2249  		t.Fatalf("mount(%q, %q, MS_BIND): %v", dir, srcMnt, err)
  2250  	}
  2251  	if err := unix.Mount("", src, "", unix.MS_SHARED, ""); err != nil {
  2252  		t.Fatalf("mount(%q, MS_SHARED): %v", srcMnt, err)
  2253  	}
  2254  
  2255  	spec, conf := sleepSpecConf(t)
  2256  
  2257  	priv := filepath.Join(tmpDir, "priv")
  2258  	slave := filepath.Join(tmpDir, "slave")
  2259  	spec.Mounts = []specs.Mount{
  2260  		{
  2261  			Source:      src,
  2262  			Destination: priv,
  2263  			Type:        "bind",
  2264  			Options:     []string{"private"},
  2265  		},
  2266  		{
  2267  			Source:      src,
  2268  			Destination: slave,
  2269  			Type:        "bind",
  2270  			Options:     []string{"slave"},
  2271  		},
  2272  	}
  2273  
  2274  	_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  2275  	if err != nil {
  2276  		t.Fatalf("error setting up container: %v", err)
  2277  	}
  2278  	defer cleanup()
  2279  
  2280  	args := Args{
  2281  		ID:        testutil.RandomContainerID(),
  2282  		Spec:      spec,
  2283  		BundleDir: bundleDir,
  2284  	}
  2285  	cont, err := New(conf, args)
  2286  	if err != nil {
  2287  		t.Fatalf("creating container: %v", err)
  2288  	}
  2289  	defer cont.Destroy()
  2290  
  2291  	if err := cont.Start(conf); err != nil {
  2292  		t.Fatalf("starting container: %v", err)
  2293  	}
  2294  
  2295  	// After the container is started, mount dir inside source and check what
  2296  	// happens to both destinations.
  2297  	if err := unix.Mount(dir, srcMnt, "bind", unix.MS_BIND, ""); err != nil {
  2298  		t.Fatalf("mount(%q, %q, MS_BIND): %v", dir, srcMnt, err)
  2299  	}
  2300  
  2301  	// Check that mount didn't propagate to private mount.
  2302  	privFile := filepath.Join(priv, "mnt", "file")
  2303  	if ws, err := execute(conf, cont, "/usr/bin/test", "!", "-f", privFile); err != nil || ws != 0 {
  2304  		t.Fatalf("exec: test ! -f %q, ws: %v, err: %v", privFile, ws, err)
  2305  	}
  2306  
  2307  	// Check that mount propagated to slave mount.
  2308  	slaveFile := filepath.Join(slave, "mnt", "file")
  2309  	if ws, err := execute(conf, cont, "/usr/bin/test", "-f", slaveFile); err != nil || ws != 0 {
  2310  		t.Fatalf("exec: test -f %q, ws: %v, err: %v", privFile, ws, err)
  2311  	}
  2312  }
  2313  
  2314  func TestMountSymlink(t *testing.T) {
  2315  	for name, conf := range configs(t, false /* noOverlay */) {
  2316  		t.Run(name, func(t *testing.T) {
  2317  			dir, err := ioutil.TempDir(testutil.TmpDir(), "mount-symlink")
  2318  			if err != nil {
  2319  				t.Fatalf("ioutil.TempDir() failed: %v", err)
  2320  			}
  2321  			defer os.RemoveAll(dir)
  2322  
  2323  			source := path.Join(dir, "source")
  2324  			target := path.Join(dir, "target")
  2325  			for _, path := range []string{source, target} {
  2326  				if err := os.MkdirAll(path, 0777); err != nil {
  2327  					t.Fatalf("os.MkdirAll(): %v", err)
  2328  				}
  2329  			}
  2330  			f, err := os.Create(path.Join(source, "file"))
  2331  			if err != nil {
  2332  				t.Fatalf("os.Create(): %v", err)
  2333  			}
  2334  			f.Close()
  2335  
  2336  			link := path.Join(dir, "link")
  2337  			if err := os.Symlink(target, link); err != nil {
  2338  				t.Fatalf("os.Symlink(%q, %q): %v", target, link, err)
  2339  			}
  2340  
  2341  			spec, _ := sleepSpecConf(t)
  2342  
  2343  			// Mount to a symlink to ensure the mount code will follow it and mount
  2344  			// at the symlink target.
  2345  			spec.Mounts = append(spec.Mounts, specs.Mount{
  2346  				Type:        "bind",
  2347  				Destination: link,
  2348  				Source:      source,
  2349  			})
  2350  
  2351  			_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  2352  			if err != nil {
  2353  				t.Fatalf("error setting up container: %v", err)
  2354  			}
  2355  			defer cleanup()
  2356  
  2357  			args := Args{
  2358  				ID:        testutil.RandomContainerID(),
  2359  				Spec:      spec,
  2360  				BundleDir: bundleDir,
  2361  			}
  2362  			cont, err := New(conf, args)
  2363  			if err != nil {
  2364  				t.Fatalf("creating container: %v", err)
  2365  			}
  2366  			defer cont.Destroy()
  2367  
  2368  			if err := cont.Start(conf); err != nil {
  2369  				t.Fatalf("starting container: %v", err)
  2370  			}
  2371  
  2372  			// Check that symlink was resolved and mount was created where the symlink
  2373  			// is pointing to.
  2374  			file := path.Join(target, "file")
  2375  			if ws, err := execute(conf, cont, "/usr/bin/test", "-f", file); err != nil || ws != 0 {
  2376  				t.Fatalf("exec: test -f %q, ws: %v, err: %v", file, ws, err)
  2377  			}
  2378  		})
  2379  	}
  2380  }
  2381  
  2382  // Check that --net-raw disables the CAP_NET_RAW capability.
  2383  func TestNetRaw(t *testing.T) {
  2384  	capNetRaw := strconv.FormatUint(bits.MaskOf64(int(linux.CAP_NET_RAW)), 10)
  2385  	app, err := testutil.FindFile("test/cmd/test_app/test_app")
  2386  	if err != nil {
  2387  		t.Fatal("error finding test_app:", err)
  2388  	}
  2389  
  2390  	for _, enableRaw := range []bool{true, false} {
  2391  		conf := testutil.TestConfig(t)
  2392  		conf.EnableRaw = enableRaw
  2393  
  2394  		test := "--enabled"
  2395  		if !enableRaw {
  2396  			test = "--disabled"
  2397  		}
  2398  
  2399  		spec := testutil.NewSpecWithArgs(app, "capability", test, capNetRaw)
  2400  		if err := run(spec, conf); err != nil {
  2401  			t.Fatalf("Error running container: %v", err)
  2402  		}
  2403  	}
  2404  }
  2405  
  2406  // TestTTYField checks TTY field returned by container.Processes().
  2407  func TestTTYField(t *testing.T) {
  2408  	stop := testutil.StartReaper()
  2409  	defer stop()
  2410  
  2411  	testApp, err := testutil.FindFile("test/cmd/test_app/test_app")
  2412  	if err != nil {
  2413  		t.Fatal("error finding test_app:", err)
  2414  	}
  2415  
  2416  	testCases := []struct {
  2417  		name         string
  2418  		useTTY       bool
  2419  		wantTTYField string
  2420  	}{
  2421  		{
  2422  			name:         "no tty",
  2423  			useTTY:       false,
  2424  			wantTTYField: "?",
  2425  		},
  2426  		{
  2427  			name:         "tty used",
  2428  			useTTY:       true,
  2429  			wantTTYField: "pts/0",
  2430  		},
  2431  	}
  2432  
  2433  	for _, test := range testCases {
  2434  		t.Run(test.name, func(t *testing.T) {
  2435  			conf := testutil.TestConfig(t)
  2436  
  2437  			// We will run /bin/sleep, possibly with an open TTY.
  2438  			cmd := []string{"/bin/sleep", "10000"}
  2439  			if test.useTTY {
  2440  				// Run inside the "pty-runner".
  2441  				cmd = append([]string{testApp, "pty-runner"}, cmd...)
  2442  			}
  2443  
  2444  			spec := testutil.NewSpecWithArgs(cmd...)
  2445  			_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  2446  			if err != nil {
  2447  				t.Fatalf("error setting up container: %v", err)
  2448  			}
  2449  			defer cleanup()
  2450  
  2451  			// Create and start the container.
  2452  			args := Args{
  2453  				ID:        testutil.RandomContainerID(),
  2454  				Spec:      spec,
  2455  				BundleDir: bundleDir,
  2456  			}
  2457  			c, err := New(conf, args)
  2458  			if err != nil {
  2459  				t.Fatalf("error creating container: %v", err)
  2460  			}
  2461  			defer c.Destroy()
  2462  			if err := c.Start(conf); err != nil {
  2463  				t.Fatalf("error starting container: %v", err)
  2464  			}
  2465  
  2466  			// Wait for sleep to be running, and check the TTY
  2467  			// field.
  2468  			var gotTTYField string
  2469  			cb := func() error {
  2470  				ps, err := c.Processes()
  2471  				if err != nil {
  2472  					err = fmt.Errorf("error getting process data from container: %v", err)
  2473  					return &backoff.PermanentError{Err: err}
  2474  				}
  2475  				for _, p := range ps {
  2476  					if strings.Contains(p.Cmd, "sleep") {
  2477  						gotTTYField = p.TTY
  2478  						return nil
  2479  					}
  2480  				}
  2481  				return fmt.Errorf("sleep not running")
  2482  			}
  2483  			if err := testutil.Poll(cb, 30*time.Second); err != nil {
  2484  				t.Fatalf("error waiting for sleep process: %v", err)
  2485  			}
  2486  
  2487  			if gotTTYField != test.wantTTYField {
  2488  				t.Errorf("tty field got %q, want %q", gotTTYField, test.wantTTYField)
  2489  			}
  2490  		})
  2491  	}
  2492  }
  2493  
  2494  // Test that container can run even when there are corrupt state files in the
  2495  // root directiry.
  2496  func TestCreateWithCorruptedStateFile(t *testing.T) {
  2497  	conf := testutil.TestConfig(t)
  2498  	spec := testutil.NewSpecWithArgs("/bin/true")
  2499  	_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  2500  	if err != nil {
  2501  		t.Fatalf("error setting up container: %v", err)
  2502  	}
  2503  	defer cleanup()
  2504  
  2505  	// Create corrupted state file.
  2506  	corruptID := testutil.RandomContainerID()
  2507  	corruptState := buildPath(conf.RootDir, FullID{SandboxID: corruptID, ContainerID: corruptID}, stateFileExtension)
  2508  	if err := ioutil.WriteFile(corruptState, []byte("this{file(is;not[valid.json"), 0777); err != nil {
  2509  		t.Fatalf("createCorruptStateFile(): %v", err)
  2510  	}
  2511  	defer os.Remove(corruptState)
  2512  
  2513  	if _, err := Load(conf.RootDir, FullID{ContainerID: corruptID}, LoadOpts{SkipCheck: true}); err == nil {
  2514  		t.Fatalf("loading corrupted state file should have failed")
  2515  	}
  2516  
  2517  	args := Args{
  2518  		ID:        testutil.RandomContainerID(),
  2519  		Spec:      spec,
  2520  		BundleDir: bundleDir,
  2521  		Attached:  true,
  2522  	}
  2523  	if ws, err := Run(conf, args); err != nil {
  2524  		t.Errorf("running container: %v", err)
  2525  	} else if !ws.Exited() || ws.ExitStatus() != 0 {
  2526  		t.Errorf("container failed, waitStatus: %v", ws)
  2527  	}
  2528  }
  2529  
  2530  func TestBindMountByOption(t *testing.T) {
  2531  	for name, conf := range configs(t, false /* noOverlay */) {
  2532  		t.Run(name, func(t *testing.T) {
  2533  			dir, err := ioutil.TempDir(testutil.TmpDir(), "bind-mount")
  2534  			spec := testutil.NewSpecWithArgs("/bin/touch", path.Join(dir, "file"))
  2535  			if err != nil {
  2536  				t.Fatalf("ioutil.TempDir(): %v", err)
  2537  			}
  2538  			spec.Mounts = append(spec.Mounts, specs.Mount{
  2539  				Destination: dir,
  2540  				Source:      dir,
  2541  				Type:        "none",
  2542  				Options:     []string{"rw", "bind"},
  2543  			})
  2544  			if err := run(spec, conf); err != nil {
  2545  				t.Fatalf("error running sandbox: %v", err)
  2546  			}
  2547  		})
  2548  	}
  2549  }
  2550  
  2551  // TestRlimits sets limit to number of open files and checks that the limit
  2552  // is propagated to the container.
  2553  func TestRlimits(t *testing.T) {
  2554  	file, err := ioutil.TempFile(testutil.TmpDir(), "ulimit")
  2555  	if err != nil {
  2556  		t.Fatal(err)
  2557  	}
  2558  	cmd := fmt.Sprintf("ulimit -n > %q", file.Name())
  2559  
  2560  	spec := testutil.NewSpecWithArgs("sh", "-c", cmd)
  2561  	spec.Process.Rlimits = []specs.POSIXRlimit{
  2562  		{Type: "RLIMIT_NOFILE", Hard: 1000, Soft: 100},
  2563  	}
  2564  
  2565  	conf := testutil.TestConfig(t)
  2566  	if err := run(spec, conf); err != nil {
  2567  		t.Fatalf("Error running container: %v", err)
  2568  	}
  2569  	got, err := ioutil.ReadFile(file.Name())
  2570  	if err != nil {
  2571  		t.Fatal(err)
  2572  	}
  2573  	if want := "100\n"; string(got) != want {
  2574  		t.Errorf("ulimit result, got: %q, want: %q", got, want)
  2575  	}
  2576  }
  2577  
  2578  // TestRlimitsExec sets limit to number of open files and checks that the limit
  2579  // is propagated to exec'd processes.
  2580  func TestRlimitsExec(t *testing.T) {
  2581  	spec, conf := sleepSpecConf(t)
  2582  	spec.Process.Rlimits = []specs.POSIXRlimit{
  2583  		{Type: "RLIMIT_NOFILE", Hard: 1000, Soft: 100},
  2584  	}
  2585  
  2586  	_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  2587  	if err != nil {
  2588  		t.Fatalf("error setting up container: %v", err)
  2589  	}
  2590  	defer cleanup()
  2591  
  2592  	args := Args{
  2593  		ID:        testutil.RandomContainerID(),
  2594  		Spec:      spec,
  2595  		BundleDir: bundleDir,
  2596  	}
  2597  	cont, err := New(conf, args)
  2598  	if err != nil {
  2599  		t.Fatalf("error creating container: %v", err)
  2600  	}
  2601  	defer cont.Destroy()
  2602  	if err := cont.Start(conf); err != nil {
  2603  		t.Fatalf("error starting container: %v", err)
  2604  	}
  2605  
  2606  	got, err := executeCombinedOutput(conf, cont, nil, "/bin/sh", "-c", "ulimit -n")
  2607  	if err != nil {
  2608  		t.Fatal(err)
  2609  	}
  2610  	if want := "100\n"; string(got) != want {
  2611  		t.Errorf("ulimit result, got: %q, want: %q", got, want)
  2612  	}
  2613  }
  2614  
  2615  // TestUsage checks that usage generates the expected memory usage.
  2616  func TestUsage(t *testing.T) {
  2617  	spec, conf := sleepSpecConf(t)
  2618  	_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  2619  	if err != nil {
  2620  		t.Fatalf("error setting up container: %v", err)
  2621  	}
  2622  	defer cleanup()
  2623  
  2624  	args := Args{
  2625  		ID:        testutil.RandomContainerID(),
  2626  		Spec:      spec,
  2627  		BundleDir: bundleDir,
  2628  	}
  2629  
  2630  	cont, err := New(conf, args)
  2631  	if err != nil {
  2632  		t.Fatalf("Creating container: %v", err)
  2633  	}
  2634  	defer cont.Destroy()
  2635  
  2636  	if err := cont.Start(conf); err != nil {
  2637  		t.Fatalf("starting container: %v", err)
  2638  	}
  2639  
  2640  	for _, full := range []bool{false, true} {
  2641  		m, err := cont.Sandbox.Usage(full)
  2642  		if err != nil {
  2643  			t.Fatalf("error usage from container: %v", err)
  2644  		}
  2645  		if m.Mapped == 0 {
  2646  			t.Errorf("Usage mapped got zero")
  2647  		}
  2648  		if m.Total == 0 {
  2649  			t.Errorf("Usage total got zero")
  2650  		}
  2651  		if full {
  2652  			if m.System == 0 {
  2653  				t.Errorf("Usage system got zero")
  2654  			}
  2655  			if m.Anonymous == 0 {
  2656  				t.Errorf("Usage anonymous got zero")
  2657  			}
  2658  		}
  2659  	}
  2660  }
  2661  
  2662  // TestUsageFD checks that usagefd generates the expected memory usage.
  2663  func TestUsageFD(t *testing.T) {
  2664  	spec, conf := sleepSpecConf(t)
  2665  
  2666  	_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  2667  	if err != nil {
  2668  		t.Fatalf("error setting up container: %v", err)
  2669  	}
  2670  	defer cleanup()
  2671  
  2672  	args := Args{
  2673  		ID:        testutil.RandomContainerID(),
  2674  		Spec:      spec,
  2675  		BundleDir: bundleDir,
  2676  	}
  2677  
  2678  	cont, err := New(conf, args)
  2679  	if err != nil {
  2680  		t.Fatalf("Creating container: %v", err)
  2681  	}
  2682  	defer cont.Destroy()
  2683  
  2684  	if err := cont.Start(conf); err != nil {
  2685  		t.Fatalf("starting container: %v", err)
  2686  	}
  2687  
  2688  	m, err := cont.Sandbox.UsageFD()
  2689  	if err != nil {
  2690  		t.Fatalf("error usageFD from container: %v", err)
  2691  	}
  2692  
  2693  	mapped, unknown, total, err := m.Fetch()
  2694  	if err != nil {
  2695  		t.Fatalf("error Fetch memory usage: %v", err)
  2696  	}
  2697  
  2698  	if mapped == 0 {
  2699  		t.Errorf("UsageFD Mapped got zero")
  2700  	}
  2701  	if unknown == 0 {
  2702  		t.Errorf("UsageFD unknown got zero")
  2703  	}
  2704  	if total == 0 {
  2705  		t.Errorf("UsageFD total got zero")
  2706  	}
  2707  }
  2708  
  2709  // TestProfile checks that profiling options generate profiles.
  2710  func TestProfile(t *testing.T) {
  2711  	// Perform a non-trivial amount of work so we actually capture
  2712  	// something in the profiles.
  2713  	spec := testutil.NewSpecWithArgs("/bin/bash", "-c", "true")
  2714  	conf := testutil.TestConfig(t)
  2715  	conf.ProfileEnable = true
  2716  	conf.ProfileBlock = filepath.Join(t.TempDir(), "block.pprof")
  2717  	conf.ProfileCPU = filepath.Join(t.TempDir(), "cpu.pprof")
  2718  	conf.ProfileHeap = filepath.Join(t.TempDir(), "heap.pprof")
  2719  	conf.ProfileMutex = filepath.Join(t.TempDir(), "mutex.pprof")
  2720  	conf.TraceFile = filepath.Join(t.TempDir(), "trace.out")
  2721  
  2722  	_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  2723  	if err != nil {
  2724  		t.Fatalf("error setting up container: %v", err)
  2725  	}
  2726  	defer cleanup()
  2727  
  2728  	args := Args{
  2729  		ID:        testutil.RandomContainerID(),
  2730  		Spec:      spec,
  2731  		BundleDir: bundleDir,
  2732  		Attached:  true,
  2733  	}
  2734  
  2735  	_, err = Run(conf, args)
  2736  	if err != nil {
  2737  		t.Fatalf("Creating container: %v", err)
  2738  	}
  2739  
  2740  	// Basic test; simply assert that the profiles are not empty.
  2741  	for _, name := range []string{conf.ProfileBlock, conf.ProfileCPU, conf.ProfileHeap, conf.ProfileMutex, conf.TraceFile} {
  2742  		fi, err := os.Stat(name)
  2743  		if err != nil {
  2744  			t.Fatalf("Unable to stat profile file %s: %v", name, err)
  2745  		}
  2746  		if fi.Size() == 0 {
  2747  			t.Errorf("Profile file %s is empty: %+v", name, fi)
  2748  		}
  2749  	}
  2750  }
  2751  
  2752  // TestSaveSystemdCgroup emulates a sandbox saving while configured with the
  2753  // systemd cgroup driver.
  2754  func TestSaveSystemdCgroup(t *testing.T) {
  2755  	spec, conf := sleepSpecConf(t)
  2756  	_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  2757  	if err != nil {
  2758  		t.Fatalf("error setting up container: %v", err)
  2759  	}
  2760  	defer cleanup()
  2761  
  2762  	// Create and start the container.
  2763  	args := Args{
  2764  		ID:        testutil.RandomContainerID(),
  2765  		Spec:      spec,
  2766  		BundleDir: bundleDir,
  2767  	}
  2768  	cont, err := New(conf, args)
  2769  	if err != nil {
  2770  		t.Fatalf("error creating container: %v", err)
  2771  	}
  2772  	defer cont.Destroy()
  2773  
  2774  	cont.CompatCgroup = cgroup.CgroupJSON{Cgroup: cgroup.CreateMockSystemdCgroup()}
  2775  	if err := cont.Saver.lock(BlockAcquire); err != nil {
  2776  		t.Fatalf("cannot lock container metadata file: %v", err)
  2777  	}
  2778  	if err := cont.saveLocked(); err != nil {
  2779  		t.Fatalf("error saving cgroup: %v", err)
  2780  	}
  2781  	cont.Saver.unlock()
  2782  	loadCont := Container{}
  2783  	cont.Saver.load(&loadCont, LoadOpts{})
  2784  	if !reflect.DeepEqual(cont.CompatCgroup, loadCont.CompatCgroup) {
  2785  		t.Errorf("CompatCgroup not properly saved: want %v, got %v", cont.CompatCgroup, loadCont.CompatCgroup)
  2786  	}
  2787  }
  2788  
  2789  // TestSandboxCommunicationUnshare checks that communication with sandboxes do
  2790  // not require being in the same network namespace. This is required to allow
  2791  // Kubernetes daemonsets/containers to communicate with sandboxes without the
  2792  // need to join the host network namespaces.
  2793  func TestSandboxCommunicationUnshare(t *testing.T) {
  2794  	spec, conf := sleepSpecConf(t)
  2795  	_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  2796  	if err != nil {
  2797  		t.Fatalf("error setting up container: %v", err)
  2798  	}
  2799  	defer cleanup()
  2800  
  2801  	args := Args{
  2802  		ID:        testutil.RandomContainerID(),
  2803  		Spec:      spec,
  2804  		BundleDir: bundleDir,
  2805  	}
  2806  
  2807  	cont, err := New(conf, args)
  2808  	if err != nil {
  2809  		t.Fatalf("Creating container: %v", err)
  2810  	}
  2811  	defer cont.Destroy()
  2812  
  2813  	if err := cont.Start(conf); err != nil {
  2814  		t.Fatalf("starting container: %v", err)
  2815  	}
  2816  
  2817  	runtime.LockOSThread()
  2818  	defer runtime.UnlockOSThread()
  2819  	if err := unix.Unshare(unix.CLONE_NEWNET); err != nil {
  2820  		t.Fatalf("unix.Unshare(): %v", err)
  2821  	}
  2822  
  2823  	// Send a simple command to test that the sandbox can be reached.
  2824  	if err := cont.SignalContainer(0, true); err != nil {
  2825  		t.Errorf("SignalContainer(): %v", err)
  2826  	}
  2827  }
  2828  
  2829  // writeAndReadFromPipe writes the bytes to the write end of the pipe, then
  2830  // reads from the read end and returns the result.
  2831  func writeAndReadFromPipe(write, read *os.File, msg string) (string, error) {
  2832  	// Write the message to be read by the guest.
  2833  	if _, err := io.StringWriter(write).WriteString(msg); err != nil {
  2834  		return "", fmt.Errorf("failed to write message to pipe: %w", err)
  2835  	}
  2836  	write.Close()
  2837  
  2838  	// Read and return the message.
  2839  	response, err := io.ReadAll(read)
  2840  	if err != nil {
  2841  		return "", fmt.Errorf("failed to read from pipe: %w", err)
  2842  	}
  2843  	read.Close()
  2844  
  2845  	return string(response), nil
  2846  }
  2847  
  2848  func createPipes() (*os.File, *os.File, *os.File, *os.File, func(), error) {
  2849  	// This is the first pipe which the host writes to and the guest reads
  2850  	// from.
  2851  	guestRead, hostWrite, err := os.Pipe()
  2852  	if err != nil {
  2853  		return nil, nil, nil, nil, nil, err
  2854  	}
  2855  
  2856  	// This is the second pipe which the guest writes to and the host reads
  2857  	// from.
  2858  	hostRead, guestWrite, err := os.Pipe()
  2859  	if err != nil {
  2860  		guestRead.Close()
  2861  		hostWrite.Close()
  2862  		return nil, nil, nil, nil, nil, err
  2863  	}
  2864  
  2865  	cleanup := func() {
  2866  		guestRead.Close()
  2867  		hostWrite.Close()
  2868  		hostRead.Close()
  2869  		guestWrite.Close()
  2870  	}
  2871  
  2872  	return guestRead, hostWrite, hostRead, guestWrite, cleanup, nil
  2873  }
  2874  
  2875  // TestFDPassingRun checks that file descriptors passed into a new container
  2876  // work as expected.
  2877  func TestFDPassingRun(t *testing.T) {
  2878  	guestRead, hostWrite, hostRead, guestWrite, cleanup, err := createPipes()
  2879  	if err != nil {
  2880  		t.Fatalf("error creating pipes: %v", err)
  2881  	}
  2882  	defer cleanup()
  2883  
  2884  	// In the guest, read from the host and write the result back to the host.
  2885  	conf := testutil.TestConfig(t)
  2886  	cmd := fmt.Sprintf("cat /proc/self/fd/%d > /proc/self/fd/%d", int(guestRead.Fd()), int(guestWrite.Fd()))
  2887  	spec := testutil.NewSpecWithArgs("bash", "-c", cmd)
  2888  
  2889  	_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  2890  	if err != nil {
  2891  		t.Fatalf("error setting up container: %v", err)
  2892  	}
  2893  	defer cleanup()
  2894  
  2895  	args := Args{
  2896  		ID:        testutil.RandomContainerID(),
  2897  		Spec:      spec,
  2898  		BundleDir: bundleDir,
  2899  		PassFiles: map[int]*os.File{
  2900  			int(guestRead.Fd()):  guestRead,
  2901  			int(guestWrite.Fd()): guestWrite,
  2902  		},
  2903  	}
  2904  
  2905  	cont, err := New(conf, args)
  2906  	if err != nil {
  2907  		t.Fatalf("Creating container: %v", err)
  2908  	}
  2909  	defer cont.Destroy()
  2910  
  2911  	if err := cont.Start(conf); err != nil {
  2912  		t.Fatalf("starting container: %v", err)
  2913  	}
  2914  
  2915  	// We close guestWrite here because it has been passed into the container.
  2916  	// If we do not close it, we will never see an EOF.
  2917  	guestWrite.Close()
  2918  
  2919  	msg := "hello"
  2920  	got, err := writeAndReadFromPipe(hostWrite, hostRead, msg)
  2921  	if err != nil {
  2922  		t.Fatal(err)
  2923  	}
  2924  	if got != msg {
  2925  		t.Errorf("got message %q, want %q", got, msg)
  2926  	}
  2927  }
  2928  
  2929  // TestFDPassingExec checks that file descriptors passed into an already
  2930  // running container work as expected.
  2931  func TestFDPassingExec(t *testing.T) {
  2932  	guestRead, hostWrite, hostRead, guestWrite, cleanup, err := createPipes()
  2933  	if err != nil {
  2934  		t.Fatalf("error creating pipes: %v", err)
  2935  	}
  2936  	defer cleanup()
  2937  
  2938  	// We just sleep here because we want to test file descriptor passing
  2939  	// inside a process executed inside an already running container.
  2940  	spec, conf := sleepSpecConf(t)
  2941  	_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  2942  	if err != nil {
  2943  		t.Fatalf("error setting up container: %v", err)
  2944  	}
  2945  	defer cleanup()
  2946  
  2947  	args := Args{
  2948  		ID:        testutil.RandomContainerID(),
  2949  		Spec:      spec,
  2950  		BundleDir: bundleDir,
  2951  	}
  2952  
  2953  	cont, err := New(conf, args)
  2954  	if err != nil {
  2955  		t.Fatalf("Creating container: %v", err)
  2956  	}
  2957  	defer cont.Destroy()
  2958  
  2959  	if err := cont.Start(conf); err != nil {
  2960  		t.Fatalf("starting container: %v", err)
  2961  	}
  2962  
  2963  	// Prepare executing a command in the running container.
  2964  	cmd := fmt.Sprintf("cat /proc/self/fd/%d > /proc/self/fd/%d", int(guestRead.Fd()), int(guestWrite.Fd()))
  2965  	execArgs := &control.ExecArgs{
  2966  		Argv: []string{"/bin/bash", "-c", cmd},
  2967  		FilePayload: control.NewFilePayload(map[int]*os.File{
  2968  			int(guestRead.Fd()):  guestRead,
  2969  			int(guestWrite.Fd()): guestWrite,
  2970  		}, nil),
  2971  	}
  2972  
  2973  	if _, err = cont.Execute(conf, execArgs); err != nil {
  2974  		t.Fatalf("Failed to execute command: %v", err)
  2975  	}
  2976  
  2977  	// We close guestWrite here because it has been passed into the container.
  2978  	// If we do not close it, we will never see an EOF.
  2979  	guestWrite.Close()
  2980  
  2981  	msg := "hello"
  2982  	got, err := writeAndReadFromPipe(hostWrite, hostRead, msg)
  2983  	if err != nil {
  2984  		t.Fatal(err)
  2985  	}
  2986  	if got != msg {
  2987  		t.Errorf("got message %q, want %q", got, msg)
  2988  	}
  2989  }
  2990  
  2991  // findInPath finds a filename in the PATH environment variable.
  2992  func findInPath(filename string) string {
  2993  	for _, dir := range strings.Split(os.Getenv("PATH"), ":") {
  2994  		fullPath := filepath.Join(dir, filename)
  2995  		if _, err := os.Stat(fullPath); err == nil {
  2996  			return fullPath
  2997  		}
  2998  	}
  2999  	return ""
  3000  }
  3001  
  3002  // TestExecFDRun checks that an executable from the host can be started inside
  3003  // a container.
  3004  func TestExecFDRun(t *testing.T) {
  3005  	// In the guest, read from the host and write the result back to the host.
  3006  	conf := testutil.TestConfig(t)
  3007  	// Note that we do not supply the name or path of the echo binary here.
  3008  	// Thus, the guest does not know the binary path or name either.
  3009  	// argv[0] inside echo is "can be anything".
  3010  	spec := testutil.NewSpecWithArgs("can be anything", "hello world")
  3011  
  3012  	_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  3013  	if err != nil {
  3014  		t.Fatalf("error setting up container: %v", err)
  3015  	}
  3016  	defer cleanup()
  3017  
  3018  	// Find the echo binary on the host.
  3019  	echoPath := findInPath("echo")
  3020  	if echoPath == "" {
  3021  		t.Fatalf("failed to find echo executable in PATH")
  3022  	}
  3023  
  3024  	// Open the echo binary as a file.
  3025  	echoFile, err := os.Open(echoPath)
  3026  	if err != nil {
  3027  		t.Fatalf("opening echo binary: %v", err)
  3028  	}
  3029  	defer echoFile.Close()
  3030  
  3031  	r, w, err := os.Pipe()
  3032  	if err != nil {
  3033  		t.Fatalf("creating pipe: %v", err)
  3034  	}
  3035  	defer r.Close()
  3036  
  3037  	args := Args{
  3038  		ID:        testutil.RandomContainerID(),
  3039  		Spec:      spec,
  3040  		BundleDir: bundleDir,
  3041  		PassFiles: map[int]*os.File{
  3042  			0: os.Stdin, 1: w, 2: w,
  3043  		},
  3044  		ExecFile: echoFile,
  3045  	}
  3046  
  3047  	cont, err := New(conf, args)
  3048  	if err != nil {
  3049  		t.Fatalf("Creating container: %v", err)
  3050  	}
  3051  	defer cont.Destroy()
  3052  
  3053  	if err := cont.Start(conf); err != nil {
  3054  		t.Fatalf("starting container: %v", err)
  3055  	}
  3056  
  3057  	w.Close()
  3058  
  3059  	got, err := io.ReadAll(r)
  3060  	if err != nil {
  3061  		t.Errorf("reading container output: %v", err)
  3062  	}
  3063  	if want := "hello world\n"; string(got) != want {
  3064  		t.Errorf("got message %q, want %q", got, want)
  3065  	}
  3066  }
  3067  
  3068  // TestExecFDExec checks that an executable from the host can be started from a
  3069  // file descriptor inside an already running container.
  3070  func TestExecFDExec(t *testing.T) {
  3071  	// We just sleep here because we want to test execution in an already
  3072  	// running container.
  3073  	spec, conf := sleepSpecConf(t)
  3074  	_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  3075  	if err != nil {
  3076  		t.Fatalf("error setting up container: %v", err)
  3077  	}
  3078  	defer cleanup()
  3079  
  3080  	args := Args{
  3081  		ID:        testutil.RandomContainerID(),
  3082  		Spec:      spec,
  3083  		BundleDir: bundleDir,
  3084  	}
  3085  
  3086  	cont, err := New(conf, args)
  3087  	if err != nil {
  3088  		t.Fatalf("Creating container: %v", err)
  3089  	}
  3090  	defer cont.Destroy()
  3091  
  3092  	if err := cont.Start(conf); err != nil {
  3093  		t.Fatalf("starting container: %v", err)
  3094  	}
  3095  
  3096  	// Find the echo binary on the host.
  3097  	echoPath := findInPath("echo")
  3098  	if echoPath == "" {
  3099  		t.Fatalf("failed to find echo executable in PATH")
  3100  	}
  3101  
  3102  	// Open the echo binary as a file.
  3103  	echoFile, err := os.Open(echoPath)
  3104  	if err != nil {
  3105  		t.Fatalf("opening echo binary: %v", err)
  3106  	}
  3107  	defer echoFile.Close()
  3108  
  3109  	// Note that we do not supply the name or path of the echo binary here.
  3110  	// Thus, the guest does not know the binary path or name either.
  3111  	// argv[0] inside echo is "can be anything".
  3112  	got, err := executeCombinedOutput(conf, cont, echoFile, "can be anything", "hello world")
  3113  	if err != nil {
  3114  		t.Fatal(err)
  3115  	}
  3116  	if want := "hello world\n"; string(got) != want {
  3117  		t.Errorf("echo result, got: %q, want: %q", got, want)
  3118  	}
  3119  }
  3120  
  3121  // skipIfNotAvailable skips the test if the requested executable files are not available.
  3122  func skipIfNotAvailable(t *testing.T, files ...string) {
  3123  	for _, f := range files {
  3124  		if _, err := exec.LookPath(f); err != nil {
  3125  			t.Skipf("%v is not available: %v", f, err)
  3126  		}
  3127  	}
  3128  }
  3129  
  3130  // createImageEROFS creates the EROFS image from the source directory using the requested options.
  3131  func createImageEROFS(image, source string, options ...string) error {
  3132  	mkfs, err := exec.LookPath("mkfs.erofs")
  3133  	if err != nil {
  3134  		return fmt.Errorf("mkfs.erofs is not available: %v", err)
  3135  	}
  3136  	cmd := fmt.Sprintf("%s %s %s %s", mkfs, strings.Join(options, " "), image, source)
  3137  	if out, err := exec.Command("/bin/sh", "-c", cmd).CombinedOutput(); err != nil {
  3138  		return fmt.Errorf("exec: sh -c %q, err: %v, out: %s", cmd, err, out)
  3139  	}
  3140  	return nil
  3141  }
  3142  
  3143  // TestMountEROFS checks that the checksums from the target directory in the container
  3144  // are identical with the ones from the source directory on the host.
  3145  func TestMountEROFS(t *testing.T) {
  3146  	// Skip this test if mkfs.erofs is not available.
  3147  	skipIfNotAvailable(t, "mkfs.erofs")
  3148  
  3149  	// Create a temporary directory to save the test files.
  3150  	testDir, err := ioutil.TempDir(testutil.TmpDir(), "erofs_mount_test_")
  3151  	if err != nil {
  3152  		t.Fatalf("ioutil.TempDir() failed: %v", err)
  3153  	}
  3154  	defer os.RemoveAll(testDir)
  3155  
  3156  	// Create a temporary directory with some random files in it, which will
  3157  	// be used as the source directory to create the EROFS images.
  3158  	sourceDir := filepath.Join(testDir, "source")
  3159  	if err := os.Mkdir(sourceDir, 0755); err != nil {
  3160  		t.Fatalf("os.Mkdir() failed: %v", err)
  3161  	}
  3162  	// Create some files with leading non-alphanumeric characters in name. It's helpful
  3163  	// to verify the on-disk directory entries order.
  3164  	for _, c := range []byte("!#$%&()*+,-:;<=>?@[]^_`{|}~") {
  3165  		name := fmt.Sprintf("%s/%c_file", sourceDir, c)
  3166  		// Create the file with random data.
  3167  		if err := ioutil.WriteFile(name, []byte(fmt.Sprintf("%v", rand.Uint64())), 0644); err != nil {
  3168  			t.Fatalf("error creating %q: %v", name, err)
  3169  		}
  3170  	}
  3171  	testApp, err := testutil.FindFile("test/cmd/test_app/test_app")
  3172  	if err != nil {
  3173  		t.Fatalf("error finding test_app: %v", err)
  3174  	}
  3175  	// Source directory is a small directory. Let's create a big directory in it.
  3176  	// So we can cover both cases.
  3177  	cmd := fmt.Sprintf("%s fsTreeCreate --target-dir=%s --create-symlink --depth=1 --file-per-level=500 --file-size=5000", testApp, filepath.Join(sourceDir, "big-directory"))
  3178  	if out, err := exec.Command("/bin/sh", "-c", cmd).CombinedOutput(); err != nil {
  3179  		t.Fatalf("exec: sh -c %q, err: %v, out: %s", cmd, err, out)
  3180  	}
  3181  
  3182  	// Create a test script which can be used to get the checksums
  3183  	// from a specified directory.
  3184  	scriptFile := filepath.Join(testDir, "test-script")
  3185  	if err := os.WriteFile(scriptFile, []byte(`#!/bin/bash
  3186  set -u -e -o pipefail
  3187  dir=$1
  3188  find $dir -printf "%P\n" | sort | md5sum
  3189  find $dir -type l | sort | xargs -L 1 readlink | md5sum
  3190  find $dir -type l -o -type f | sort | xargs cat | md5sum`), 0755); err != nil {
  3191  		t.Fatalf("os.WriteFile() failed: %v", err)
  3192  	}
  3193  
  3194  	// Get the checksums from the source directory on the host.
  3195  	var checksums string
  3196  	if out, err := exec.Command(scriptFile, sourceDir).CombinedOutput(); err != nil {
  3197  		t.Fatalf("exec: %s %s, err: %v, out: %s", scriptFile, sourceDir, err, out)
  3198  	} else {
  3199  		checksums = string(out)
  3200  	}
  3201  
  3202  	images := []struct {
  3203  		name    string
  3204  		options string
  3205  	}{
  3206  		{
  3207  			// Generate extended inodes. Inline regular files if possible.
  3208  			name:    "image1",
  3209  			options: "-E force-inode-extended",
  3210  		},
  3211  		{
  3212  			// Generate extended inodes. Do not inline regular files.
  3213  			name:    "image2",
  3214  			options: "-E force-inode-extended -E noinline_data",
  3215  		},
  3216  		{
  3217  			// Generate compact inodes. Inline regular files if possible.
  3218  			name:    "image3",
  3219  			options: "-E force-inode-compact",
  3220  		},
  3221  		{
  3222  			// Generate compact inodes. Do not inline regular files.
  3223  			name:    "image4",
  3224  			options: "-E force-inode-compact -E noinline_data",
  3225  		},
  3226  	}
  3227  
  3228  	// Create the EROFS images.
  3229  	for _, i := range images {
  3230  		if err := createImageEROFS(filepath.Join(testDir, i.name), sourceDir, i.options); err != nil {
  3231  			t.Fatalf("error creating EROFS image: %v", err)
  3232  		}
  3233  	}
  3234  
  3235  	spec, conf := sleepSpecConf(t)
  3236  	_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  3237  	if err != nil {
  3238  		t.Fatalf("error setting up container: %v", err)
  3239  	}
  3240  	defer cleanup()
  3241  
  3242  	// Create and start the container.
  3243  	args := Args{
  3244  		ID:        testutil.RandomContainerID(),
  3245  		Spec:      spec,
  3246  		BundleDir: bundleDir,
  3247  	}
  3248  	c, err := New(conf, args)
  3249  	if err != nil {
  3250  		t.Fatalf("error creating container: %v", err)
  3251  	}
  3252  	defer c.Destroy()
  3253  	if err := c.Start(conf); err != nil {
  3254  		t.Fatalf("error starting container: %v", err)
  3255  	}
  3256  
  3257  	targetDir := "/mnt"
  3258  	for _, i := range images {
  3259  		// Mount the EROFS image in the container.
  3260  		imageFile := filepath.Join(testDir, i.name)
  3261  		if err := c.Sandbox.Mount(c.ID, erofs.Name, imageFile, targetDir); err != nil {
  3262  			t.Fatalf("error mounting EROFS image %q at %q, err: %v", imageFile, targetDir, err)
  3263  		}
  3264  
  3265  		// Get the checksums from the target directory in the container, and check if they are
  3266  		// identical with the ones got from the source directory on the host.
  3267  		if out, err := executeCombinedOutput(conf, c, nil, scriptFile, targetDir); err != nil {
  3268  			t.Fatalf("exec: %s %s, err: %v, out: %s", scriptFile, targetDir, err, out)
  3269  		} else if checksums != string(out) {
  3270  			t.Errorf("checksums do not match, got: %s from %s, expected: %s", out, imageFile, checksums)
  3271  		}
  3272  
  3273  		// Unmount the EROFS image in the container.
  3274  		if out, err := executeCombinedOutput(conf, c, nil, "/bin/umount", targetDir); err != nil {
  3275  			t.Fatalf("exec: umount %q, err: %v, out: %s", targetDir, err, out)
  3276  		}
  3277  	}
  3278  }
  3279  
  3280  // createRootfsEROFS creates a rootfs directory and an EROFS rootfs image in
  3281  // the directory dir.
  3282  func createRootfsEROFS(dir string) (string, string, error) {
  3283  	// Create a rootfs directory with busybox in root.
  3284  	rootfsDir := filepath.Join(dir, "rootfs")
  3285  	if err := os.Mkdir(rootfsDir, 0755); err != nil {
  3286  		return "", "", fmt.Errorf("os.Mkdir() failed: %v", err)
  3287  	}
  3288  	busybox, err := exec.LookPath("busybox")
  3289  	if err != nil {
  3290  		return "", "", fmt.Errorf("busybox is not available: %v", err)
  3291  	}
  3292  	if err := testutil.Copy(busybox, filepath.Join(rootfsDir, "busybox")); err != nil {
  3293  		return "", "", fmt.Errorf("failed to copy busybox: %v", err)
  3294  	}
  3295  
  3296  	// Handcraft the following mount points that the sentry mounts need, because EROFS
  3297  	// does not support creating synthetic directories yet and we may not want to use
  3298  	// overlay in some tests.
  3299  	for _, dir := range []string{"dev", "proc", "sys", "tmp"} {
  3300  		if err := os.Mkdir(filepath.Join(rootfsDir, dir), 0755); err != nil {
  3301  			return "", "", fmt.Errorf("os.Mkdir() failed: %v", err)
  3302  		}
  3303  	}
  3304  
  3305  	// Build the EROFS rootfs image.
  3306  	rootfsImage := filepath.Join(dir, "rootfs.img")
  3307  	if err := createImageEROFS(rootfsImage, rootfsDir, "-E noinline_data"); err != nil {
  3308  		return "", "", fmt.Errorf("error creating EROFS image: %v", err)
  3309  	}
  3310  
  3311  	return rootfsDir, rootfsImage, nil
  3312  }
  3313  
  3314  // TestRootfsEROFS starts a container using an EROFS image as the rootfs and checks that
  3315  // the rootfs in the container is an EROFS.
  3316  func TestRootfsEROFS(t *testing.T) {
  3317  	// Skip this test if mkfs.erofs or busybox are not available.
  3318  	skipIfNotAvailable(t, "mkfs.erofs", "busybox")
  3319  
  3320  	testDir, err := ioutil.TempDir(testutil.TmpDir(), "erofs_rootfs_test_")
  3321  	if err != nil {
  3322  		t.Fatalf("ioutil.TempDir() failed: %v", err)
  3323  	}
  3324  	defer os.RemoveAll(testDir)
  3325  
  3326  	rootfsDir, rootfsImage, err := createRootfsEROFS(testDir)
  3327  	if err != nil {
  3328  		t.Fatalf("failed to create EROFS rootfs image: %v", err)
  3329  	}
  3330  
  3331  	// Create the spec and set the EROFS rootfs annotations.
  3332  	spec := testutil.NewSpecWithArgs("/busybox", "grep", "/ / ro - erofs", "/proc/self/mountinfo")
  3333  	spec.Root.Path = rootfsDir
  3334  	if spec.Annotations == nil {
  3335  		spec.Annotations = make(map[string]string)
  3336  	}
  3337  	spec.Annotations[boot.RootfsPrefix+"type"] = erofs.Name
  3338  	spec.Annotations[boot.RootfsPrefix+"source"] = rootfsImage
  3339  	// Disable the overlay, as we want to be sure that rootfs will always be
  3340  	// shown as EROFS in mountinfo.
  3341  	spec.Annotations[boot.RootfsPrefix+"overlay"] = config.NoOverlay.String()
  3342  
  3343  	conf := testutil.TestConfig(t)
  3344  
  3345  	for _, mounts := range [][]specs.Mount{
  3346  		// Case 1: EROFS rootfs without any other gofer mount.
  3347  		nil,
  3348  
  3349  		// Case 2: EROFS rootfs with a LISAFS backed gofer mount.
  3350  		[]specs.Mount{
  3351  			{
  3352  				Type:        "bind",
  3353  				Destination: "/tmp",
  3354  				Source:      "/tmp",
  3355  			},
  3356  		},
  3357  	} {
  3358  		spec.Mounts = mounts
  3359  
  3360  		_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  3361  		if err != nil {
  3362  			t.Fatalf("error setting up container: %v", err)
  3363  		}
  3364  		defer cleanup()
  3365  
  3366  		// Create and start the container.
  3367  		args := Args{
  3368  			ID:        testutil.RandomContainerID(),
  3369  			Spec:      spec,
  3370  			BundleDir: bundleDir,
  3371  			Attached:  true,
  3372  		}
  3373  		ws, err := Run(conf, args)
  3374  		if err != nil {
  3375  			t.Fatalf("error running container: %v", err)
  3376  		}
  3377  		if ws.ExitStatus() != 0 {
  3378  			t.Errorf("got exit status %v want %v", ws.ExitStatus(), 0)
  3379  		}
  3380  	}
  3381  }
  3382  
  3383  // TestCheckpointRestoreEROFS does the checkpoint/restore test on each platform using
  3384  // an EROFS image as the rootfs.
  3385  func TestCheckpointRestoreEROFS(t *testing.T) {
  3386  	// Skip this test if mkfs.erofs or busybox are not available.
  3387  	skipIfNotAvailable(t, "mkfs.erofs", "busybox")
  3388  
  3389  	testDir, err := ioutil.TempDir(testutil.TmpDir(), "erofs_checkpoint_restore_test_")
  3390  	if err != nil {
  3391  		t.Fatalf("ioutil.TempDir() failed: %v", err)
  3392  	}
  3393  	defer os.RemoveAll(testDir)
  3394  
  3395  	rootfsDir, rootfsImage, err := createRootfsEROFS(testDir)
  3396  	if err != nil {
  3397  		t.Fatalf("failed to create EROFS rootfs image: %v", err)
  3398  	}
  3399  
  3400  	// Skip overlay because test requires writing to host file.
  3401  	for name, conf := range configs(t, true /* noOverlay */) {
  3402  		t.Run(name, func(t *testing.T) {
  3403  			testCheckpointRestore(t, conf, statefile.CompressionLevelDefault, func(script string) *specs.Spec {
  3404  				spec := testutil.NewSpecWithArgs("/busybox", "sh", "-c", script)
  3405  				spec.Root = &specs.Root{
  3406  					Path:     rootfsDir,
  3407  					Readonly: false,
  3408  				}
  3409  				if spec.Annotations == nil {
  3410  					spec.Annotations = make(map[string]string)
  3411  				}
  3412  				spec.Annotations[boot.RootfsPrefix+"type"] = erofs.Name
  3413  				spec.Annotations[boot.RootfsPrefix+"source"] = rootfsImage
  3414  				// EROFS does not support creating synthetic directories yet, so let's add
  3415  				// a writeable and savable overlay for rootfs, which allows the sentry to
  3416  				// create the mount point for the bind mount of the temporary directory shared
  3417  				// between host and test container.
  3418  				spec.Annotations[boot.RootfsPrefix+"overlay"] = config.MemoryOverlay.String()
  3419  				return spec
  3420  			})
  3421  		})
  3422  	}
  3423  }
  3424  
  3425  // TestLookupEROFS reads the files in EROFS images, which contain some random files,
  3426  // and checks if the data is as expected.
  3427  func TestLookupEROFS(t *testing.T) {
  3428  	// Skip this test if mkfs.erofs is not available.
  3429  	skipIfNotAvailable(t, "mkfs.erofs")
  3430  
  3431  	// Create a temporary directory to save the test files.
  3432  	testDir, err := ioutil.TempDir(testutil.TmpDir(), "erofs_lookup_test_")
  3433  	if err != nil {
  3434  		t.Fatalf("ioutil.TempDir() failed: %v", err)
  3435  	}
  3436  	defer os.RemoveAll(testDir)
  3437  
  3438  	spec, conf := sleepSpecConf(t)
  3439  	_, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
  3440  	if err != nil {
  3441  		t.Fatalf("error setting up container: %v", err)
  3442  	}
  3443  	defer cleanup()
  3444  
  3445  	// Create and start the container.
  3446  	args := Args{
  3447  		ID:        testutil.RandomContainerID(),
  3448  		Spec:      spec,
  3449  		BundleDir: bundleDir,
  3450  	}
  3451  	c, err := New(conf, args)
  3452  	if err != nil {
  3453  		t.Fatalf("error creating container: %v", err)
  3454  	}
  3455  	defer c.Destroy()
  3456  	if err := c.Start(conf); err != nil {
  3457  		t.Fatalf("error starting container: %v", err)
  3458  	}
  3459  
  3460  	tcs := []struct {
  3461  		name string
  3462  		size int
  3463  	}{
  3464  		{
  3465  			name: "tiny",
  3466  			size: 1,
  3467  		},
  3468  		{
  3469  			name: "small",
  3470  			size: 10,
  3471  		},
  3472  		{
  3473  			name: "medium",
  3474  			size: 100,
  3475  		},
  3476  		{
  3477  			name: "large",
  3478  			size: 1000,
  3479  		},
  3480  	}
  3481  
  3482  	targetDir := "/mnt"
  3483  	for _, tc := range tcs {
  3484  		// Add some randomness to the number of files.
  3485  		size := tc.size + rand.Intn(tc.size)
  3486  
  3487  		// Create a temporary directory with some random files in it, which will
  3488  		// be used as the source directory to create the EROFS image.
  3489  		sourceDir := filepath.Join(testDir, tc.name)
  3490  		if err := os.Mkdir(sourceDir, 0755); err != nil {
  3491  			t.Fatalf("os.Mkdir() failed: %v", err)
  3492  		}
  3493  		randomFiles := make([]string, 0, size)
  3494  		for i := 0; i < size; i++ {
  3495  			file, err := ioutil.TempFile(sourceDir, "")
  3496  			if err != nil {
  3497  				t.Fatalf("ioutil.TempFile() failed: %v", err)
  3498  			}
  3499  			name := filepath.Base(file.Name())
  3500  			if _, err := file.Write([]byte(name)); err != nil {
  3501  				t.Fatalf("file.Write() failed: %v", err)
  3502  			}
  3503  			file.Close()
  3504  			randomFiles = append(randomFiles, name)
  3505  		}
  3506  
  3507  		// Create the EROFS image.
  3508  		imageFile := filepath.Join(testDir, fmt.Sprintf("%s.img", tc.name))
  3509  		if err := createImageEROFS(imageFile, sourceDir); err != nil {
  3510  			t.Fatalf("error creating EROFS image: %v", err)
  3511  		}
  3512  
  3513  		// Mount the EROFS image in the container.
  3514  		if err := c.Sandbox.Mount(c.ID, erofs.Name, imageFile, targetDir); err != nil {
  3515  			t.Fatalf("error mounting EROFS image %q at %q, err: %v", imageFile, targetDir, err)
  3516  		}
  3517  
  3518  		// Read the files in the EROFS image and check if the data is as expected.
  3519  		for i, inc := 0, max(size/100, 1); i < size; i += inc {
  3520  			targetFile := randomFiles[i]
  3521  			cmd := fmt.Sprintf("cat %s", filepath.Join(targetDir, targetFile))
  3522  			if out, err := executeCombinedOutput(conf, c, nil, "/bin/sh", "-c", cmd); err != nil {
  3523  				t.Fatalf("exec: sh -c %q, err: %v, out: %s", cmd, err, out)
  3524  			} else if targetFile != string(out) {
  3525  				t.Errorf("file does not match, got: %s, expected: %s", out, targetFile)
  3526  			}
  3527  		}
  3528  
  3529  		// Test for the read failure with a non-existent file.
  3530  		cmd := fmt.Sprintf("cat %s", filepath.Join(targetDir, "nonexist"))
  3531  		if out, err := executeCombinedOutput(conf, c, nil, "/bin/sh", "-c", cmd); err == nil {
  3532  			t.Errorf("exec: sh -c %q, succeeded to read the non-existent file: %s", cmd, out)
  3533  		}
  3534  
  3535  		// Unmount the EROFS image in the container.
  3536  		if out, err := executeCombinedOutput(conf, c, nil, "/bin/umount", targetDir); err != nil {
  3537  			t.Fatalf("exec: umount %q, err: %v, out: %s", targetDir, err, out)
  3538  		}
  3539  	}
  3540  }