Skip to content

Commit b90a4ad

Browse files
committed
Lock OS threads when exec'ing with Pdeathsig
On Linux, when (os/exec.Cmd).SysProcAttr.Pdeathsig is set, the signal will be sent to the process when the OS thread on which cmd.Start() was executed dies. The runtime terminates an OS thread when a goroutine exits after being wired to the thread with runtime.LockOSThread(). If other goroutines are allowed to be scheduled onto a thread which called cmd.Start(), an unrelated goroutine could cause the thread to be terminated and prematurely signal the command. See golang/go#27505 for more information. Prevent started subprocesses with Pdeathsig from getting signaled prematurely by wiring the starting goroutine to the OS thread until the subprocess has exited. No other goroutines can be scheduled onto a locked thread so it will remain alive until unlocked or the daemon process exits. Signed-off-by: Cory Snider <[email protected]>
1 parent 6c1411a commit b90a4ad

File tree

2 files changed

+28
-4
lines changed

2 files changed

+28
-4
lines changed

chrootarchive/archive_unix.go

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,12 @@ func invokeUnpack(decompressedArchive io.Reader, dest string, options *archive.T
9595
cmd.Stdout = output
9696
cmd.Stderr = output
9797

98+
// reexec.Command() sets cmd.SysProcAttr.Pdeathsig on Linux, which
99+
// causes the started process to be signaled when the creating OS thread
100+
// dies. Ensure that the reexec is not prematurely signaled. See
101+
// https://go.dev/issue/27505 for more information.
102+
runtime.LockOSThread()
103+
defer runtime.UnlockOSThread()
98104
if err := cmd.Start(); err != nil {
99105
w.Close()
100106
return fmt.Errorf("Untar error on re-exec cmd: %v", err)
@@ -188,15 +194,27 @@ func invokePack(srcPath string, options *archive.TarOptions, root string) (io.Re
188194
return nil, errors.Wrap(err, "error getting options pipe for tar process")
189195
}
190196

191-
if err := cmd.Start(); err != nil {
192-
return nil, errors.Wrap(err, "tar error on re-exec cmd")
193-
}
194-
197+
started := make(chan error)
195198
go func() {
199+
// reexec.Command() sets cmd.SysProcAttr.Pdeathsig on Linux,
200+
// which causes the started process to be signaled when the
201+
// creating OS thread dies. Ensure that the subprocess is not
202+
// prematurely signaled. See https://go.dev/issue/27505 for more
203+
// information.
204+
runtime.LockOSThread()
205+
defer runtime.UnlockOSThread()
206+
if err := cmd.Start(); err != nil {
207+
started <- err
208+
return
209+
}
210+
close(started)
196211
err := cmd.Wait()
197212
err = errors.Wrapf(err, "error processing tar file: %s", errBuff)
198213
tarW.CloseWithError(err)
199214
}()
215+
if err := <-started; err != nil {
216+
return nil, errors.Wrap(err, "tar error on re-exec cmd")
217+
}
200218

201219
if err := json.NewEncoder(stdin).Encode(options); err != nil {
202220
stdin.Close()

chrootarchive/diff_unix.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,12 @@ func applyLayerHandler(dest string, layer io.Reader, options *archive.TarOptions
115115
outBuf, errBuf := new(bytes.Buffer), new(bytes.Buffer)
116116
cmd.Stdout, cmd.Stderr = outBuf, errBuf
117117

118+
// reexec.Command() sets cmd.SysProcAttr.Pdeathsig on Linux, which
119+
// causes the started process to be signaled when the creating OS thread
120+
// dies. Ensure that the reexec is not prematurely signaled. See
121+
// https://go.dev/issue/27505 for more information.
122+
runtime.LockOSThread()
123+
defer runtime.UnlockOSThread()
118124
if err = cmd.Run(); err != nil {
119125
return 0, fmt.Errorf("ApplyLayer %s stdout: %s stderr: %s", err, outBuf, errBuf)
120126
}

0 commit comments

Comments
 (0)