github.com/ttpreport/gvisor-ligolo@v0.0.0-20240123134145-a858404967ba/runsc/boot/loader.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 boot loads the kernel and runs a container.
    16  package boot
    17  
    18  import (
    19  	"errors"
    20  	"fmt"
    21  	mrand "math/rand"
    22  	"os"
    23  	"runtime"
    24  	gtime "time"
    25  
    26  	specs "github.com/opencontainers/runtime-spec/specs-go"
    27  	"github.com/syndtr/gocapability/capability"
    28  	"github.com/ttpreport/gvisor-ligolo/pkg/abi/linux"
    29  	"github.com/ttpreport/gvisor-ligolo/pkg/bpf"
    30  	"github.com/ttpreport/gvisor-ligolo/pkg/cleanup"
    31  	"github.com/ttpreport/gvisor-ligolo/pkg/context"
    32  	"github.com/ttpreport/gvisor-ligolo/pkg/coverage"
    33  	"github.com/ttpreport/gvisor-ligolo/pkg/cpuid"
    34  	"github.com/ttpreport/gvisor-ligolo/pkg/fd"
    35  	"github.com/ttpreport/gvisor-ligolo/pkg/log"
    36  	"github.com/ttpreport/gvisor-ligolo/pkg/memutil"
    37  	"github.com/ttpreport/gvisor-ligolo/pkg/rand"
    38  	"github.com/ttpreport/gvisor-ligolo/pkg/refs"
    39  	"github.com/ttpreport/gvisor-ligolo/pkg/sentry/control"
    40  	"github.com/ttpreport/gvisor-ligolo/pkg/sentry/fdimport"
    41  	"github.com/ttpreport/gvisor-ligolo/pkg/sentry/fsimpl/host"
    42  	"github.com/ttpreport/gvisor-ligolo/pkg/sentry/fsimpl/tmpfs"
    43  	"github.com/ttpreport/gvisor-ligolo/pkg/sentry/fsimpl/user"
    44  	"github.com/ttpreport/gvisor-ligolo/pkg/sentry/inet"
    45  	"github.com/ttpreport/gvisor-ligolo/pkg/sentry/kernel"
    46  	"github.com/ttpreport/gvisor-ligolo/pkg/sentry/kernel/auth"
    47  	"github.com/ttpreport/gvisor-ligolo/pkg/sentry/loader"
    48  	"github.com/ttpreport/gvisor-ligolo/pkg/sentry/pgalloc"
    49  	"github.com/ttpreport/gvisor-ligolo/pkg/sentry/platform"
    50  	"github.com/ttpreport/gvisor-ligolo/pkg/sentry/seccheck"
    51  	pb "github.com/ttpreport/gvisor-ligolo/pkg/sentry/seccheck/points/points_go_proto"
    52  	"github.com/ttpreport/gvisor-ligolo/pkg/sentry/socket/netfilter"
    53  	"github.com/ttpreport/gvisor-ligolo/pkg/sentry/time"
    54  	"github.com/ttpreport/gvisor-ligolo/pkg/sentry/usage"
    55  	"github.com/ttpreport/gvisor-ligolo/pkg/sentry/vfs"
    56  	"github.com/ttpreport/gvisor-ligolo/pkg/sentry/watchdog"
    57  	"github.com/ttpreport/gvisor-ligolo/pkg/sighandling"
    58  	"github.com/ttpreport/gvisor-ligolo/pkg/sync"
    59  	"github.com/ttpreport/gvisor-ligolo/pkg/tcpip"
    60  	"github.com/ttpreport/gvisor-ligolo/pkg/tcpip/link/ethernet"
    61  	"github.com/ttpreport/gvisor-ligolo/pkg/tcpip/link/loopback"
    62  	"github.com/ttpreport/gvisor-ligolo/pkg/tcpip/link/packetsocket"
    63  	"github.com/ttpreport/gvisor-ligolo/pkg/tcpip/link/sniffer"
    64  	"github.com/ttpreport/gvisor-ligolo/pkg/tcpip/network/arp"
    65  	"github.com/ttpreport/gvisor-ligolo/pkg/tcpip/network/ipv4"
    66  	"github.com/ttpreport/gvisor-ligolo/pkg/tcpip/network/ipv6"
    67  	"github.com/ttpreport/gvisor-ligolo/pkg/tcpip/stack"
    68  	"github.com/ttpreport/gvisor-ligolo/pkg/tcpip/transport/icmp"
    69  	"github.com/ttpreport/gvisor-ligolo/pkg/tcpip/transport/raw"
    70  	"github.com/ttpreport/gvisor-ligolo/pkg/tcpip/transport/tcp"
    71  	"github.com/ttpreport/gvisor-ligolo/pkg/tcpip/transport/udp"
    72  	"github.com/ttpreport/gvisor-ligolo/runsc/boot/filter"
    73  	_ "github.com/ttpreport/gvisor-ligolo/runsc/boot/platforms" // register all platforms.
    74  	pf "github.com/ttpreport/gvisor-ligolo/runsc/boot/portforward"
    75  	"github.com/ttpreport/gvisor-ligolo/runsc/boot/pprof"
    76  	"github.com/ttpreport/gvisor-ligolo/runsc/config"
    77  	"github.com/ttpreport/gvisor-ligolo/runsc/profile"
    78  	"github.com/ttpreport/gvisor-ligolo/runsc/specutils"
    79  	"github.com/ttpreport/gvisor-ligolo/runsc/specutils/seccomp"
    80  	"golang.org/x/sys/unix"
    81  
    82  	// Top-level inet providers.
    83  	"github.com/ttpreport/gvisor-ligolo/pkg/sentry/socket/hostinet"
    84  	"github.com/ttpreport/gvisor-ligolo/pkg/sentry/socket/netstack"
    85  
    86  	// Include other supported socket providers.
    87  	_ "github.com/ttpreport/gvisor-ligolo/pkg/sentry/socket/netlink"
    88  	_ "github.com/ttpreport/gvisor-ligolo/pkg/sentry/socket/netlink/route"
    89  	_ "github.com/ttpreport/gvisor-ligolo/pkg/sentry/socket/netlink/uevent"
    90  	_ "github.com/ttpreport/gvisor-ligolo/pkg/sentry/socket/unix"
    91  )
    92  
    93  type containerInfo struct {
    94  	conf *config.Config
    95  
    96  	// spec is the base configuration for the root container.
    97  	spec *specs.Spec
    98  
    99  	// procArgs refers to the container's init task.
   100  	procArgs kernel.CreateProcessArgs
   101  
   102  	// stdioFDs contains stdin, stdout, and stderr.
   103  	stdioFDs []*fd.FD
   104  
   105  	// passFDs are mappings of user-supplied host to guest file descriptors.
   106  	passFDs []fdMapping
   107  
   108  	// execFD is the host file descriptor used for program execution.
   109  	execFD *fd.FD
   110  
   111  	// goferFDs are the FDs that attach the sandbox to the gofers.
   112  	goferFDs []*fd.FD
   113  
   114  	// overlayFilestoreFDs are the FDs to the regular files that will back the
   115  	// tmpfs upper mount in the overlay mounts.
   116  	overlayFilestoreFDs []*fd.FD
   117  
   118  	// overlayMediums contains information about how the gofer mounts have been
   119  	// overlaid. The first entry is for rootfs and the following entries are for
   120  	// bind mounts in spec.Mounts (in the same order).
   121  	overlayMediums []OverlayMedium
   122  
   123  	// nvidiaUVMDevMajor is the device major number used for nvidia-uvm.
   124  	nvidiaUVMDevMajor uint32
   125  }
   126  
   127  // Loader keeps state needed to start the kernel and run the container.
   128  type Loader struct {
   129  	// k is the kernel.
   130  	k *kernel.Kernel
   131  
   132  	// ctrl is the control server.
   133  	ctrl *controller
   134  
   135  	// root contains information about the root container in the sandbox.
   136  	root containerInfo
   137  
   138  	watchdog *watchdog.Watchdog
   139  
   140  	// stopSignalForwarding disables forwarding of signals to the sandboxed
   141  	// container. It should be called when a sandbox is destroyed.
   142  	stopSignalForwarding func()
   143  
   144  	// stopProfiling stops profiling started at container creation. It
   145  	// should be called when a sandbox is destroyed.
   146  	stopProfiling func()
   147  
   148  	// PreSeccompCallback is called right before installing seccomp filters.
   149  	PreSeccompCallback func()
   150  
   151  	// restore is set to true if we are restoring a container.
   152  	restore bool
   153  
   154  	// sandboxID is the ID for the whole sandbox.
   155  	sandboxID string
   156  
   157  	// mountHints provides extra information about mounts for containers that
   158  	// apply to the entire pod.
   159  	mountHints *PodMountHints
   160  
   161  	// productName is the value to show in
   162  	// /sys/devices/virtual/dmi/id/product_name.
   163  	productName string
   164  
   165  	// nvidiaUVMDevMajor is the device major number used for nvidia-uvm.
   166  	nvidiaUVMDevMajor uint32
   167  
   168  	// mu guards processes and porForwardProxies.
   169  	mu sync.Mutex
   170  
   171  	// processes maps containers init process and invocation of exec. Root
   172  	// processes are keyed with container ID and pid=0, while exec invocations
   173  	// have the corresponding pid set.
   174  	//
   175  	// processes is guarded by mu.
   176  	processes map[execID]*execProcess
   177  
   178  	// portForwardProxies is a list of active port forwarding connections.
   179  	//
   180  	// portForwardProxies is guarded by mu.
   181  	portForwardProxies []*pf.Proxy
   182  }
   183  
   184  // execID uniquely identifies a sentry process that is executed in a container.
   185  type execID struct {
   186  	cid string
   187  	pid kernel.ThreadID
   188  }
   189  
   190  // execProcess contains the thread group and host TTY of a sentry process.
   191  type execProcess struct {
   192  	// tg will be nil for containers that haven't started yet.
   193  	tg *kernel.ThreadGroup
   194  
   195  	// tty will be nil if the process is not attached to a terminal.
   196  	tty *host.TTYFileDescription
   197  
   198  	// pidnsPath is the pid namespace path in spec
   199  	pidnsPath string
   200  
   201  	// hostTTY is present when creating a sub-container with terminal enabled.
   202  	// TTY file is passed during container create and must be saved until
   203  	// container start.
   204  	hostTTY *fd.FD
   205  }
   206  
   207  // fdMapping maps guest to host file descriptors. Guest file descriptors are
   208  // exposed to the application inside the sandbox through the FD table.
   209  type fdMapping struct {
   210  	guest int
   211  	host  *fd.FD
   212  }
   213  
   214  // FDMapping is a helper type to represent a mapping from guest to host file
   215  // descriptors. In contrast to the unexported fdMapping type, it does not imply
   216  // file ownership.
   217  type FDMapping struct {
   218  	Guest int
   219  	Host  int
   220  }
   221  
   222  func init() {
   223  	// Initialize the random number generator.
   224  	mrand.Seed(gtime.Now().UnixNano())
   225  }
   226  
   227  // Args are the arguments for New().
   228  type Args struct {
   229  	// Id is the sandbox ID.
   230  	ID string
   231  	// Spec is the sandbox specification.
   232  	Spec *specs.Spec
   233  	// Conf is the system configuration.
   234  	Conf *config.Config
   235  	// ControllerFD is the FD to the URPC controller. The Loader takes ownership
   236  	// of this FD and may close it at any time.
   237  	ControllerFD int
   238  	// Device is an optional argument that is passed to the platform. The Loader
   239  	// takes ownership of this file and may close it at any time.
   240  	Device *os.File
   241  	// GoferFDs is an array of FDs used to connect with the Gofer. The Loader
   242  	// takes ownership of these FDs and may close them at any time.
   243  	GoferFDs []int
   244  	// StdioFDs is the stdio for the application. The Loader takes ownership of
   245  	// these FDs and may close them at any time.
   246  	StdioFDs []int
   247  	// PassFDs are user-supplied FD mappings from host to guest descriptors.
   248  	// The Loader takes ownership of these FDs and may close them at any time.
   249  	PassFDs []FDMapping
   250  	// ExecFD is the host file descriptor used for program execution.
   251  	ExecFD int
   252  	// OverlayFilestoreFDs are the FDs to the regular files that will back the
   253  	// tmpfs upper mount in the overlay mounts.
   254  	OverlayFilestoreFDs []int
   255  	// OverlayMediums contains information about how the gofer mounts have been
   256  	// overlaid. The first entry is for rootfs and the following entries are for
   257  	// bind mounts in Spec.Mounts (in the same order).
   258  	OverlayMediums []OverlayMedium
   259  	// NumCPU is the number of CPUs to create inside the sandbox.
   260  	NumCPU int
   261  	// TotalMem is the initial amount of total memory to report back to the
   262  	// container.
   263  	TotalMem uint64
   264  	// TotalHostMem is the total memory reported by host /proc/meminfo.
   265  	TotalHostMem uint64
   266  	// UserLogFD is the file descriptor to write user logs to.
   267  	UserLogFD int
   268  	// ProductName is the value to show in
   269  	// /sys/devices/virtual/dmi/id/product_name.
   270  	ProductName string
   271  	// PodInitConfigFD is the file descriptor to a file passed in the
   272  	//	--pod-init-config flag
   273  	PodInitConfigFD int
   274  	// SinkFDs is an ordered array of file descriptors to be used by seccheck
   275  	// sinks configured from the --pod-init-config file.
   276  	SinkFDs []int
   277  	// ProfileOpts contains the set of profiles to enable and the
   278  	// corresponding FDs where profile data will be written.
   279  	ProfileOpts profile.Opts
   280  }
   281  
   282  // make sure stdioFDs are always the same on initial start and on restore
   283  const startingStdioFD = 256
   284  
   285  // New initializes a new kernel loader configured by spec.
   286  // New also handles setting up a kernel for restoring a container.
   287  func New(args Args) (*Loader, error) {
   288  	stopProfiling := profile.Start(args.ProfileOpts)
   289  
   290  	// Initialize seccheck points.
   291  	seccheck.Initialize()
   292  
   293  	// We initialize the rand package now to make sure /dev/urandom is pre-opened
   294  	// on kernels that do not support getrandom(2).
   295  	if err := rand.Init(); err != nil {
   296  		return nil, fmt.Errorf("setting up rand: %w", err)
   297  	}
   298  
   299  	if err := usage.Init(); err != nil {
   300  		return nil, fmt.Errorf("setting up memory usage: %w", err)
   301  	}
   302  
   303  	kernel.IOUringEnabled = args.Conf.IOUring
   304  
   305  	info := containerInfo{
   306  		conf:           args.Conf,
   307  		spec:           args.Spec,
   308  		overlayMediums: args.OverlayMediums,
   309  	}
   310  
   311  	// Make host FDs stable between invocations. Host FDs must map to the exact
   312  	// same number when the sandbox is restored. Otherwise the wrong FD will be
   313  	// used.
   314  	newfd := startingStdioFD
   315  
   316  	for _, stdioFD := range args.StdioFDs {
   317  		// Check that newfd is unused to avoid clobbering over it.
   318  		if _, err := unix.FcntlInt(uintptr(newfd), unix.F_GETFD, 0); !errors.Is(err, unix.EBADF) {
   319  			if err != nil {
   320  				return nil, fmt.Errorf("error checking for FD (%d) conflict: %w", newfd, err)
   321  			}
   322  			return nil, fmt.Errorf("unable to remap stdios, FD %d is already in use", newfd)
   323  		}
   324  
   325  		err := unix.Dup3(stdioFD, newfd, unix.O_CLOEXEC)
   326  		if err != nil {
   327  			return nil, fmt.Errorf("dup3 of stdios failed: %w", err)
   328  		}
   329  		info.stdioFDs = append(info.stdioFDs, fd.New(newfd))
   330  		_ = unix.Close(stdioFD)
   331  		newfd++
   332  	}
   333  	for _, goferFD := range args.GoferFDs {
   334  		info.goferFDs = append(info.goferFDs, fd.New(goferFD))
   335  	}
   336  	for _, overlayFD := range args.OverlayFilestoreFDs {
   337  		info.overlayFilestoreFDs = append(info.overlayFilestoreFDs, fd.New(overlayFD))
   338  	}
   339  
   340  	if args.ExecFD >= 0 {
   341  		info.execFD = fd.New(args.ExecFD)
   342  	}
   343  
   344  	for _, customFD := range args.PassFDs {
   345  		info.passFDs = append(info.passFDs, fdMapping{
   346  			host:  fd.New(customFD.Host),
   347  			guest: customFD.Guest,
   348  		})
   349  	}
   350  
   351  	// Create kernel and platform.
   352  	p, err := createPlatform(args.Conf, args.Device)
   353  	if err != nil {
   354  		return nil, fmt.Errorf("creating platform: %w", err)
   355  	}
   356  	if args.Conf.NVProxy && p.OwnsPageTables() {
   357  		return nil, fmt.Errorf("--nvproxy is incompatible with platform %s: owns page tables", args.Conf.Platform)
   358  	}
   359  	k := &kernel.Kernel{
   360  		Platform: p,
   361  	}
   362  
   363  	// Create memory file.
   364  	mf, err := createMemoryFile()
   365  	if err != nil {
   366  		return nil, fmt.Errorf("creating memory file: %w", err)
   367  	}
   368  	k.SetMemoryFile(mf)
   369  
   370  	// Create VDSO.
   371  	//
   372  	// Pass k as the platform since it is savable, unlike the actual platform.
   373  	vdso, err := loader.PrepareVDSO(k)
   374  	if err != nil {
   375  		return nil, fmt.Errorf("creating vdso: %w", err)
   376  	}
   377  
   378  	// Create timekeeper.
   379  	tk := kernel.NewTimekeeper(k, vdso.ParamPage.FileRange())
   380  	tk.SetClocks(time.NewCalibratedClocks())
   381  
   382  	if err := enableStrace(args.Conf); err != nil {
   383  		return nil, fmt.Errorf("enabling strace: %w", err)
   384  	}
   385  
   386  	// Create capabilities.
   387  	caps, err := specutils.Capabilities(args.Conf.EnableRaw, args.Spec.Process.Capabilities)
   388  	if err != nil {
   389  		return nil, fmt.Errorf("converting capabilities: %w", err)
   390  	}
   391  
   392  	// Convert the spec's additional GIDs to KGIDs.
   393  	extraKGIDs := make([]auth.KGID, 0, len(args.Spec.Process.User.AdditionalGids))
   394  	for _, GID := range args.Spec.Process.User.AdditionalGids {
   395  		extraKGIDs = append(extraKGIDs, auth.KGID(GID))
   396  	}
   397  
   398  	// Create credentials.
   399  	creds := auth.NewUserCredentials(
   400  		auth.KUID(args.Spec.Process.User.UID),
   401  		auth.KGID(args.Spec.Process.User.GID),
   402  		extraKGIDs,
   403  		caps,
   404  		auth.NewRootUserNamespace())
   405  
   406  	// Create root network namespace/stack.
   407  	netns, err := newRootNetworkNamespace(args.Conf, tk, k, creds.UserNamespace)
   408  	if err != nil {
   409  		return nil, fmt.Errorf("creating network: %w", err)
   410  	}
   411  
   412  	if args.NumCPU == 0 {
   413  		args.NumCPU = runtime.NumCPU()
   414  	}
   415  	log.Infof("CPUs: %d", args.NumCPU)
   416  	runtime.GOMAXPROCS(args.NumCPU)
   417  
   418  	if args.TotalHostMem > 0 {
   419  		// As per tmpfs(5), the default size limit is 50% of total physical RAM.
   420  		// See mm/shmem.c:shmem_default_max_blocks().
   421  		tmpfs.SetDefaultSizeLimit(args.TotalHostMem / 2)
   422  	}
   423  
   424  	if args.TotalMem > 0 {
   425  		// Adjust the total memory returned by the Sentry so that applications that
   426  		// use /proc/meminfo can make allocations based on this limit.
   427  		usage.MinimumTotalMemoryBytes = args.TotalMem
   428  		usage.MaximumTotalMemoryBytes = args.TotalMem
   429  		log.Infof("Setting total memory to %.2f GB", float64(args.TotalMem)/(1<<30))
   430  	}
   431  
   432  	// Initiate the Kernel object, which is required by the Context passed
   433  	// to createVFS in order to mount (among other things) procfs.
   434  	if err = k.Init(kernel.InitKernelArgs{
   435  		FeatureSet:                  cpuid.HostFeatureSet().Fixed(),
   436  		Timekeeper:                  tk,
   437  		RootUserNamespace:           creds.UserNamespace,
   438  		RootNetworkNamespace:        netns,
   439  		ApplicationCores:            uint(args.NumCPU),
   440  		Vdso:                        vdso,
   441  		RootUTSNamespace:            kernel.NewUTSNamespace(args.Spec.Hostname, args.Spec.Hostname, creds.UserNamespace),
   442  		RootIPCNamespace:            kernel.NewIPCNamespace(creds.UserNamespace),
   443  		RootAbstractSocketNamespace: kernel.NewAbstractSocketNamespace(),
   444  		PIDNamespace:                kernel.NewRootPIDNamespace(creds.UserNamespace),
   445  	}); err != nil {
   446  		return nil, fmt.Errorf("initializing kernel: %w", err)
   447  	}
   448  
   449  	if err := registerFilesystems(k, &info); err != nil {
   450  		return nil, fmt.Errorf("registering filesystems: %w", err)
   451  	}
   452  
   453  	// Turn on packet logging if enabled.
   454  	if args.Conf.LogPackets {
   455  		log.Infof("Packet logging enabled")
   456  		sniffer.LogPackets.Store(1)
   457  	} else {
   458  		log.Infof("Packet logging disabled")
   459  		sniffer.LogPackets.Store(0)
   460  	}
   461  
   462  	// Create a watchdog.
   463  	dogOpts := watchdog.DefaultOpts
   464  	dogOpts.TaskTimeoutAction = args.Conf.WatchdogAction
   465  	dog := watchdog.New(k, dogOpts)
   466  
   467  	procArgs, err := createProcessArgs(args.ID, args.Spec, creds, k, k.RootPIDNamespace())
   468  	if err != nil {
   469  		return nil, fmt.Errorf("creating init process for root container: %w", err)
   470  	}
   471  	info.procArgs = procArgs
   472  
   473  	if err := initCompatLogs(args.UserLogFD); err != nil {
   474  		return nil, fmt.Errorf("initializing compat logs: %w", err)
   475  	}
   476  
   477  	mountHints, err := NewPodMountHints(args.Spec)
   478  	if err != nil {
   479  		return nil, fmt.Errorf("creating pod mount hints: %w", err)
   480  	}
   481  
   482  	// Set up host mount that will be used for imported fds.
   483  	hostFilesystem, err := host.NewFilesystem(k.VFS())
   484  	if err != nil {
   485  		return nil, fmt.Errorf("failed to create hostfs filesystem: %w", err)
   486  	}
   487  	defer hostFilesystem.DecRef(k.SupervisorContext())
   488  	k.SetHostMount(k.VFS().NewDisconnectedMount(hostFilesystem, nil, &vfs.MountOptions{}))
   489  
   490  	if args.PodInitConfigFD >= 0 {
   491  		if err := setupSeccheck(args.PodInitConfigFD, args.SinkFDs); err != nil {
   492  			log.Warningf("unable to configure event session: %v", err)
   493  		}
   494  	}
   495  
   496  	eid := execID{cid: args.ID}
   497  	l := &Loader{
   498  		k:                 k,
   499  		watchdog:          dog,
   500  		sandboxID:         args.ID,
   501  		processes:         map[execID]*execProcess{eid: {}},
   502  		mountHints:        mountHints,
   503  		root:              info,
   504  		stopProfiling:     stopProfiling,
   505  		productName:       args.ProductName,
   506  		nvidiaUVMDevMajor: info.nvidiaUVMDevMajor,
   507  	}
   508  
   509  	// We don't care about child signals; some platforms can generate a
   510  	// tremendous number of useless ones (I'm looking at you, ptrace).
   511  	if err := sighandling.IgnoreChildStop(); err != nil {
   512  		return nil, fmt.Errorf("ignore child stop signals failed: %w", err)
   513  	}
   514  
   515  	// Create the control server using the provided FD.
   516  	//
   517  	// This must be done *after* we have initialized the kernel since the
   518  	// controller is used to configure the kernel's network stack.
   519  	ctrl, err := newController(args.ControllerFD, l)
   520  	if err != nil {
   521  		return nil, fmt.Errorf("creating control server: %w", err)
   522  	}
   523  	l.ctrl = ctrl
   524  
   525  	// Only start serving after Loader is set to controller and controller is set
   526  	// to Loader, because they are both used in the urpc methods.
   527  	if err := ctrl.srv.StartServing(); err != nil {
   528  		return nil, fmt.Errorf("starting control server: %w", err)
   529  	}
   530  
   531  	return l, nil
   532  }
   533  
   534  // createProcessArgs creates args that can be used with kernel.CreateProcess.
   535  func createProcessArgs(id string, spec *specs.Spec, creds *auth.Credentials, k *kernel.Kernel, pidns *kernel.PIDNamespace) (kernel.CreateProcessArgs, error) {
   536  	// Create initial limits.
   537  	ls, err := createLimitSet(spec)
   538  	if err != nil {
   539  		return kernel.CreateProcessArgs{}, fmt.Errorf("creating limits: %w", err)
   540  	}
   541  	env, err := specutils.ResolveEnvs(spec.Process.Env)
   542  	if err != nil {
   543  		return kernel.CreateProcessArgs{}, fmt.Errorf("resolving env: %w", err)
   544  	}
   545  
   546  	wd := spec.Process.Cwd
   547  	if wd == "" {
   548  		wd = "/"
   549  	}
   550  
   551  	// Create the process arguments.
   552  	procArgs := kernel.CreateProcessArgs{
   553  		Argv:                    spec.Process.Args,
   554  		Envv:                    env,
   555  		WorkingDirectory:        wd,
   556  		Credentials:             creds,
   557  		Umask:                   0022,
   558  		Limits:                  ls,
   559  		MaxSymlinkTraversals:    linux.MaxSymlinkTraversals,
   560  		UTSNamespace:            k.RootUTSNamespace(),
   561  		IPCNamespace:            k.RootIPCNamespace(),
   562  		AbstractSocketNamespace: k.RootAbstractSocketNamespace(),
   563  		ContainerID:             id,
   564  		PIDNamespace:            pidns,
   565  	}
   566  
   567  	return procArgs, nil
   568  }
   569  
   570  // Destroy cleans up all resources used by the loader.
   571  //
   572  // Note that this will block until all open control server connections have
   573  // been closed. For that reason, this should NOT be called in a defer, because
   574  // a panic in a control server rpc would then hang forever.
   575  func (l *Loader) Destroy() {
   576  	if l.stopSignalForwarding != nil {
   577  		l.stopSignalForwarding()
   578  	}
   579  	l.watchdog.Stop()
   580  
   581  	// Stop the control server. This will indirectly stop any
   582  	// long-running control operations that are in flight, e.g.
   583  	// profiling operations.
   584  	l.ctrl.stop()
   585  
   586  	// Release all kernel resources. This is only safe after we can no longer
   587  	// save/restore.
   588  	l.k.Release()
   589  
   590  	// Release any dangling tcp connections.
   591  	tcpip.ReleaseDanglingEndpoints()
   592  
   593  	// In the success case, stdioFDs and goferFDs will only contain
   594  	// released/closed FDs that ownership has been passed over to host FDs and
   595  	// gofer sessions. Close them here in case of failure.
   596  	for _, f := range l.root.stdioFDs {
   597  		_ = f.Close()
   598  	}
   599  	for _, f := range l.root.passFDs {
   600  		_ = f.host.Close()
   601  	}
   602  	for _, f := range l.root.goferFDs {
   603  		_ = f.Close()
   604  	}
   605  
   606  	l.stopProfiling()
   607  }
   608  
   609  func createPlatform(conf *config.Config, deviceFile *os.File) (platform.Platform, error) {
   610  	p, err := platform.Lookup(conf.Platform)
   611  	if err != nil {
   612  		panic(fmt.Sprintf("invalid platform %s: %s", conf.Platform, err))
   613  	}
   614  	log.Infof("Platform: %s", conf.Platform)
   615  	return p.New(deviceFile)
   616  }
   617  
   618  func createMemoryFile() (*pgalloc.MemoryFile, error) {
   619  	const memfileName = "runsc-memory"
   620  	memfd, err := memutil.CreateMemFD(memfileName, 0)
   621  	if err != nil {
   622  		return nil, fmt.Errorf("error creating memfd: %w", err)
   623  	}
   624  	memfile := os.NewFile(uintptr(memfd), memfileName)
   625  	// We can't enable pgalloc.MemoryFileOpts.UseHostMemcgPressure even if
   626  	// there are memory cgroups specified, because at this point we're already
   627  	// in a mount namespace in which the relevant cgroupfs is not visible.
   628  	mf, err := pgalloc.NewMemoryFile(memfile, pgalloc.MemoryFileOpts{})
   629  	if err != nil {
   630  		_ = memfile.Close()
   631  		return nil, fmt.Errorf("error creating pgalloc.MemoryFile: %w", err)
   632  	}
   633  	return mf, nil
   634  }
   635  
   636  // installSeccompFilters installs sandbox seccomp filters with the host.
   637  func (l *Loader) installSeccompFilters() error {
   638  	if l.PreSeccompCallback != nil {
   639  		l.PreSeccompCallback()
   640  	}
   641  	if l.root.conf.DisableSeccomp {
   642  		filter.Report("syscall filter is DISABLED. Running in less secure mode.")
   643  	} else {
   644  		hostnet := l.root.conf.Network == config.NetworkHost
   645  		opts := filter.Options{
   646  			Platform:              l.k.Platform,
   647  			HostNetwork:           hostnet,
   648  			HostNetworkRawSockets: hostnet && l.root.conf.EnableRaw,
   649  			HostFilesystem:        l.root.conf.DirectFS,
   650  			ProfileEnable:         l.root.conf.ProfileEnable,
   651  			NVProxy:               l.root.conf.NVProxy,
   652  			TPUProxy:              l.root.conf.TPUProxy,
   653  			ControllerFD:          l.ctrl.srv.FD(),
   654  		}
   655  		if err := filter.Install(opts); err != nil {
   656  			return fmt.Errorf("installing seccomp filters: %w", err)
   657  		}
   658  	}
   659  	return nil
   660  }
   661  
   662  // Run runs the root container.
   663  func (l *Loader) Run() error {
   664  	err := l.run()
   665  	l.ctrl.manager.startResultChan <- err
   666  	if err != nil {
   667  		// Give the controller some time to send the error to the
   668  		// runtime. If we return too quickly here the process will exit
   669  		// and the control connection will be closed before the error
   670  		// is returned.
   671  		gtime.Sleep(2 * gtime.Second)
   672  		return err
   673  	}
   674  	return nil
   675  }
   676  
   677  func (l *Loader) run() error {
   678  	if l.root.conf.Network == config.NetworkHost {
   679  		// Delay host network configuration to this point because network namespace
   680  		// is configured after the loader is created and before Run() is called.
   681  		log.Debugf("Configuring host network")
   682  		s := l.k.RootNetworkNamespace().Stack().(*hostinet.Stack)
   683  		if err := s.Configure(l.root.conf.EnableRaw); err != nil {
   684  			return err
   685  		}
   686  	}
   687  
   688  	l.mu.Lock()
   689  	defer l.mu.Unlock()
   690  
   691  	eid := execID{cid: l.sandboxID}
   692  	ep, ok := l.processes[eid]
   693  	if !ok {
   694  		return fmt.Errorf("trying to start deleted container %q", l.sandboxID)
   695  	}
   696  
   697  	// If we are restoring, we do not want to create a process.
   698  	// l.restore is set by the container manager when a restore call is made.
   699  	if !l.restore {
   700  		if l.root.conf.ProfileEnable {
   701  			pprof.Initialize()
   702  		}
   703  
   704  		// Finally done with all configuration. Setup filters before user code
   705  		// is loaded.
   706  		if err := l.installSeccompFilters(); err != nil {
   707  			return err
   708  		}
   709  
   710  		// Create the root container init task. It will begin running
   711  		// when the kernel is started.
   712  		var (
   713  			tg  *kernel.ThreadGroup
   714  			err error
   715  		)
   716  		tg, ep.tty, err = l.createContainerProcess(true, l.sandboxID, &l.root)
   717  		if err != nil {
   718  			return err
   719  		}
   720  
   721  		if seccheck.Global.Enabled(seccheck.PointContainerStart) {
   722  			evt := pb.Start{
   723  				Id:       l.sandboxID,
   724  				Cwd:      l.root.spec.Process.Cwd,
   725  				Args:     l.root.spec.Process.Args,
   726  				Terminal: l.root.spec.Process.Terminal,
   727  			}
   728  			fields := seccheck.Global.GetFieldSet(seccheck.PointContainerStart)
   729  			if fields.Local.Contains(seccheck.FieldContainerStartEnv) {
   730  				evt.Env = l.root.spec.Process.Env
   731  			}
   732  			if !fields.Context.Empty() {
   733  				evt.ContextData = &pb.ContextData{}
   734  				kernel.LoadSeccheckData(tg.Leader(), fields.Context, evt.ContextData)
   735  			}
   736  			_ = seccheck.Global.SentToSinks(func(c seccheck.Sink) error {
   737  				return c.ContainerStart(context.Background(), fields, &evt)
   738  			})
   739  		}
   740  	}
   741  
   742  	ep.tg = l.k.GlobalInit()
   743  	if ns, ok := specutils.GetNS(specs.PIDNamespace, l.root.spec); ok {
   744  		ep.pidnsPath = ns.Path
   745  	}
   746  
   747  	// Handle signals by forwarding them to the root container process
   748  	// (except for panic signal, which should cause a panic).
   749  	l.stopSignalForwarding = sighandling.StartSignalForwarding(func(sig linux.Signal) {
   750  		// Panic signal should cause a panic.
   751  		if l.root.conf.PanicSignal != -1 && sig == linux.Signal(l.root.conf.PanicSignal) {
   752  			panic("Signal-induced panic")
   753  		}
   754  
   755  		// Otherwise forward to root container.
   756  		deliveryMode := DeliverToProcess
   757  		if l.root.spec.Process.Terminal {
   758  			// Since we are running with a console, we should forward the signal to
   759  			// the foreground process group so that job control signals like ^C can
   760  			// be handled properly.
   761  			deliveryMode = DeliverToForegroundProcessGroup
   762  		}
   763  		log.Infof("Received external signal %d, mode: %s", sig, deliveryMode)
   764  		if err := l.signal(l.sandboxID, 0, int32(sig), deliveryMode); err != nil {
   765  			log.Warningf("error sending signal %s to container %q: %s", sig, l.sandboxID, err)
   766  		}
   767  	})
   768  
   769  	log.Infof("Process should have started...")
   770  	l.watchdog.Start()
   771  	return l.k.Start()
   772  }
   773  
   774  // createSubcontainer creates a new container inside the sandbox.
   775  func (l *Loader) createSubcontainer(cid string, tty *fd.FD) error {
   776  	l.mu.Lock()
   777  	defer l.mu.Unlock()
   778  
   779  	eid := execID{cid: cid}
   780  	if _, ok := l.processes[eid]; ok {
   781  		return fmt.Errorf("container %q already exists", cid)
   782  	}
   783  	l.processes[eid] = &execProcess{hostTTY: tty}
   784  	return nil
   785  }
   786  
   787  // startSubcontainer starts a child container. It returns the thread group ID of
   788  // the newly created process. Used FDs are either closed or released. It's safe
   789  // for the caller to close any remaining files upon return.
   790  func (l *Loader) startSubcontainer(spec *specs.Spec, conf *config.Config, cid string, stdioFDs, goferFDs, overlayFilestoreFDs []*fd.FD, overlayMediums []OverlayMedium) error {
   791  	// Create capabilities.
   792  	caps, err := specutils.Capabilities(conf.EnableRaw, spec.Process.Capabilities)
   793  	if err != nil {
   794  		return fmt.Errorf("creating capabilities: %w", err)
   795  	}
   796  
   797  	l.mu.Lock()
   798  	defer l.mu.Unlock()
   799  
   800  	ep := l.processes[execID{cid: cid}]
   801  	if ep == nil {
   802  		return fmt.Errorf("trying to start a deleted container %q", cid)
   803  	}
   804  
   805  	// Convert the spec's additional GIDs to KGIDs.
   806  	extraKGIDs := make([]auth.KGID, 0, len(spec.Process.User.AdditionalGids))
   807  	for _, GID := range spec.Process.User.AdditionalGids {
   808  		extraKGIDs = append(extraKGIDs, auth.KGID(GID))
   809  	}
   810  
   811  	// Create credentials. We reuse the root user namespace because the
   812  	// sentry currently supports only 1 mount namespace, which is tied to a
   813  	// single user namespace. Thus we must run in the same user namespace
   814  	// to access mounts.
   815  	creds := auth.NewUserCredentials(
   816  		auth.KUID(spec.Process.User.UID),
   817  		auth.KGID(spec.Process.User.GID),
   818  		extraKGIDs,
   819  		caps,
   820  		l.k.RootUserNamespace())
   821  
   822  	var pidns *kernel.PIDNamespace
   823  	if ns, ok := specutils.GetNS(specs.PIDNamespace, spec); ok {
   824  		if ns.Path != "" {
   825  			for _, p := range l.processes {
   826  				if ns.Path == p.pidnsPath {
   827  					log.Debugf("Joining PID namespace named %q", ns.Path)
   828  					pidns = p.tg.PIDNamespace()
   829  					break
   830  				}
   831  			}
   832  		}
   833  		if pidns == nil {
   834  			log.Warningf("PID namespace %q not found, running in new PID namespace", ns.Path)
   835  			pidns = l.k.RootPIDNamespace().NewChild(l.k.RootUserNamespace())
   836  		}
   837  		ep.pidnsPath = ns.Path
   838  	} else {
   839  		pidns = l.k.RootPIDNamespace()
   840  	}
   841  
   842  	info := &containerInfo{
   843  		conf:                conf,
   844  		spec:                spec,
   845  		goferFDs:            goferFDs,
   846  		overlayFilestoreFDs: overlayFilestoreFDs,
   847  		overlayMediums:      overlayMediums,
   848  		nvidiaUVMDevMajor:   l.nvidiaUVMDevMajor,
   849  	}
   850  	info.procArgs, err = createProcessArgs(cid, spec, creds, l.k, pidns)
   851  	if err != nil {
   852  		return fmt.Errorf("creating new process: %w", err)
   853  	}
   854  
   855  	// Use stdios or TTY depending on the spec configuration.
   856  	if spec.Process.Terminal {
   857  		if l := len(stdioFDs); l != 0 {
   858  			return fmt.Errorf("using TTY, stdios not expected: %d", l)
   859  		}
   860  		if ep.hostTTY == nil {
   861  			return fmt.Errorf("terminal enabled but no TTY provided. Did you set --console-socket on create?")
   862  		}
   863  		info.stdioFDs = []*fd.FD{ep.hostTTY, ep.hostTTY, ep.hostTTY}
   864  		ep.hostTTY = nil
   865  	} else {
   866  		info.stdioFDs = stdioFDs
   867  	}
   868  
   869  	ep.tg, ep.tty, err = l.createContainerProcess(false, cid, info)
   870  	if err != nil {
   871  		return err
   872  	}
   873  
   874  	if seccheck.Global.Enabled(seccheck.PointContainerStart) {
   875  		evt := pb.Start{
   876  			Id:       cid,
   877  			Cwd:      spec.Process.Cwd,
   878  			Args:     spec.Process.Args,
   879  			Terminal: spec.Process.Terminal,
   880  		}
   881  		fields := seccheck.Global.GetFieldSet(seccheck.PointContainerStart)
   882  		if fields.Local.Contains(seccheck.FieldContainerStartEnv) {
   883  			evt.Env = spec.Process.Env
   884  		}
   885  		if !fields.Context.Empty() {
   886  			evt.ContextData = &pb.ContextData{}
   887  			kernel.LoadSeccheckData(ep.tg.Leader(), fields.Context, evt.ContextData)
   888  		}
   889  		_ = seccheck.Global.SentToSinks(func(c seccheck.Sink) error {
   890  			return c.ContainerStart(context.Background(), fields, &evt)
   891  		})
   892  	}
   893  
   894  	l.k.StartProcess(ep.tg)
   895  	return nil
   896  }
   897  
   898  func (l *Loader) createContainerProcess(root bool, cid string, info *containerInfo) (*kernel.ThreadGroup, *host.TTYFileDescription, error) {
   899  	// Create the FD map, which will set stdin, stdout, and stderr.
   900  	ctx := info.procArgs.NewContext(l.k)
   901  	fdTable, ttyFile, err := createFDTable(ctx, info.spec.Process.Terminal, info.stdioFDs, info.passFDs, info.spec.Process.User)
   902  	if err != nil {
   903  		return nil, nil, fmt.Errorf("importing fds: %w", err)
   904  	}
   905  	// CreateProcess takes a reference on fdTable if successful. We won't need
   906  	// ours either way.
   907  	info.procArgs.FDTable = fdTable
   908  
   909  	if info.execFD != nil {
   910  		if info.procArgs.Filename != "" {
   911  			return nil, nil, fmt.Errorf("process must either be started from a file or a filename, not both")
   912  		}
   913  		file, err := host.NewFD(ctx, l.k.HostMount(), info.execFD.FD(), &host.NewFDOptions{
   914  			Readonly:     true,
   915  			Savable:      true,
   916  			VirtualOwner: true,
   917  			UID:          auth.KUID(info.spec.Process.User.UID),
   918  			GID:          auth.KGID(info.spec.Process.User.GID),
   919  		})
   920  		if err != nil {
   921  			return nil, nil, err
   922  		}
   923  		defer file.DecRef(ctx)
   924  		info.execFD.Release()
   925  
   926  		info.procArgs.File = file
   927  	}
   928  
   929  	// Gofer FDs must be ordered and the first FD is always the rootfs.
   930  	if len(info.goferFDs) < 1 {
   931  		return nil, nil, fmt.Errorf("rootfs gofer FD not found")
   932  	}
   933  	l.startGoferMonitor(cid, int32(info.goferFDs[0].FD()))
   934  
   935  	mntr := newContainerMounter(info, l.k, l.mountHints, l.productName, l.sandboxID)
   936  	if root {
   937  		if err := mntr.processHints(info.conf, info.procArgs.Credentials); err != nil {
   938  			return nil, nil, err
   939  		}
   940  	}
   941  	if err := setupContainerVFS(ctx, info, mntr, &info.procArgs); err != nil {
   942  		return nil, nil, err
   943  	}
   944  
   945  	// Add the HOME environment variable if it is not already set.
   946  	info.procArgs.Envv, err = user.MaybeAddExecUserHome(ctx, info.procArgs.MountNamespace,
   947  		info.procArgs.Credentials.RealKUID, info.procArgs.Envv)
   948  	if err != nil {
   949  		return nil, nil, err
   950  	}
   951  
   952  	// Create and start the new process.
   953  	tg, _, err := l.k.CreateProcess(info.procArgs)
   954  	if err != nil {
   955  		return nil, nil, fmt.Errorf("creating process: %w", err)
   956  	}
   957  	// CreateProcess takes a reference on FDTable if successful.
   958  	info.procArgs.FDTable.DecRef(ctx)
   959  
   960  	// Set the foreground process group on the TTY to the global init process
   961  	// group, since that is what we are about to start running.
   962  	if ttyFile != nil {
   963  		ttyFile.InitForegroundProcessGroup(tg.ProcessGroup())
   964  	}
   965  
   966  	// Install seccomp filters with the new task if there are any.
   967  	if info.conf.OCISeccomp {
   968  		if info.spec.Linux != nil && info.spec.Linux.Seccomp != nil {
   969  			program, err := seccomp.BuildProgram(info.spec.Linux.Seccomp)
   970  			if err != nil {
   971  				return nil, nil, fmt.Errorf("building seccomp program: %w", err)
   972  			}
   973  
   974  			if log.IsLogging(log.Debug) {
   975  				out, _ := bpf.DecodeProgram(program)
   976  				log.Debugf("Installing OCI seccomp filters\nProgram:\n%s", out)
   977  			}
   978  
   979  			task := tg.Leader()
   980  			// NOTE: It seems Flags are ignored by runc so we ignore them too.
   981  			if err := task.AppendSyscallFilter(program, true); err != nil {
   982  				return nil, nil, fmt.Errorf("appending seccomp filters: %w", err)
   983  			}
   984  		}
   985  	} else {
   986  		if info.spec.Linux != nil && info.spec.Linux.Seccomp != nil {
   987  			log.Warningf("Seccomp spec is being ignored")
   988  		}
   989  	}
   990  
   991  	return tg, ttyFile, nil
   992  }
   993  
   994  // startGoferMonitor runs a goroutine to monitor gofer's health. It polls on
   995  // the gofer FD looking for disconnects, and kills the container processes if
   996  // the rootfs FD disconnects.
   997  //
   998  // Note that other gofer mounts are allowed to be unmounted and disconnected.
   999  func (l *Loader) startGoferMonitor(cid string, rootfsGoferFD int32) {
  1000  	if rootfsGoferFD < 0 {
  1001  		panic(fmt.Sprintf("invalid FD: %d", rootfsGoferFD))
  1002  	}
  1003  	go func() {
  1004  		log.Debugf("Monitoring gofer health for container %q", cid)
  1005  		events := []unix.PollFd{
  1006  			{
  1007  				Fd:     rootfsGoferFD,
  1008  				Events: unix.POLLHUP | unix.POLLRDHUP,
  1009  			},
  1010  		}
  1011  		_, _, err := specutils.RetryEintr(func() (uintptr, uintptr, error) {
  1012  			// Use ppoll instead of poll because it's already allowed in seccomp.
  1013  			n, err := unix.Ppoll(events, nil, nil)
  1014  			return uintptr(n), 0, err
  1015  		})
  1016  		if err != nil {
  1017  			panic(fmt.Sprintf("Error monitoring gofer FDs: %s", err))
  1018  		}
  1019  
  1020  		l.mu.Lock()
  1021  		defer l.mu.Unlock()
  1022  
  1023  		// The gofer could have been stopped due to a normal container shutdown.
  1024  		// Check if the container has not stopped yet.
  1025  		if tg, _ := l.tryThreadGroupFromIDLocked(execID{cid: cid}); tg != nil {
  1026  			log.Infof("Gofer socket disconnected, killing container %q", cid)
  1027  			if err := l.signalAllProcesses(cid, int32(linux.SIGKILL)); err != nil {
  1028  				log.Warningf("Error killing container %q after gofer stopped: %s", cid, err)
  1029  			}
  1030  		}
  1031  	}()
  1032  }
  1033  
  1034  // destroySubcontainer stops a container if it is still running and cleans up
  1035  // its filesystem.
  1036  func (l *Loader) destroySubcontainer(cid string) error {
  1037  	l.mu.Lock()
  1038  	defer l.mu.Unlock()
  1039  
  1040  	tg, err := l.tryThreadGroupFromIDLocked(execID{cid: cid})
  1041  	if err != nil {
  1042  		// Container doesn't exist.
  1043  		return err
  1044  	}
  1045  
  1046  	// The container exists, but has it been started?
  1047  	if tg != nil {
  1048  		if err := l.signalAllProcesses(cid, int32(linux.SIGKILL)); err != nil {
  1049  			return fmt.Errorf("sending SIGKILL to all container processes: %w", err)
  1050  		}
  1051  		// Wait for all processes that belong to the container to exit (including
  1052  		// exec'd processes).
  1053  		for _, t := range l.k.TaskSet().Root.Tasks() {
  1054  			if t.ContainerID() == cid {
  1055  				t.ThreadGroup().WaitExited()
  1056  			}
  1057  		}
  1058  	}
  1059  
  1060  	// No more failure from this point on. Remove all container thread groups
  1061  	// from the map.
  1062  	for key := range l.processes {
  1063  		if key.cid == cid {
  1064  			delete(l.processes, key)
  1065  		}
  1066  	}
  1067  
  1068  	log.Debugf("Container destroyed, cid: %s", cid)
  1069  	return nil
  1070  }
  1071  
  1072  func (l *Loader) executeAsync(args *control.ExecArgs) (kernel.ThreadID, error) {
  1073  	// Hold the lock for the entire operation to ensure that exec'd process is
  1074  	// added to 'processes' in case it races with destroyContainer().
  1075  	l.mu.Lock()
  1076  	defer l.mu.Unlock()
  1077  
  1078  	tg, err := l.tryThreadGroupFromIDLocked(execID{cid: args.ContainerID})
  1079  	if err != nil {
  1080  		return 0, err
  1081  	}
  1082  	if tg == nil {
  1083  		return 0, fmt.Errorf("container %q not started", args.ContainerID)
  1084  	}
  1085  
  1086  	// Get the container MountNamespace from the Task. Try to acquire ref may fail
  1087  	// in case it raced with task exit.
  1088  	// task.MountNamespace() does not take a ref, so we must do so ourselves.
  1089  	args.MountNamespace = tg.Leader().MountNamespace()
  1090  	if args.MountNamespace == nil || !args.MountNamespace.TryIncRef() {
  1091  		return 0, fmt.Errorf("container %q has stopped", args.ContainerID)
  1092  	}
  1093  
  1094  	args.Envv, err = specutils.ResolveEnvs(args.Envv)
  1095  	if err != nil {
  1096  		return 0, fmt.Errorf("resolving env: %w", err)
  1097  	}
  1098  
  1099  	// Add the HOME environment variable if it is not already set.
  1100  	ctx := vfs.WithRoot(l.k.SupervisorContext(), args.MountNamespace.Root())
  1101  	defer args.MountNamespace.DecRef(ctx)
  1102  	args.Envv, err = user.MaybeAddExecUserHome(ctx, args.MountNamespace, args.KUID, args.Envv)
  1103  	if err != nil {
  1104  		return 0, err
  1105  	}
  1106  	args.PIDNamespace = tg.PIDNamespace()
  1107  
  1108  	args.Limits, err = createLimitSet(l.root.spec)
  1109  	if err != nil {
  1110  		return 0, fmt.Errorf("creating limits: %w", err)
  1111  	}
  1112  
  1113  	// Start the process.
  1114  	proc := control.Proc{Kernel: l.k}
  1115  	newTG, tgid, ttyFile, err := control.ExecAsync(&proc, args)
  1116  	if err != nil {
  1117  		return 0, err
  1118  	}
  1119  
  1120  	eid := execID{cid: args.ContainerID, pid: tgid}
  1121  	l.processes[eid] = &execProcess{
  1122  		tg:  newTG,
  1123  		tty: ttyFile,
  1124  	}
  1125  	log.Debugf("updated processes: %v", l.processes)
  1126  
  1127  	return tgid, nil
  1128  }
  1129  
  1130  // waitContainer waits for the init process of a container to exit.
  1131  func (l *Loader) waitContainer(cid string, waitStatus *uint32) error {
  1132  	// Don't defer unlock, as doing so would make it impossible for
  1133  	// multiple clients to wait on the same container.
  1134  	tg, err := l.threadGroupFromID(execID{cid: cid})
  1135  	if err != nil {
  1136  		return fmt.Errorf("can't wait for container %q: %w", cid, err)
  1137  	}
  1138  
  1139  	// If the thread either has already exited or exits during waiting,
  1140  	// consider the container exited.
  1141  	ws := l.wait(tg)
  1142  	*waitStatus = ws
  1143  
  1144  	// Check for leaks and write coverage report after the root container has
  1145  	// exited. This guarantees that the report is written in cases where the
  1146  	// sandbox is killed by a signal after the ContMgrWait request is completed.
  1147  	if l.root.procArgs.ContainerID == cid {
  1148  		// All sentry-created resources should have been released at this point.
  1149  		refs.DoLeakCheck()
  1150  		_ = coverage.Report()
  1151  	}
  1152  	return nil
  1153  }
  1154  
  1155  func (l *Loader) waitPID(tgid kernel.ThreadID, cid string, waitStatus *uint32) error {
  1156  	if tgid <= 0 {
  1157  		return fmt.Errorf("PID (%d) must be positive", tgid)
  1158  	}
  1159  
  1160  	// Try to find a process that was exec'd
  1161  	eid := execID{cid: cid, pid: tgid}
  1162  	execTG, err := l.threadGroupFromID(eid)
  1163  	if err == nil {
  1164  		ws := l.wait(execTG)
  1165  		*waitStatus = ws
  1166  
  1167  		l.mu.Lock()
  1168  		delete(l.processes, eid)
  1169  		log.Debugf("updated processes (removal): %v", l.processes)
  1170  		l.mu.Unlock()
  1171  		return nil
  1172  	}
  1173  
  1174  	// The caller may be waiting on a process not started directly via exec.
  1175  	// In this case, find the process in the container's PID namespace.
  1176  	initTG, err := l.threadGroupFromID(execID{cid: cid})
  1177  	if err != nil {
  1178  		return fmt.Errorf("waiting for PID %d: %w", tgid, err)
  1179  	}
  1180  	tg := initTG.PIDNamespace().ThreadGroupWithID(tgid)
  1181  	if tg == nil {
  1182  		return fmt.Errorf("waiting for PID %d: no such process", tgid)
  1183  	}
  1184  	if tg.Leader().ContainerID() != cid {
  1185  		return fmt.Errorf("process %d is part of a different container: %q", tgid, tg.Leader().ContainerID())
  1186  	}
  1187  	ws := l.wait(tg)
  1188  	*waitStatus = ws
  1189  	return nil
  1190  }
  1191  
  1192  // wait waits for the process with TGID 'tgid' in a container's PID namespace
  1193  // to exit.
  1194  func (l *Loader) wait(tg *kernel.ThreadGroup) uint32 {
  1195  	tg.WaitExited()
  1196  	return uint32(tg.ExitStatus())
  1197  }
  1198  
  1199  // WaitForStartSignal waits for a start signal from the control server.
  1200  func (l *Loader) WaitForStartSignal() {
  1201  	<-l.ctrl.manager.startChan
  1202  }
  1203  
  1204  // WaitExit waits for the root container to exit, and returns its exit status.
  1205  func (l *Loader) WaitExit() linux.WaitStatus {
  1206  	// Wait for container.
  1207  	l.k.WaitExited()
  1208  
  1209  	// Check all references.
  1210  	refs.OnExit()
  1211  
  1212  	return l.k.GlobalInit().ExitStatus()
  1213  }
  1214  
  1215  func newRootNetworkNamespace(conf *config.Config, clock tcpip.Clock, uniqueID stack.UniqueID, userns *auth.UserNamespace) (*inet.Namespace, error) {
  1216  	// Create an empty network stack because the network namespace may be empty at
  1217  	// this point. Netns is configured before Run() is called. Netstack is
  1218  	// configured using a control uRPC message. Host network is configured inside
  1219  	// Run().
  1220  	switch conf.Network {
  1221  	case config.NetworkHost:
  1222  		// If configured for raw socket support with host network
  1223  		// stack, make sure that we have CAP_NET_RAW the host,
  1224  		// otherwise we can't make raw sockets.
  1225  		if conf.EnableRaw && !specutils.HasCapabilities(capability.CAP_NET_RAW) {
  1226  			return nil, fmt.Errorf("configuring network=host with raw sockets requires CAP_NET_RAW capability")
  1227  		}
  1228  		// No network namespacing support for hostinet yet, hence creator is nil.
  1229  		return inet.NewRootNamespace(hostinet.NewStack(), nil, userns), nil
  1230  
  1231  	case config.NetworkNone, config.NetworkSandbox:
  1232  		s, err := newEmptySandboxNetworkStack(clock, uniqueID, conf.AllowPacketEndpointWrite)
  1233  		if err != nil {
  1234  			return nil, err
  1235  		}
  1236  		creator := &sandboxNetstackCreator{
  1237  			clock:                    clock,
  1238  			uniqueID:                 uniqueID,
  1239  			allowPacketEndpointWrite: conf.AllowPacketEndpointWrite,
  1240  		}
  1241  		return inet.NewRootNamespace(s, creator, userns), nil
  1242  
  1243  	default:
  1244  		panic(fmt.Sprintf("invalid network configuration: %v", conf.Network))
  1245  	}
  1246  
  1247  }
  1248  
  1249  func newEmptySandboxNetworkStack(clock tcpip.Clock, uniqueID stack.UniqueID, allowPacketEndpointWrite bool) (inet.Stack, error) {
  1250  	netProtos := []stack.NetworkProtocolFactory{ipv4.NewProtocol, ipv6.NewProtocol, arp.NewProtocol}
  1251  	transProtos := []stack.TransportProtocolFactory{
  1252  		tcp.NewProtocol,
  1253  		udp.NewProtocol,
  1254  		icmp.NewProtocol4,
  1255  		icmp.NewProtocol6,
  1256  	}
  1257  	s := netstack.Stack{Stack: stack.New(stack.Options{
  1258  		NetworkProtocols:   netProtos,
  1259  		TransportProtocols: transProtos,
  1260  		Clock:              clock,
  1261  		Stats:              netstack.Metrics,
  1262  		HandleLocal:        true,
  1263  		// Enable raw sockets for users with sufficient
  1264  		// privileges.
  1265  		RawFactory:               raw.EndpointFactory{},
  1266  		AllowPacketEndpointWrite: allowPacketEndpointWrite,
  1267  		UniqueID:                 uniqueID,
  1268  		DefaultIPTables:          netfilter.DefaultLinuxTables,
  1269  	})}
  1270  
  1271  	// Enable SACK Recovery.
  1272  	{
  1273  		opt := tcpip.TCPSACKEnabled(true)
  1274  		if err := s.Stack.SetTransportProtocolOption(tcp.ProtocolNumber, &opt); err != nil {
  1275  			return nil, fmt.Errorf("SetTransportProtocolOption(%d, &%T(%t)): %s", tcp.ProtocolNumber, opt, opt, err)
  1276  		}
  1277  	}
  1278  
  1279  	// Set default TTLs as required by socket/netstack.
  1280  	{
  1281  		opt := tcpip.DefaultTTLOption(netstack.DefaultTTL)
  1282  		if err := s.Stack.SetNetworkProtocolOption(ipv4.ProtocolNumber, &opt); err != nil {
  1283  			return nil, fmt.Errorf("SetNetworkProtocolOption(%d, &%T(%d)): %s", ipv4.ProtocolNumber, opt, opt, err)
  1284  		}
  1285  		if err := s.Stack.SetNetworkProtocolOption(ipv6.ProtocolNumber, &opt); err != nil {
  1286  			return nil, fmt.Errorf("SetNetworkProtocolOption(%d, &%T(%d)): %s", ipv6.ProtocolNumber, opt, opt, err)
  1287  		}
  1288  	}
  1289  
  1290  	// Enable Receive Buffer Auto-Tuning.
  1291  	{
  1292  		opt := tcpip.TCPModerateReceiveBufferOption(true)
  1293  		if err := s.Stack.SetTransportProtocolOption(tcp.ProtocolNumber, &opt); err != nil {
  1294  			return nil, fmt.Errorf("SetTransportProtocolOption(%d, &%T(%t)): %s", tcp.ProtocolNumber, opt, opt, err)
  1295  		}
  1296  	}
  1297  
  1298  	return &s, nil
  1299  }
  1300  
  1301  // sandboxNetstackCreator implements kernel.NetworkStackCreator.
  1302  //
  1303  // +stateify savable
  1304  type sandboxNetstackCreator struct {
  1305  	clock                    tcpip.Clock
  1306  	uniqueID                 stack.UniqueID
  1307  	allowPacketEndpointWrite bool
  1308  }
  1309  
  1310  // CreateStack implements kernel.NetworkStackCreator.CreateStack.
  1311  func (f *sandboxNetstackCreator) CreateStack() (inet.Stack, error) {
  1312  	s, err := newEmptySandboxNetworkStack(f.clock, f.uniqueID, f.allowPacketEndpointWrite)
  1313  	if err != nil {
  1314  		return nil, err
  1315  	}
  1316  
  1317  	// Setup loopback.
  1318  	n := &Network{Stack: s.(*netstack.Stack).Stack}
  1319  	nicID := tcpip.NICID(f.uniqueID.UniqueID())
  1320  	link := DefaultLoopbackLink
  1321  	linkEP := packetsocket.New(ethernet.New(loopback.New()))
  1322  	opts := stack.NICOptions{Name: link.Name}
  1323  
  1324  	if err := n.createNICWithAddrs(nicID, linkEP, opts, link.Addresses); err != nil {
  1325  		return nil, err
  1326  	}
  1327  
  1328  	return s, nil
  1329  }
  1330  
  1331  // signal sends a signal to one or more processes in a container. If PID is 0,
  1332  // then the container init process is used. Depending on the SignalDeliveryMode
  1333  // option, the signal may be sent directly to the indicated process, to all
  1334  // processes in the container, or to the foreground process group. pid is
  1335  // relative to the root PID namespace, not the container's.
  1336  func (l *Loader) signal(cid string, pid, signo int32, mode SignalDeliveryMode) error {
  1337  	if pid < 0 {
  1338  		return fmt.Errorf("PID (%d) must be positive", pid)
  1339  	}
  1340  
  1341  	switch mode {
  1342  	case DeliverToProcess:
  1343  		if err := l.signalProcess(cid, kernel.ThreadID(pid), signo); err != nil {
  1344  			return fmt.Errorf("signaling process in container %q PID %d: %w", cid, pid, err)
  1345  		}
  1346  		return nil
  1347  
  1348  	case DeliverToForegroundProcessGroup:
  1349  		if err := l.signalForegrondProcessGroup(cid, kernel.ThreadID(pid), signo); err != nil {
  1350  			return fmt.Errorf("signaling foreground process group in container %q PID %d: %w", cid, pid, err)
  1351  		}
  1352  		return nil
  1353  
  1354  	case DeliverToAllProcesses:
  1355  		if pid != 0 {
  1356  			return fmt.Errorf("PID (%d) cannot be set when signaling all processes", pid)
  1357  		}
  1358  		// Check that the container has actually started before signaling it.
  1359  		if _, err := l.threadGroupFromID(execID{cid: cid}); err != nil {
  1360  			return err
  1361  		}
  1362  		if err := l.signalAllProcesses(cid, signo); err != nil {
  1363  			return fmt.Errorf("signaling all processes in container %q: %w", cid, err)
  1364  		}
  1365  		return nil
  1366  
  1367  	default:
  1368  		panic(fmt.Sprintf("unknown signal delivery mode %v", mode))
  1369  	}
  1370  }
  1371  
  1372  // signalProcess sends signal to process in the given container. tgid is
  1373  // relative to the root PID namespace, not the container's.
  1374  func (l *Loader) signalProcess(cid string, tgid kernel.ThreadID, signo int32) error {
  1375  	execTG, err := l.threadGroupFromID(execID{cid: cid, pid: tgid})
  1376  	if err == nil {
  1377  		// Send signal directly to the identified process.
  1378  		return l.k.SendExternalSignalThreadGroup(execTG, &linux.SignalInfo{Signo: signo})
  1379  	}
  1380  
  1381  	// The caller may be signaling a process not started directly via exec.
  1382  	// In this case, find the process and check that the process belongs to the
  1383  	// container in question.
  1384  	tg := l.k.RootPIDNamespace().ThreadGroupWithID(tgid)
  1385  	if tg == nil {
  1386  		return fmt.Errorf("no such process with PID %d", tgid)
  1387  	}
  1388  	if tg.Leader().ContainerID() != cid {
  1389  		return fmt.Errorf("process %d belongs to a different container: %q", tgid, tg.Leader().ContainerID())
  1390  	}
  1391  	return l.k.SendExternalSignalThreadGroup(tg, &linux.SignalInfo{Signo: signo})
  1392  }
  1393  
  1394  // signalForegrondProcessGroup looks up foreground process group from the TTY
  1395  // for the given "tgid" inside container "cid", and send the signal to it.
  1396  func (l *Loader) signalForegrondProcessGroup(cid string, tgid kernel.ThreadID, signo int32) error {
  1397  	l.mu.Lock()
  1398  	tg, err := l.tryThreadGroupFromIDLocked(execID{cid: cid, pid: tgid})
  1399  	if err != nil {
  1400  		l.mu.Unlock()
  1401  		return fmt.Errorf("no thread group found: %w", err)
  1402  	}
  1403  	if tg == nil {
  1404  		l.mu.Unlock()
  1405  		return fmt.Errorf("container %q not started", cid)
  1406  	}
  1407  
  1408  	tty, err := l.ttyFromIDLocked(execID{cid: cid, pid: tgid})
  1409  	l.mu.Unlock()
  1410  	if err != nil {
  1411  		return fmt.Errorf("no thread group found: %w", err)
  1412  	}
  1413  	if tty == nil {
  1414  		return fmt.Errorf("no TTY attached")
  1415  	}
  1416  	pg := tty.ForegroundProcessGroup()
  1417  	if pg == nil {
  1418  		// No foreground process group has been set. Signal the
  1419  		// original thread group.
  1420  		log.Warningf("No foreground process group for container %q and PID %d. Sending signal directly to PID %d.", cid, tgid, tgid)
  1421  		return l.k.SendExternalSignalThreadGroup(tg, &linux.SignalInfo{Signo: signo})
  1422  	}
  1423  	// Send the signal to all processes in the process group.
  1424  	var lastErr error
  1425  	for _, tg := range l.k.TaskSet().Root.ThreadGroups() {
  1426  		if tg.ProcessGroup() != pg {
  1427  			continue
  1428  		}
  1429  		if err := l.k.SendExternalSignalThreadGroup(tg, &linux.SignalInfo{Signo: signo}); err != nil {
  1430  			lastErr = err
  1431  		}
  1432  	}
  1433  	return lastErr
  1434  }
  1435  
  1436  // signalAllProcesses that belong to specified container. It's a noop if the
  1437  // container hasn't started or has exited.
  1438  func (l *Loader) signalAllProcesses(cid string, signo int32) error {
  1439  	// Pause the kernel to prevent new processes from being created while
  1440  	// the signal is delivered. This prevents process leaks when SIGKILL is
  1441  	// sent to the entire container.
  1442  	l.k.Pause()
  1443  	defer l.k.Unpause()
  1444  	return l.k.SendContainerSignal(cid, &linux.SignalInfo{Signo: signo})
  1445  }
  1446  
  1447  // threadGroupFromID is similar to tryThreadGroupFromIDLocked except that it
  1448  // acquires mutex before calling it and fails in case container hasn't started
  1449  // yet.
  1450  func (l *Loader) threadGroupFromID(key execID) (*kernel.ThreadGroup, error) {
  1451  	l.mu.Lock()
  1452  	defer l.mu.Unlock()
  1453  	tg, err := l.tryThreadGroupFromIDLocked(key)
  1454  	if err != nil {
  1455  		return nil, err
  1456  	}
  1457  	if tg == nil {
  1458  		return nil, fmt.Errorf("container %q not started", key.cid)
  1459  	}
  1460  	return tg, nil
  1461  }
  1462  
  1463  // tryThreadGroupFromIDLocked returns the thread group for the given execution
  1464  // ID. It may return nil in case the container has not started yet. Returns
  1465  // error if execution ID is invalid or if the container cannot be found (maybe
  1466  // it has been deleted). Caller must hold 'mu'.
  1467  func (l *Loader) tryThreadGroupFromIDLocked(key execID) (*kernel.ThreadGroup, error) {
  1468  	ep := l.processes[key]
  1469  	if ep == nil {
  1470  		return nil, fmt.Errorf("container %q not found", key.cid)
  1471  	}
  1472  	return ep.tg, nil
  1473  }
  1474  
  1475  // ttyFromIDLocked returns the TTY files for the given execution ID. It may
  1476  // return nil in case the container has not started yet. Returns error if
  1477  // execution ID is invalid or if the container cannot be found (maybe it has
  1478  // been deleted). Caller must hold 'mu'.
  1479  func (l *Loader) ttyFromIDLocked(key execID) (*host.TTYFileDescription, error) {
  1480  	ep := l.processes[key]
  1481  	if ep == nil {
  1482  		return nil, fmt.Errorf("container %q not found", key.cid)
  1483  	}
  1484  	return ep.tty, nil
  1485  }
  1486  
  1487  func createFDTable(ctx context.Context, console bool, stdioFDs []*fd.FD, passFDs []fdMapping, user specs.User) (*kernel.FDTable, *host.TTYFileDescription, error) {
  1488  	if len(stdioFDs) != 3 {
  1489  		return nil, nil, fmt.Errorf("stdioFDs should contain exactly 3 FDs (stdin, stdout, and stderr), but %d FDs received", len(stdioFDs))
  1490  	}
  1491  	fdMap := map[int]*fd.FD{
  1492  		0: stdioFDs[0],
  1493  		1: stdioFDs[1],
  1494  		2: stdioFDs[2],
  1495  	}
  1496  
  1497  	// Create the entries for the host files that were passed to our app.
  1498  	for _, customFD := range passFDs {
  1499  		if customFD.guest < 0 {
  1500  			return nil, nil, fmt.Errorf("guest file descriptors must be 0 or greater")
  1501  		}
  1502  		fdMap[customFD.guest] = customFD.host
  1503  	}
  1504  
  1505  	k := kernel.KernelFromContext(ctx)
  1506  	fdTable := k.NewFDTable()
  1507  	ttyFile, err := fdimport.Import(ctx, fdTable, console, auth.KUID(user.UID), auth.KGID(user.GID), fdMap)
  1508  	if err != nil {
  1509  		fdTable.DecRef(ctx)
  1510  		return nil, nil, err
  1511  	}
  1512  	return fdTable, ttyFile, nil
  1513  }
  1514  
  1515  // portForward implements initiating a portForward connection in the sandbox. portForwardProxies
  1516  // represent a two connections each copying to each other (read ends to write ends) in goroutines.
  1517  // The proxies are stored and can be cleaned up, or clean up after themselves if the connection
  1518  // is broken.
  1519  func (l *Loader) portForward(opts *PortForwardOpts) error {
  1520  	// Validate that we have a stream FD to write to. If this happens then
  1521  	// it means there is a misbehaved urpc client or a bug has occurred.
  1522  	if len(opts.Files) != 1 {
  1523  		return fmt.Errorf("stream FD is required for port forward")
  1524  	}
  1525  
  1526  	l.mu.Lock()
  1527  	defer l.mu.Unlock()
  1528  
  1529  	cid := opts.ContainerID
  1530  	tg, err := l.tryThreadGroupFromIDLocked(execID{cid: cid})
  1531  	if err != nil {
  1532  		return fmt.Errorf("failed to get threadgroup from %q: %w", cid, err)
  1533  	}
  1534  	if tg == nil {
  1535  		return fmt.Errorf("container %q not started", cid)
  1536  	}
  1537  
  1538  	// Import the fd for the UDS.
  1539  	ctx := l.k.SupervisorContext()
  1540  	fd, err := l.importFD(ctx, opts.Files[0])
  1541  	if err != nil {
  1542  		return fmt.Errorf("importing stream fd: %w", err)
  1543  	}
  1544  	cu := cleanup.Make(func() { fd.DecRef(ctx) })
  1545  	defer cu.Clean()
  1546  
  1547  	fdConn := pf.NewFileDescriptionConn(fd)
  1548  
  1549  	// Create a proxy to forward data between the fdConn and the sandboxed application.
  1550  	pair := pf.ProxyPair{To: fdConn}
  1551  
  1552  	switch l.root.conf.Network {
  1553  	case config.NetworkSandbox:
  1554  		stack := l.k.RootNetworkNamespace().Stack().(*netstack.Stack).Stack
  1555  		nsConn, err := pf.NewNetstackConn(stack, opts.Port)
  1556  		if err != nil {
  1557  			return fmt.Errorf("creating netstack port forward connection: %w", err)
  1558  		}
  1559  		pair.From = nsConn
  1560  	case config.NetworkHost:
  1561  		hConn, err := pf.NewHostInetConn(opts.Port)
  1562  		if err != nil {
  1563  			return fmt.Errorf("creating hostinet port forward connection: %w", err)
  1564  		}
  1565  		pair.From = hConn
  1566  	default:
  1567  		return fmt.Errorf("unsupported network type %q for container %q", l.root.conf.Network, cid)
  1568  	}
  1569  	cu.Release()
  1570  	proxy := pf.NewProxy(pair, opts.ContainerID)
  1571  
  1572  	// Add to the list of port forward connections and remove when the
  1573  	// connection closes.
  1574  	l.portForwardProxies = append(l.portForwardProxies, proxy)
  1575  	proxy.AddCleanup(func() {
  1576  		l.mu.Lock()
  1577  		defer l.mu.Unlock()
  1578  		for i := range l.portForwardProxies {
  1579  			if l.portForwardProxies[i] == proxy {
  1580  				l.portForwardProxies = append(l.portForwardProxies[:i], l.portForwardProxies[i+1:]...)
  1581  				break
  1582  			}
  1583  		}
  1584  	})
  1585  
  1586  	// Start forwarding on the connection.
  1587  	proxy.Start(ctx)
  1588  	return nil
  1589  }
  1590  
  1591  // importFD generically imports a host file descriptor without adding it to any
  1592  // fd table.
  1593  func (l *Loader) importFD(ctx context.Context, f *os.File) (*vfs.FileDescription, error) {
  1594  	hostFD, err := fd.NewFromFile(f)
  1595  	if err != nil {
  1596  		return nil, err
  1597  	}
  1598  	defer hostFD.Close()
  1599  	fd, err := host.NewFD(ctx, l.k.HostMount(), hostFD.FD(), &host.NewFDOptions{
  1600  		Savable:      false, // We disconnect and close on save.
  1601  		IsTTY:        false,
  1602  		VirtualOwner: false, // FD not visible to the sandboxed app so user can't be changed.
  1603  	})
  1604  
  1605  	if err != nil {
  1606  		return nil, err
  1607  	}
  1608  	hostFD.Release()
  1609  	return fd, nil
  1610  }
  1611  
  1612  func (l *Loader) containerCount() int {
  1613  	l.mu.Lock()
  1614  	defer l.mu.Unlock()
  1615  
  1616  	containers := 0
  1617  	for id := range l.processes {
  1618  		if id.pid == 0 {
  1619  			// pid==0 represents the init process of a container. There is
  1620  			// only one of such process per container.
  1621  			containers++
  1622  		}
  1623  	}
  1624  	return containers
  1625  }