diff options
author | Fabricio Voznika <fvoznika@google.com> | 2018-05-24 14:27:05 -0700 |
---|---|---|
committer | Shentubot <shentubot@google.com> | 2018-05-24 14:27:57 -0700 |
commit | e48f7078761b00552ac74068c184ee4fb90fe9aa (patch) | |
tree | 8cb4ff41119d6fa8c28ed11d33f350bae4321ad1 /runsc/boot | |
parent | 7996ae7ccf284718fc98f5ba34c94b044b858ec2 (diff) |
Configure sandbox as superuser
Container user might not have enough priviledge to walk directories and
mount filesystems. Instead, create superuser to perform these steps of
the configuration.
PiperOrigin-RevId: 197953667
Change-Id: I643650ab654e665408e2af1b8e2f2aa12d58d4fb
Diffstat (limited to 'runsc/boot')
-rw-r--r-- | runsc/boot/fs.go | 43 | ||||
-rw-r--r-- | runsc/boot/loader.go | 48 | ||||
-rw-r--r-- | runsc/boot/loader_test.go | 2 |
3 files changed, 52 insertions, 41 deletions
diff --git a/runsc/boot/fs.go b/runsc/boot/fs.go index 86cbe1169..e5b7663d0 100644 --- a/runsc/boot/fs.go +++ b/runsc/boot/fs.go @@ -51,21 +51,30 @@ func (f *fdDispenser) empty() bool { return len(f.fds) == 0 } -// createMountNamespace creates a mount manager containing the root filesystem -// and all mounts. -func createMountNamespace(ctx context.Context, spec *specs.Spec, conf *Config, ioFDs []int) (*fs.MountNamespace, error) { +// createMountNamespace creates a mount namespace containing the root filesystem +// and all mounts. 'rootCtx' is used to walk directories to find mount points. +func createMountNamespace(userCtx context.Context, rootCtx context.Context, spec *specs.Spec, conf *Config, ioFDs []int) (*fs.MountNamespace, error) { fds := &fdDispenser{fds: ioFDs} - - // Create the MountNamespace from the root. - rootInode, err := createRootMount(ctx, spec, conf, fds) + rootInode, err := createRootMount(rootCtx, spec, conf, fds) if err != nil { - return nil, fmt.Errorf("failed to create root overlay: %v", err) + return nil, fmt.Errorf("failed to create root mount: %v", err) } - mns, err := fs.NewMountNamespace(ctx, rootInode) + mns, err := fs.NewMountNamespace(userCtx, rootInode) if err != nil { - return nil, fmt.Errorf("failed to construct MountNamespace: %v", err) + return nil, fmt.Errorf("failed to create root mount namespace: %v", err) + } + if err := configureMounts(rootCtx, spec, conf, mns, fds); err != nil { + return nil, fmt.Errorf("failed to configure mounts: %v", err) + } + if !fds.empty() { + return nil, fmt.Errorf("not all mount points were consumed, remaining: %v", fds) } + return mns, nil +} +// configureMounts iterates over Spec.Mounts and mounts them in the specified +// mount namespace. +func configureMounts(ctx context.Context, spec *specs.Spec, conf *Config, mns *fs.MountNamespace, fds *fdDispenser) error { // Keep track of whether proc, sys, and tmp were mounted. var procMounted, sysMounted, tmpMounted bool @@ -88,7 +97,7 @@ func createMountNamespace(ctx context.Context, spec *specs.Spec, conf *Config, i } if err := mountSubmount(ctx, spec, conf, mns, fds, m); err != nil { - return nil, err + return err } } @@ -97,7 +106,7 @@ func createMountNamespace(ctx context.Context, spec *specs.Spec, conf *Config, i Type: "devtmpfs", Destination: "/dev", }); err != nil { - return nil, err + return err } // Mount proc and sys even if the user did not ask for it, as the spec @@ -107,7 +116,7 @@ func createMountNamespace(ctx context.Context, spec *specs.Spec, conf *Config, i Type: "proc", Destination: "/proc", }); err != nil { - return nil, err + return err } } if !sysMounted { @@ -115,7 +124,7 @@ func createMountNamespace(ctx context.Context, spec *specs.Spec, conf *Config, i Type: "sysfs", Destination: "/sys", }); err != nil { - return nil, err + return err } } @@ -127,15 +136,11 @@ func createMountNamespace(ctx context.Context, spec *specs.Spec, conf *Config, i Type: "tmpfs", Destination: "/tmp", }); err != nil { - return nil, err + return err } } - if !fds.empty() { - return nil, fmt.Errorf("not all mount points were consumed, remaining: %v", fds) - } - - return mns, nil + return nil } // createRootMount creates the root filesystem. diff --git a/runsc/boot/loader.go b/runsc/boot/loader.go index 566f2eb46..76edbb905 100644 --- a/runsc/boot/loader.go +++ b/runsc/boot/loader.go @@ -137,9 +137,6 @@ func New(spec *specs.Spec, conf *Config, controllerFD int, ioFDs []int, console extraKGIDs, caps, auth.NewRootUserNamespace()) - if err != nil { - return nil, fmt.Errorf("error creating credentials: %v", err) - } // Create user namespace. // TODO: Not clear what domain name should be here. It is @@ -159,22 +156,6 @@ func New(spec *specs.Spec, conf *Config, controllerFD int, ioFDs []int, console return nil, fmt.Errorf("error getting executable path: %v", err) } - // Create the process arguments. - procArgs := kernel.CreateProcessArgs{ - Filename: exec, - Argv: spec.Process.Args, - Envv: spec.Process.Env, - WorkingDirectory: spec.Process.Cwd, - Credentials: creds, - // Creating the FDMap requires that we have kernel.Kernel.fdMapUids, so - // it must wait until we have a Kernel. - Umask: uint(syscall.Umask(0)), - Limits: ls, - MaxSymlinkTraversals: linux.MaxSymlinkTraversals, - UTSNamespace: utsns, - IPCNamespace: ipcns, - } - // Create an empty network stack because the network namespace may be empty at // this point. Netns is configured before Run() is called. Netstack is // configured using a control uRPC message. Host network is configured inside @@ -219,14 +200,39 @@ func New(spec *specs.Spec, conf *Config, controllerFD int, ioFDs []int, console return nil, fmt.Errorf("error creating control server: %v", err) } + // Create the process arguments. + procArgs := kernel.CreateProcessArgs{ + Filename: exec, + Argv: spec.Process.Args, + Envv: spec.Process.Env, + WorkingDirectory: spec.Process.Cwd, + Credentials: creds, + // Creating the FDMap requires that we have kernel.Kernel.fdMapUids, so + // it must wait until we have a Kernel. + Umask: uint(syscall.Umask(0)), + Limits: ls, + MaxSymlinkTraversals: linux.MaxSymlinkTraversals, + UTSNamespace: utsns, + IPCNamespace: ipcns, + } ctx := procArgs.NewContext(k) + // Use root user to configure mounts. The current user might not have + // permission to do so. + rootProcArgs := kernel.CreateProcessArgs{ + WorkingDirectory: "/", + Credentials: auth.NewRootCredentials(creds.UserNamespace), + Umask: uint(syscall.Umask(0022)), + MaxSymlinkTraversals: linux.MaxSymlinkTraversals, + } + rootCtx := rootProcArgs.NewContext(k) + // Create the virtual filesystem. - mm, err := createMountNamespace(ctx, spec, conf, ioFDs) + mns, err := createMountNamespace(ctx, rootCtx, spec, conf, ioFDs) if err != nil { return nil, fmt.Errorf("error creating mounts: %v", err) } - k.SetRootMountNamespace(mm) + k.SetRootMountNamespace(mns) // Create the FD map, which will set stdin, stdout, and stderr. If console // is true, then ioctl calls will be passed through to the host fd. diff --git a/runsc/boot/loader_test.go b/runsc/boot/loader_test.go index d2e5fe74e..5bc6f1646 100644 --- a/runsc/boot/loader_test.go +++ b/runsc/boot/loader_test.go @@ -239,7 +239,7 @@ func TestCreateMountNamespace(t *testing.T) { for _, tc := range testCases { ctx := contexttest.Context(t) - mm, err := createMountNamespace(ctx, &tc.spec, conf, nil) + mm, err := createMountNamespace(ctx, ctx, &tc.spec, conf, nil) if err != nil { t.Fatalf("createMountNamespace test case %q failed: %v", tc.name, err) } |