summaryrefslogtreecommitdiffhomepage
path: root/runsc/boot
diff options
context:
space:
mode:
authorFabricio Voznika <fvoznika@google.com>2018-05-24 14:27:05 -0700
committerShentubot <shentubot@google.com>2018-05-24 14:27:57 -0700
commite48f7078761b00552ac74068c184ee4fb90fe9aa (patch)
tree8cb4ff41119d6fa8c28ed11d33f350bae4321ad1 /runsc/boot
parent7996ae7ccf284718fc98f5ba34c94b044b858ec2 (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.go43
-rw-r--r--runsc/boot/loader.go48
-rw-r--r--runsc/boot/loader_test.go2
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)
}