os/exec: if exec.Cmd.Ptrace is set should the code set runtime.LockOSThread()? #28315
Labels
FrozenDueToAge
NeedsInvestigation
Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone
What version of Go are you using (
go version
)?This is a problem under all most all Go versions, but this was 1.11
Does this issue reproduce with the latest release?
yes, but it's racy, see below.
What operating system and processor architecture are you using (
go env
)?almost any linux post about 1.2 :-) and probably any Unix.
What did you do?
As part of writing strace in go for the u-root project I hit an interesting snag and have a question.
If you want to trace a child on Unix, the common path is to have the child of a fork call ptrace with PTRACE_TRACEME. The child will be stopped on the next system call and the parent is then able to take control via ptrace. This is why, as you may have noticed, the strace commands you run show an exec as the first system call.
What's this have to do with Go? The TRACEME rules are strict: only the parent can trace. So if, by some means, the goroutine running the tracing sometimes ends up being run by some process not the parent, you lose trace records with ENOENT, since a process not the parent is trying to trace the child.
I hit this in practice and the fix is easy: the process starting the Command with Ptrace set has to do a runtime.LockOSThread() (and of course unlock after) before starting the command, which ensures that the parent tracing the child is always the parent.
My question: should exec.Command, before calling fork or clone, call runtime.LockOSThread() when Ptrace is set?
On the one hand, it means we're adding a side effect of setting Ptrace: a LockOSThread(). OTOH, NOT setting leads to all kinds of unexpected problems: ptrace failures that seem to have no origin.
Here's a program from liz rice, modified to show the problem. If you use the go func the program rarely works correctly; comment out the go func and it rarely fails.
package main
import (
"fmt"
"os"
"os/exec"
"syscall"
)
func main() {
var regs syscall.PtraceRegs
}
The text was updated successfully, but these errors were encountered: