Skip to content

Commit 2ca0537

Browse files
committed
Implement Pdeathsig behavior for child processes and enhance integration tests
Signed-off-by: fahed dorgaa <[email protected]>
1 parent cc4f3f5 commit 2ca0537

File tree

2 files changed

+96
-49
lines changed

2 files changed

+96
-49
lines changed

hack/integration-pdeathsig.sh

Lines changed: 68 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,27 @@
44
# 1. Uses rootlesskit to spawn a long-running process
55
# 2. Kills the rootlesskit parent process
66
# 3. Verifies that the child process is killed as expected
7+
# 4. Tests both with --reaper true and --reaper false
78

89
source $(realpath $(dirname $0))/common.inc.sh
910

1011
INFO "Starting Pdeathsig test using rootlesskit..."
1112

12-
# Create a temporary directory for test artifacts
13-
TEMP_DIR=$(mktemp -d)
14-
INFO "Created temporary directory: $TEMP_DIR"
13+
# Function to run the test with a specific reaper setting
14+
run_test() {
15+
local reaper_setting=$1
16+
INFO "Testing with --reaper $reaper_setting"
1517

16-
# Create a marker file that will be touched by the child process if it's still alive
17-
MARKER_FILE="$TEMP_DIR/child_still_alive"
18+
# Create a temporary directory for test artifacts
19+
TEMP_DIR=$(mktemp -d)
20+
INFO "Created temporary directory: $TEMP_DIR"
1821

19-
# Create a script that will be executed by rootlesskit
20-
CHILD_SCRIPT="$TEMP_DIR/child_script.sh"
21-
cat > "$CHILD_SCRIPT" << 'EOF'
22+
# Create a marker file that will be touched by the child process if it's still alive
23+
MARKER_FILE="$TEMP_DIR/child_still_alive"
24+
25+
# Create a script that will be executed by rootlesskit
26+
CHILD_SCRIPT="$TEMP_DIR/child_script.sh"
27+
cat > "$CHILD_SCRIPT" << 'EOF'
2228
#!/bin/bash
2329
echo "Child process started with PID: $$"
2430
echo "Parent PID: $PPID"
@@ -50,51 +56,70 @@ echo "Child completed normally (this shouldn't happen if Pdeathsig is working)"
5056
touch MARKER_FILE_PLACEHOLDER
5157
EOF
5258

53-
# Replace the placeholder with the actual marker file path
54-
sed -i "s|MARKER_FILE_PLACEHOLDER|$MARKER_FILE|g" "$CHILD_SCRIPT"
55-
chmod +x "$CHILD_SCRIPT"
59+
# Replace the placeholder with the actual marker file path
60+
sed -i "s|MARKER_FILE_PLACEHOLDER|$MARKER_FILE|g" "$CHILD_SCRIPT"
61+
chmod +x "$CHILD_SCRIPT"
5662

57-
# Start rootlesskit with the child script
58-
INFO "Starting rootlesskit..."
59-
$ROOTLESSKIT "$CHILD_SCRIPT" &
60-
ROOTLESSKIT_PID=$!
61-
INFO "Rootlesskit started with PID: $ROOTLESSKIT_PID"
63+
# Start rootlesskit with the child script
64+
INFO "Starting rootlesskit with --reaper $reaper_setting..."
65+
if [ "$reaper_setting" = "true" ]; then
66+
$ROOTLESSKIT --reaper $reaper_setting --pidns "$CHILD_SCRIPT" &
67+
else
68+
$ROOTLESSKIT --reaper $reaper_setting "$CHILD_SCRIPT" &
69+
fi
70+
ROOTLESSKIT_PID=$!
71+
INFO "Rootlesskit started with PID: $ROOTLESSKIT_PID"
6272

63-
# Wait a moment for the child to start
64-
sleep 2
73+
# Wait a moment for the child to start
74+
sleep 2
6575

66-
# Find the child process
67-
CHILD_PID=$(pgrep -P $ROOTLESSKIT_PID)
68-
if [ -z "$CHILD_PID" ]; then
69-
ERROR "Failed to find child process"
70-
exit 1
71-
fi
72-
INFO "Found child process with PID: $CHILD_PID"
76+
# Find the child process
77+
ROOTLESSKIT_CHILD_PID=$(pgrep -P $ROOTLESSKIT_PID)
78+
if [ -z "$ROOTLESSKIT_CHILD_PID" ]; then
79+
ERROR "Failed to find rootlesskit child process"
80+
return 1
81+
fi
82+
INFO "Found rootlesskit child process with PID: $ROOTLESSKIT_CHILD_PID"
83+
84+
# Kill the rootlesskit process
85+
INFO "Killing rootlesskit process (PID: $ROOTLESSKIT_PID)..."
86+
kill -9 $ROOTLESSKIT_PID
87+
88+
# Wait a moment for the rootlesskit child to be killed
89+
sleep 2
90+
91+
# Check if the rootlesskit child process is still running
92+
if ps -p $ROOTLESSKIT_CHILD_PID > /dev/null; then
93+
ERROR "FAIL: Rootlesskit Child process (PID: $ROOTLESSKIT_CHILD_PID) is still running after rootlesskit parent was killed"
94+
kill -9 $ROOTLESSKIT_CHILD_PID # Clean up
95+
return 1
96+
else
97+
INFO "PASS: Rootlesskit Child process (PID: $ROOTLESSKIT_CHILD_PID) was killed as expected"
98+
fi
7399

74-
# Kill the rootlesskit process
75-
INFO "Killing rootlesskit process (PID: $ROOTLESSKIT_PID)..."
76-
kill -9 $ROOTLESSKIT_PID
100+
# Check if the marker file exists
101+
if [ -f "$MARKER_FILE" ]; then
102+
ERROR "FAIL: Marker file exists, which means the child process wasn't killed by Pdeathsig"
103+
return 1
104+
else
105+
INFO "PASS: Marker file doesn't exist, which means the child process was killed by Pdeathsig"
106+
fi
77107

78-
# Wait a moment for the child to be killed
79-
sleep 2
108+
INFO "Test with --reaper $reaper_setting completed successfully!"
109+
rm -rf "$TEMP_DIR"
110+
return 0
111+
}
80112

81-
# Check if the child process is still running
82-
if ps -p $CHILD_PID > /dev/null; then
83-
ERROR "FAIL: Child process (PID: $CHILD_PID) is still running after parent was killed"
84-
kill -9 $CHILD_PID # Clean up
113+
# Run tests with both reaper settings
114+
if ! run_test "true"; then
115+
ERROR "Test with --reaper true failed"
85116
exit 1
86-
else
87-
INFO "PASS: Child process (PID: $CHILD_PID) was killed as expected"
88117
fi
89118

90-
# Check if the marker file exists
91-
if [ -f "$MARKER_FILE" ]; then
92-
ERROR "FAIL: Marker file exists, which means the child process wasn't killed by Pdeathsig"
119+
if ! run_test "false"; then
120+
ERROR "Test with --reaper false failed"
93121
exit 1
94-
else
95-
INFO "PASS: Marker file doesn't exist, which means the child process was killed by Pdeathsig"
96122
fi
97123

98-
INFO "Test completed successfully!"
99-
rm -rf "$TEMP_DIR"
124+
INFO "All tests completed successfully!"
100125
exit 0

pkg/child/child.go

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -503,12 +503,24 @@ func Child(opt Opt) error {
503503
return fmt.Errorf("command %v exited: %w", opt.TargetCmd, err)
504504
}
505505
} else {
506-
if err := cmd.Start(); err != nil {
507-
return fmt.Errorf("command %v exited: %w", opt.TargetCmd, err)
508-
}
509-
sigc := sigproxy.ForwardAllSignals(context.TODO(), cmd.Process.Pid)
510-
defer sigproxysignal.StopCatch(sigc)
511-
if err := cmd.Wait(); err != nil {
506+
// Launch a goroutine to execute the command with Pdeathsig
507+
go func() {
508+
// Lock the goroutine to the OS thread
509+
runtime.LockOSThread()
510+
defer runtime.UnlockOSThread()
511+
512+
// Set the parent death signal
513+
if err := unix.Prctl(unix.PR_SET_PDEATHSIG, uintptr(unix.SIGKILL), 0, 0, 0); err != nil {
514+
cmdErrCh <- err
515+
return
516+
}
517+
518+
// Run the command without reaping
519+
cmdErrCh <- runWithoutReap(cmd)
520+
}()
521+
522+
// Wait for the command to complete
523+
if err := <-cmdErrCh; err != nil {
512524
return fmt.Errorf("command %v exited: %w", opt.TargetCmd, err)
513525
}
514526
}
@@ -529,6 +541,16 @@ func setMountPropagation(propagation string) error {
529541
return nil
530542
}
531543

544+
func runWithoutReap(cmd *exec.Cmd) error {
545+
cmd.SysProcAttr.Setsid = true
546+
if err := cmd.Start(); err != nil {
547+
return err
548+
}
549+
sigc := sigproxy.ForwardAllSignals(context.TODO(), cmd.Process.Pid)
550+
defer sigproxysignal.StopCatch(sigc)
551+
return cmd.Wait()
552+
}
553+
532554
func runAndReap(cmd *exec.Cmd) error {
533555
c := make(chan os.Signal, 32)
534556
signal.Notify(c, syscall.SIGCHLD)

0 commit comments

Comments
 (0)