Allow sandbox to start without any tasks.
This is the first set of changes to allow multiple containers in a sandbox. - Changes to allow kernel.Start() without any tasks. - New control message to StartContainer() in root namespaces. - Added new function StartSandbox() to keep the existing behavior separate from when the multi-containers is enabled. - Test to verify the new control message with one container. PiperOrigin-RevId: 446792577
This commit is contained in:
parent
bb36c43e97
commit
0c54ff1ffe
|
@ -15,12 +15,152 @@
|
|||
package control
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/fd"
|
||||
"gvisor.dev/gvisor/pkg/log"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs/user"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
"gvisor.dev/gvisor/pkg/sentry/limits"
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs"
|
||||
"gvisor.dev/gvisor/pkg/urpc"
|
||||
)
|
||||
|
||||
// Lifecycle provides functions related to starting and stopping tasks.
|
||||
type Lifecycle struct {
|
||||
// Kernel is the kernel where the tasks belong to.
|
||||
Kernel *kernel.Kernel
|
||||
|
||||
// Sends a message to the sentry that the task has been started.
|
||||
StartedCh chan struct{}
|
||||
|
||||
// TODO(b/202052732): Root mount namespace. When running multiple
|
||||
// containers, create the mount namespace using the mount spec in
|
||||
// the StartContainerArgs.
|
||||
MountNamespaceVFS2 *vfs.MountNamespace
|
||||
}
|
||||
|
||||
// StartContainerArgs is the set of arguments to start a container.
|
||||
type StartContainerArgs struct {
|
||||
// Filename is the filename to load.
|
||||
//
|
||||
// If this is provided as "", then the file will be guessed via Argv[0].
|
||||
Filename string `json:"filename"`
|
||||
|
||||
// Argv is a list of arguments.
|
||||
Argv []string `json:"argv"`
|
||||
|
||||
// Envv is a list of environment variables.
|
||||
Envv []string `json:"envv"`
|
||||
|
||||
// WorkingDirectory defines the working directory for the new process.
|
||||
WorkingDirectory string `json:"wd"`
|
||||
|
||||
// KUID is the UID to run with in the root user namespace. Defaults to
|
||||
// root if not set explicitly.
|
||||
KUID auth.KUID `json:"KUID"`
|
||||
|
||||
// KGID is the GID to run with in the root user namespace. Defaults to
|
||||
// the root group if not set explicitly.
|
||||
KGID auth.KGID `json:"KGID"`
|
||||
|
||||
// ExtraKGIDs is the list of additional groups to which the user belongs.
|
||||
ExtraKGIDs []auth.KGID `json:"extraKGID"`
|
||||
|
||||
// Capabilities is the list of capabilities to give to the process.
|
||||
Capabilities *auth.TaskCapabilities `json:"capabilities"`
|
||||
|
||||
// FilePayload determines the files to give to the new process.
|
||||
urpc.FilePayload
|
||||
|
||||
// ContainerID is the container for the process being executed.
|
||||
ContainerID string `json:"containerID"`
|
||||
|
||||
// Limits is the limit set for the process being executed.
|
||||
Limits *limits.LimitSet `json:"limits"`
|
||||
}
|
||||
|
||||
// String prints the StartContainerArgs.argv as a string.
|
||||
func (args StartContainerArgs) String() string {
|
||||
if len(args.Argv) == 0 {
|
||||
return args.Filename
|
||||
}
|
||||
a := make([]string, len(args.Argv))
|
||||
copy(a, args.Argv)
|
||||
if args.Filename != "" {
|
||||
a[0] = args.Filename
|
||||
}
|
||||
return strings.Join(a, " ")
|
||||
}
|
||||
|
||||
// StartContainer will start a new container in the sandbox.
|
||||
func (l *Lifecycle) StartContainer(args *StartContainerArgs, _ *uint32) error {
|
||||
// Import file descriptors.
|
||||
fdTable := l.Kernel.NewFDTable()
|
||||
|
||||
creds := auth.NewUserCredentials(
|
||||
args.KUID,
|
||||
args.KGID,
|
||||
args.ExtraKGIDs,
|
||||
args.Capabilities,
|
||||
l.Kernel.RootUserNamespace())
|
||||
|
||||
limitSet := args.Limits
|
||||
if limitSet == nil {
|
||||
limitSet = limits.NewLimitSet()
|
||||
}
|
||||
initArgs := kernel.CreateProcessArgs{
|
||||
Filename: args.Filename,
|
||||
Argv: args.Argv,
|
||||
Envv: args.Envv,
|
||||
WorkingDirectory: args.WorkingDirectory,
|
||||
Credentials: creds,
|
||||
FDTable: fdTable,
|
||||
Umask: 0022,
|
||||
Limits: limitSet,
|
||||
MaxSymlinkTraversals: linux.MaxSymlinkTraversals,
|
||||
UTSNamespace: l.Kernel.RootUTSNamespace(),
|
||||
IPCNamespace: l.Kernel.RootIPCNamespace(),
|
||||
AbstractSocketNamespace: l.Kernel.RootAbstractSocketNamespace(),
|
||||
ContainerID: args.ContainerID,
|
||||
PIDNamespace: l.Kernel.RootPIDNamespace(),
|
||||
MountNamespaceVFS2: l.MountNamespaceVFS2,
|
||||
}
|
||||
|
||||
ctx := initArgs.NewContext(l.Kernel)
|
||||
defer fdTable.DecRef(ctx)
|
||||
|
||||
resolved, err := user.ResolveExecutablePath(ctx, &initArgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
initArgs.Filename = resolved
|
||||
|
||||
fds, err := fd.NewFromFiles(args.Files)
|
||||
if err != nil {
|
||||
return fmt.Errorf("duplicating payload files: %w", err)
|
||||
}
|
||||
defer func() {
|
||||
for _, fd := range fds {
|
||||
_ = fd.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
tg, _, err := l.Kernel.CreateProcess(initArgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Start the newly created process.
|
||||
l.Kernel.StartProcess(tg)
|
||||
|
||||
log.Infof("Started the new container")
|
||||
|
||||
l.StartedCh <- struct{}{}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Pause pauses all tasks, blocking until they are stopped.
|
||||
|
|
|
@ -950,6 +950,9 @@ func (k *Kernel) CreateProcess(args CreateProcessArgs) (*ThreadGroup, ThreadID,
|
|||
if VFS2Enabled {
|
||||
mntnsVFS2 = args.MountNamespaceVFS2
|
||||
if mntnsVFS2 == nil {
|
||||
if k.globalInit == nil {
|
||||
return nil, 0, fmt.Errorf("mount namespace is nil")
|
||||
}
|
||||
// Add a reference to the namespace, which is transferred to the new process.
|
||||
mntnsVFS2 = k.globalInit.Leader().MountNamespaceVFS2()
|
||||
mntnsVFS2.IncRef()
|
||||
|
@ -983,6 +986,9 @@ func (k *Kernel) CreateProcess(args CreateProcessArgs) (*ThreadGroup, ThreadID,
|
|||
} else {
|
||||
mntns = args.MountNamespace
|
||||
if mntns == nil {
|
||||
if k.globalInit == nil {
|
||||
return nil, 0, fmt.Errorf("mount namespace is nil")
|
||||
}
|
||||
mntns = k.GlobalInit().Leader().MountNamespace()
|
||||
mntns.IncRef()
|
||||
}
|
||||
|
@ -1100,9 +1106,6 @@ func (k *Kernel) Start() error {
|
|||
k.extMu.Lock()
|
||||
defer k.extMu.Unlock()
|
||||
|
||||
if k.globalInit == nil {
|
||||
return fmt.Errorf("kernel contains no tasks")
|
||||
}
|
||||
if k.started {
|
||||
return fmt.Errorf("kernel already started")
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue