Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 25 additions & 3 deletions internal/shim/manager/manager_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,10 +186,32 @@ func (manager) Start(ctx context.Context, bparams *bootapi.BootstrapParams) (_ *
cmd.ExtraFiles = append(cmd.ExtraFiles, s.f)
}

cloneMntNs(ctx, cmd)
userns := cloneMntNs(ctx, cmd)

if err := cmd.Start(); err != nil {
return nil, err
if startErr := cmd.Start(); startErr != nil {
if !userns {
return nil, startErr
}
Comment thread
dmcgowan marked this conversation as resolved.
// clone(CLONE_NEWUSER) can fail for reasons not covered by the
// proactive AppArmor check — e.g. seccomp filters, LSM policies,
// or EACCES from the child's capability recomputation when
// inherited socket fds cross the user namespace boundary after
// exec. Retry without namespace isolation rather than failing
// the container start.
//
// Note: we cannot log here — during "start" the logger output
// goes to stderr which containerd captures as part of the
// bootstrap response (CombinedOutput), corrupting the JSON.
Comment thread
dmcgowan marked this conversation as resolved.
cmd, err = newCommand(ctx, id, bparams.ContainerdGrpcAddress, bparams.ContainerdTtrpcAddress, debug)
if err != nil {
return nil, err
}
for _, s := range sockets {
cmd.ExtraFiles = append(cmd.ExtraFiles, s.f)
}
if err := cmd.Start(); err != nil {
return nil, fmt.Errorf("retry without userns failed: %w (original error: %v)", err, startErr)
}
Comment thread
dmcgowan marked this conversation as resolved.
}

defer func() {
Expand Down
14 changes: 7 additions & 7 deletions internal/shim/manager/mount_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,19 +52,18 @@ import (
// filesystem setup.
//
// If namespace creation is not possible (e.g. AppArmor restricts
// unprivileged user namespaces), the function logs a warning and the shim
// will run without mount isolation.
func cloneMntNs(_ context.Context, cmd *exec.Cmd) {
// unprivileged user namespaces), the shim runs without mount isolation
// and this function returns false.
// cloneMntNs returns true if user namespace clone flags were set.
func cloneMntNs(_ context.Context, cmd *exec.Cmd) bool {
if restricted, err := apparmorRestrictsUserns(); err != nil {
// Failed to check apparmor userns restriction, skipping mount namespace isolation")
Comment thread
dmcgowan marked this conversation as resolved.
// We can't log anything here as it will break the TTRPC protocol!
// TODO(vvoland): Find a better way to surface this to the user.
return
return false
} else if restricted {
// apparmor_restrict_unprivileged_userns=1 prevents user namespace creation; shim will run without mount namespace isolation
// We can't log anything here as it will break the TTRPC protocol!
// TODO(vvoland): Find a better way to surface this to the user.
return
return false
}

uid := os.Getuid()
Expand All @@ -76,6 +75,7 @@ func cloneMntNs(_ context.Context, cmd *exec.Cmd) {
cmd.SysProcAttr.GidMappings = []syscall.SysProcIDMap{
{ContainerID: gid, HostID: gid, Size: 1},
}
return true
}

// apparmorRestrictsUserns checks if the kernel sysctl
Expand Down
2 changes: 1 addition & 1 deletion internal/shim/manager/mount_other.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ import (
"os/exec"
)

func cloneMntNs(_ context.Context, _ *exec.Cmd) {}
func cloneMntNs(_ context.Context, _ *exec.Cmd) bool { return false }
Loading