Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nsenter: correctly handle pidns orphaning #976

Closed
wants to merge 7 commits into from
Closed
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
8 changes: 4 additions & 4 deletions libcontainer/configs/namespaces_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ var (
supportedNamespaces = make(map[NamespaceType]bool)
)

// nsToFile converts the namespace type to its filename
func nsToFile(ns NamespaceType) string {
// NsName converts the namespace type to its filename
func NsName(ns NamespaceType) string {
switch ns {
case NEWNET:
return "net"
Expand All @@ -50,7 +50,7 @@ func IsNamespaceSupported(ns NamespaceType) bool {
if ok {
return supported
}
nsFile := nsToFile(ns)
nsFile := NsName(ns)
// if the namespace type is unknown, just return false
if nsFile == "" {
return false
Expand Down Expand Up @@ -84,7 +84,7 @@ func (n *Namespace) GetPath(pid int) string {
if n.Path != "" {
return n.Path
}
return fmt.Sprintf("/proc/%d/ns/%s", pid, nsToFile(n.Type))
return fmt.Sprintf("/proc/%d/ns/%s", pid, NsName(n.Type))
}

func (n *Namespaces) Remove(t NamespaceType) bool {
Expand Down
16 changes: 11 additions & 5 deletions libcontainer/container_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -1223,16 +1223,22 @@ func (c *linuxContainer) currentState() (*State, error) {
// can setns in order.
func (c *linuxContainer) orderNamespacePaths(namespaces map[configs.NamespaceType]string) ([]string, error) {
paths := []string{}
nsTypes := []configs.NamespaceType{
order := []configs.NamespaceType{
// The user namespace *must* be done first.
configs.NEWUSER,
configs.NEWIPC,
configs.NEWUTS,
configs.NEWNET,
configs.NEWPID,
configs.NEWNS,
}
// join userns if the init process explicitly requires NEWUSER
if c.config.Namespaces.Contains(configs.NEWUSER) {
nsTypes = append(nsTypes, configs.NEWUSER)

// Remove namespaces that we don't need to join.
var nsTypes []configs.NamespaceType
for _, ns := range order {
if c.config.Namespaces.Contains(ns) {
nsTypes = append(nsTypes, ns)
}
}
for _, nsType := range nsTypes {
if p, ok := namespaces[nsType]; ok && p != "" {
Expand All @@ -1249,7 +1255,7 @@ func (c *linuxContainer) orderNamespacePaths(namespaces map[configs.NamespaceTyp
if strings.ContainsRune(p, ',') {
return nil, newSystemError(fmt.Errorf("invalid path %s", p))
}
paths = append(paths, p)
paths = append(paths, fmt.Sprintf("%s:%s", configs.NsName(nsType), p))
}
}
return paths, nil
Expand Down
20 changes: 10 additions & 10 deletions libcontainer/integration/exec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ func TestEnter(t *testing.T) {
}
err = container.Run(&pconfig)
stdinR.Close()
defer stdinW.Close()
defer closeStdin(stdinW)
ok(t, err)
pid, err := pconfig.Pid()
ok(t, err)
Expand Down Expand Up @@ -273,7 +273,7 @@ func TestEnter(t *testing.T) {
stdinW2.Close()
waitProcess(&pconfig2, t)

stdinW.Close()
closeStdin(stdinW)
waitProcess(&pconfig, t)

// Check that both processes live in the same pidns
Expand Down Expand Up @@ -499,7 +499,7 @@ func testFreeze(t *testing.T, systemd bool) {
}
err = container.Run(pconfig)
stdinR.Close()
defer stdinW.Close()
defer closeStdin(stdinW)
ok(t, err)

err = container.Pause()
Expand All @@ -512,7 +512,7 @@ func testFreeze(t *testing.T, systemd bool) {
t.Fatal("Unexpected state: ", state)
}

stdinW.Close()
closeStdin(stdinW)
waitProcess(pconfig, t)
}

Expand Down Expand Up @@ -713,7 +713,7 @@ func TestContainerState(t *testing.T) {
t.Fatal(err)
}
stdinR.Close()
defer stdinW.Close()
defer closeStdin(stdinW)

st, err := container.State()
if err != nil {
Expand All @@ -727,7 +727,7 @@ func TestContainerState(t *testing.T) {
if l1 != l {
t.Fatal("Container using non-host ipc namespace")
}
stdinW.Close()
closeStdin(stdinW)
waitProcess(p, t)
}

Expand Down Expand Up @@ -1222,7 +1222,7 @@ func TestRootfsPropagationSlaveMount(t *testing.T) {

err = container.Run(pconfig)
stdinR.Close()
defer stdinW.Close()
defer closeStdin(stdinW)
ok(t, err)

// Create mnt1host/mnt2host and bind mount itself on top of it. This
Expand Down Expand Up @@ -1256,7 +1256,7 @@ func TestRootfsPropagationSlaveMount(t *testing.T) {

stdinW2.Close()
waitProcess(pconfig2, t)
stdinW.Close()
closeStdin(stdinW)
waitProcess(pconfig, t)

mountPropagated = false
Expand Down Expand Up @@ -1339,7 +1339,7 @@ func TestRootfsPropagationSharedMount(t *testing.T) {

err = container.Run(pconfig)
stdinR.Close()
defer stdinW.Close()
defer closeStdin(stdinW)
ok(t, err)

// Create mnt1host/mnt2cont. This will become visible inside container
Expand Down Expand Up @@ -1377,7 +1377,7 @@ func TestRootfsPropagationSharedMount(t *testing.T) {
// Wait for process
stdinW2.Close()
waitProcess(pconfig2, t)
stdinW.Close()
closeStdin(stdinW)
waitProcess(pconfig, t)

defer unmountOp(dir2host)
Expand Down
34 changes: 17 additions & 17 deletions libcontainer/integration/execin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func TestExecIn(t *testing.T) {
}
err = container.Run(process)
stdinR.Close()
defer stdinW.Close()
defer closeStdin(stdinW)
ok(t, err)

buffers := newStdBuffers()
Expand All @@ -54,7 +54,7 @@ func TestExecIn(t *testing.T) {
err = container.Run(ps)
ok(t, err)
waitProcess(ps, t)
stdinW.Close()
closeStdin(stdinW)
waitProcess(process, t)

out := buffers.Stdout.String()
Expand Down Expand Up @@ -105,7 +105,7 @@ func testExecInRlimit(t *testing.T, userns bool) {
}
err = container.Run(process)
stdinR.Close()
defer stdinW.Close()
defer closeStdin(stdinW)
ok(t, err)

buffers := newStdBuffers()
Expand All @@ -125,7 +125,7 @@ func testExecInRlimit(t *testing.T, userns bool) {
ok(t, err)
waitProcess(ps, t)

stdinW.Close()
closeStdin(stdinW)
waitProcess(process, t)

out := buffers.Stdout.String()
Expand Down Expand Up @@ -159,7 +159,7 @@ func TestExecInAdditionalGroups(t *testing.T) {
}
err = container.Run(process)
stdinR.Close()
defer stdinW.Close()
defer closeStdin(stdinW)
ok(t, err)

var stdout bytes.Buffer
Expand All @@ -177,7 +177,7 @@ func TestExecInAdditionalGroups(t *testing.T) {
// Wait for process
waitProcess(&pconfig, t)

stdinW.Close()
closeStdin(stdinW)
waitProcess(process, t)

outputGroups := string(stdout.Bytes())
Expand Down Expand Up @@ -216,7 +216,7 @@ func TestExecInError(t *testing.T) {
err = container.Run(process)
stdinR.Close()
defer func() {
stdinW.Close()
closeStdin(stdinW)
if _, err := process.Wait(); err != nil {
t.Log(err)
}
Expand Down Expand Up @@ -267,7 +267,7 @@ func TestExecInTTY(t *testing.T) {
}
err = container.Run(process)
stdinR.Close()
defer stdinW.Close()
defer closeStdin(stdinW)
ok(t, err)

var stdout bytes.Buffer
Expand All @@ -292,7 +292,7 @@ func TestExecInTTY(t *testing.T) {
}
waitProcess(ps, t)

stdinW.Close()
closeStdin(stdinW)
waitProcess(process, t)

out := stdout.String()
Expand Down Expand Up @@ -324,7 +324,7 @@ func TestExecInEnvironment(t *testing.T) {
}
err = container.Run(process)
stdinR.Close()
defer stdinW.Close()
defer closeStdin(stdinW)
ok(t, err)

buffers := newStdBuffers()
Expand All @@ -345,7 +345,7 @@ func TestExecInEnvironment(t *testing.T) {
ok(t, err)
waitProcess(process2, t)

stdinW.Close()
closeStdin(stdinW)
waitProcess(process, t)

out := buffers.Stdout.String()
Expand Down Expand Up @@ -388,7 +388,7 @@ func TestExecinPassExtraFiles(t *testing.T) {
}
err = container.Run(process)
stdinR.Close()
defer stdinW.Close()
defer closeStdin(stdinW)
if err != nil {
t.Fatal(err)
}
Expand All @@ -410,7 +410,7 @@ func TestExecinPassExtraFiles(t *testing.T) {
}

waitProcess(inprocess, t)
stdinW.Close()
closeStdin(stdinW)
waitProcess(process, t)

out := string(stdout.Bytes())
Expand Down Expand Up @@ -461,7 +461,7 @@ func TestExecInOomScoreAdj(t *testing.T) {
}
err = container.Run(process)
stdinR.Close()
defer stdinW.Close()
defer closeStdin(stdinW)
ok(t, err)

buffers := newStdBuffers()
Expand All @@ -477,7 +477,7 @@ func TestExecInOomScoreAdj(t *testing.T) {
ok(t, err)
waitProcess(ps, t)

stdinW.Close()
closeStdin(stdinW)
waitProcess(process, t)

out := buffers.Stdout.String()
Expand Down Expand Up @@ -516,7 +516,7 @@ func TestExecInUserns(t *testing.T) {
}
err = container.Run(process)
stdinR.Close()
defer stdinW.Close()
defer closeStdin(stdinW)
ok(t, err)

initPID, err := process.Pid()
Expand All @@ -537,7 +537,7 @@ func TestExecInUserns(t *testing.T) {
err = container.Run(process2)
ok(t, err)
waitProcess(process2, t)
stdinW.Close()
closeStdin(stdinW)
waitProcess(process, t)

if out := strings.TrimSpace(buffers.Stdout.String()); out != initUserns {
Expand Down
9 changes: 9 additions & 0 deletions libcontainer/integration/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"crypto/md5"
"encoding/hex"
"fmt"
"io"
"io/ioutil"
"os"
"os/exec"
Expand Down Expand Up @@ -52,6 +53,14 @@ func ok(t testing.TB, err error) {
}
}

func closeStdin(w io.WriteCloser) {
// Now, a sane shell wouldn't require this, but busybox is not sane. For
// some reason, busybox will not wait(-1) until you enter a newline. It
// doesn't make any sense.
w.Write([]byte("\n"))
w.Close()
}

func waitProcess(p *libcontainer.Process, t *testing.T) {
_, file, line, _ := runtime.Caller(1)
status, err := p.Wait()
Expand Down
Loading