From 8b6a623a05eefb40da116402370e01ca3ba65e1a Mon Sep 17 00:00:00 2001 From: Fahed Dorgaa Date: Tue, 31 Mar 2026 23:56:39 +0100 Subject: [PATCH] fix: remove Setsid from runWithoutReap to restore TTY Commit 2ca0537 introduced Setsid=true in runWithoutReap(), which creates a new session for the child process and detaches it from the controlling terminal. This causes bash to fail with: bash: cannot set terminal process group (-1): Inappropriate ioctl for device bash: no job control in this shell Setsid is only needed in runAndReap() where rootlesskit acts as init and needs session isolation for zombie reaping via Wait4(-1, ...). In the non-reaping path, the child should inherit the parent session to retain access to the TTY. Pdeathsig (PR_SET_PDEATHSIG) does not require Setsid. An integration test for runWithoutReap is added to prevent regressions. Fixes #557 Signed-off-by: fahed dorgaa --- .github/workflows/main.yaml | 2 ++ hack/integration-run-without-reap.sh | 42 ++++++++++++++++++++++++++++ pkg/child/child.go | 1 - 3 files changed, 44 insertions(+), 1 deletion(-) create mode 100755 hack/integration-run-without-reap.sh diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 42f85896..53eb1cab 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -54,6 +54,8 @@ jobs: run: docker run --rm --net=none --privileged rootlesskit:test-integration ./integration-systemd-socket.sh - name: "Integration test: pdeathsig" run: docker run --rm --privileged rootlesskit:test-integration ./integration-pdeathsig.sh + - name: "Integration test: runWithoutReap" + run: docker run --rm --privileged rootlesskit:test-integration ./integration-run-without-reap.sh - name: "Integration test: Network (network driver=slirp4netns)" run: | docker run --rm --privileged rootlesskit:test-integration ./integration-net.sh slirp4netns diff --git a/hack/integration-run-without-reap.sh b/hack/integration-run-without-reap.sh new file mode 100755 index 00000000..9e5bf71f --- /dev/null +++ b/hack/integration-run-without-reap.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# Integration test for runWithoutReap (--reaper=false path). +# Regression test for https://github.com/rootless-containers/rootlesskit/issues/557 +source $(realpath $(dirname $0))/common.inc.sh + +INFO "Testing runWithoutReap: command execution" +out=$($ROOTLESSKIT --reaper=false echo hello 2>&1) +if ! echo "$out" | grep -q "hello"; then + ERROR "expected 'hello' in output, got: $out" + exit 1 +fi + +INFO "Testing runWithoutReap: exit code propagation" +set +e +$ROOTLESSKIT --reaper=false sh -c "exit 42" >/dev/null 2>&1 +code=$? +set -e +if [ $code != 42 ]; then + ERROR "expected exit code 42, got $code" + exit 1 +fi + +INFO "Testing runWithoutReap: TTY preservation" +# Use script(1) to allocate a PTY; verify the child sees a TTY +# and does not print "cannot set terminal process group" (issue #557). +tmp=$(mktemp -d) +script -qec "$ROOTLESSKIT --reaper=false sh -c 'tty; echo DONE'" "$tmp/typescript" > "$tmp/out" 2>&1 +if grep -qi "cannot set terminal process group" "$tmp/out"; then + ERROR "child lost its controlling terminal (setsid regression)" + cat "$tmp/out" + rm -rf "$tmp" + exit 1 +fi +if ! grep -q "DONE" "$tmp/out"; then + ERROR "child did not complete" + cat "$tmp/out" + rm -rf "$tmp" + exit 1 +fi +rm -rf "$tmp" + +INFO "===== All runWithoutReap tests passed =====" diff --git a/pkg/child/child.go b/pkg/child/child.go index 87824782..c72b9044 100644 --- a/pkg/child/child.go +++ b/pkg/child/child.go @@ -542,7 +542,6 @@ func setMountPropagation(propagation string) error { } func runWithoutReap(cmd *exec.Cmd) error { - cmd.SysProcAttr.Setsid = true if err := cmd.Start(); err != nil { return err }