diff --git a/libcontainer/init_linux.go b/libcontainer/init_linux.go index d7058eaa..0433913a 100644 --- a/libcontainer/init_linux.go +++ b/libcontainer/init_linux.go @@ -187,7 +187,17 @@ func setupUser(config *initConfig) error { return err } } - + // change the permissions on the STDIO of the current process so that when the user + // is changed for the container, it's STDIO of the process matches the user. + for _, fd := range []uintptr{ + os.Stdin.Fd(), + os.Stderr.Fd(), + os.Stdout.Fd(), + } { + if err := syscall.Fchown(int(fd), execUser.Uid, execUser.Gid); err != nil { + return err + } + } suppGroups := append(execUser.Sgids, addGroups...) if err := syscall.Setgroups(suppGroups); err != nil { return err diff --git a/libcontainer/integration/exec_test.go b/libcontainer/integration/exec_test.go index 582d6bb3..04fbe651 100644 --- a/libcontainer/integration/exec_test.go +++ b/libcontainer/integration/exec_test.go @@ -994,3 +994,23 @@ func TestHook(t *testing.T) { t.Fatalf("expected file to not exist, got %s", fi.Name()) } } + +func TestSTDIOPermissions(t *testing.T) { + if testing.Short() { + return + } + + rootfs, err := newRootfs() + ok(t, err) + defer remove(rootfs) + config := newTemplateConfig(rootfs) + buffers, exitCode, err := runContainer(config, "", "sh", "-c", "echo hi > /dev/stderr") + ok(t, err) + if exitCode != 0 { + t.Fatalf("exit code not 0. code %d stderr %q", exitCode, buffers.Stderr) + } + + if actual := strings.Trim(buffers.Stderr.String(), "\n"); actual != "hi" { + t.Fatalf("stderr should equal be equal %q %q", actual, "hi") + } +}