diff --git a/libcontainer/nsinit/exec.go b/libcontainer/nsinit/exec.go index 03e0f4b..fbc7512 100644 --- a/libcontainer/nsinit/exec.go +++ b/libcontainer/nsinit/exec.go @@ -123,6 +123,7 @@ func DefaultCreateCommand(container *libcontainer.Container, console, rootfs, da command.Env = append(os.Environ(), env...) system.SetCloneFlags(command, uintptr(GetNamespaceFlags(container.Namespaces))) + command.SysProcAttr.Pdeathsig = syscall.SIGKILL command.ExtraFiles = []*os.File{pipe} return command diff --git a/libcontainer/nsinit/init.go b/libcontainer/nsinit/init.go index af60d73..879b194 100644 --- a/libcontainer/nsinit/init.go +++ b/libcontainer/nsinit/init.go @@ -85,12 +85,53 @@ func Init(container *libcontainer.Container, uncleanRootfs, consolePath string, return err } } + + pdeathSignal, err := system.GetParentDeathSignal() + if err != nil { + return fmt.Errorf("get parent death signal %s", err) + } + if err := FinalizeNamespace(container); err != nil { return fmt.Errorf("finalize namespace %s", err) } + + // FinalizeNamespace can change user/group which clears the parent death + // signal, so we restore it here. + if err := RestoreParentDeathSignal(pdeathSignal); err != nil { + return fmt.Errorf("restore parent death signal %s", err) + } + return system.Execv(args[0], args[0:], container.Env) } +// RestoreParentDeathSignal sets the parent death signal to old. +func RestoreParentDeathSignal(old int) error { + if old == 0 { + return nil + } + + current, err := system.GetParentDeathSignal() + if err != nil { + return fmt.Errorf("get parent death signal %s", err) + } + + if old == current { + return nil + } + + if err := system.ParentDeathSignal(uintptr(old)); err != nil { + return fmt.Errorf("set parent death signal %s", err) + } + + // Signal self if parent is already dead. Does nothing if running in a new + // PID namespace, as Getppid will always return 0. + if syscall.Getppid() == 1 { + return syscall.Kill(syscall.Getpid(), syscall.Signal(old)) + } + + return nil +} + // SetupUser changes the groups, gid, and uid for the user inside the container func SetupUser(u string) error { uid, gid, suppGids, err := user.GetUserGroupSupplementary(u, syscall.Getuid(), syscall.Getgid()) diff --git a/system/calls_linux.go b/system/calls_linux.go index cc4727a..faead01 100644 --- a/system/calls_linux.go +++ b/system/calls_linux.go @@ -3,6 +3,7 @@ package system import ( "os/exec" "syscall" + "unsafe" ) func Chroot(dir string) error { @@ -122,6 +123,18 @@ func ParentDeathSignal(sig uintptr) error { return nil } +func GetParentDeathSignal() (int, error) { + var sig int + + _, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_GET_PDEATHSIG, uintptr(unsafe.Pointer(&sig)), 0) + + if err != 0 { + return -1, err + } + + return sig, nil +} + func Setctty() error { if _, _, err := syscall.RawSyscall(syscall.SYS_IOCTL, 0, uintptr(syscall.TIOCSCTTY), 0); err != 0 { return err