Current-Users archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

linux ptrace issue [Re: linux clone issue]



On Tue, Oct 05, 2021 at 01:08:52PM +0200, Manuel Bouyer wrote:
> On Tue, Oct 05, 2021 at 12:42:33AM -0400, Eric Hawicz wrote:
> > 
> > On 10/4/2021 10:33 AM, Manuel Bouyer wrote:
> > > Hello
> > > I'm trying to run a binary-only linux program under NetBSD 9.2.
> > >  From what I found, the binary was built on Ubuntu 16.04
> > > [...]
> > > 
> > > As you can see above (ktrace -si output), the read on fd 3 in 26751 returns
> > > with an error as soon as the child does its execve(), just as if CLOSEEXEC
> > > was set in the child. But the dup2(4,1) should keep the write side open
> > > without CLOSEEXEC. The program does a similar sequence just before
> > > (also forking a shell to execute some command) and it works.
> > > Later when sh tries to write to stdout it gets a SIGPIPE.
> > > 
> > > I couldn't reproduce this with a simple program.
> > > But it seems that I can't reproduce this clone call. It seems that we are
> > > called with flags 0x1200011, which would translate to
> > > CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD,
> > > and a NULL stack pointer.
> > > But when run on linux, this clone syscall straces to
> > > CLONE_VM|CLONE_VFORK|SIGCHLD
> > 
> > I think that combination of flags is actually a "fork()" call, which glibc
> > implements using clone.  I found that through https://eli.thegreenplace.net/2018/launching-linux-threads-and-processes-with-clone/,
> > which mentions that glibc has a ARCH_FORK macro, though it seems that the
> > more recent code uses an arch_fork inline function: https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/arch-fork.h;h=b846da08f98839aef336868de24850626428509c;hb=HEAD
> 
> Yes, I think it's a form of fork() or vfork(). But when I compile a
> test program on linux (RHEL7 or Ubuntu 20), fork() and vfork() appears
> as fork and vfork in NetBSD's ktrace, not clone.

I missed a point in the trace output, the parent is killed, and
read() returns not because the other end is closed but because of the
signal.

This seems to come from a ptrace difference between linux and our emulation.
Actually this binary linux program does a fork() and the child does the
work, the parent just waits. But what happens is:
the parent:
p = fork()
wait()
ptrace(PTRACE_CONT, p, NULL, SIG_0)
exit(0)

the child does:
ptrace(PTRACE_TRACEME, 0, NULL, NULL)
<do its work, including several sh fork/exec>
exit(0)

On linux, ptrace(PTRACE_TRACEME) returns EPERM, the wait in the parent
waits until the child exits, and ptrace(PTRACE_CONT) gets ESRCH.

On NetBSD, ptrace(PTRACE_TRACEME) succeeds, wait() returns at some point
before the child exits, the parent ptrace(PTRACE_CONT) the child, the
child gets killed (not by the parent, I can't see a kill() in the trace).

On linux, ptrace(PTRACE_TRACEME) receiving EPERM may be because the process
is running under strace. Running strace without -f (so that only the parent
gets traced), I see the wait() returning, the parent getting a SIGCHLD, and
ptrace(PTRACE_CONT) succeeding. But on linux, it doesn't seem that an
orphaned child process gets killed.

Could our linux ptrace emulation be fixed in any way ?
especially avoid the
pid XXX was killed: orphaned traced process

-- 
Manuel Bouyer <bouyer%antioche.eu.org@localhost>
     NetBSD: 26 ans d'experience feront toujours la difference
--


Home | Main Index | Thread Index | Old Index