lkml.org 
[lkml]   [2008]   [Oct]   [27]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
From
Subjectinconsistent behavior with ptrace(TRACEME) and fork/exec
Date
--nextPart3480442.bVZSW9GQNi
Content-Type: text/plain;
charset="us-ascii"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

i'm hoping my understanding of ptrace is correct and that the attached test=
=20
case (reduced from LTP) isnt just completely broken ... my understanding is=
=20
that if a parent forks and the child does a ptrace(TRACEME) right before=20
doing an exec(), the kernel should always halt it and wait indefinitely for=
=20
the parent to start ptracing it.

unfortunately, this behavior seems to be unreliable. most of the time it=20
works, but sometimes the kernel does not halt the child and it gladly does=
=20
the exec() that it set out to do. i dont believe this to be a race in the=
=20
user space parent component as forcing it to delay via judicious usage of=20
sleep() shows the same behavior.

if all goes well, we should only ever see "SUCCESS!" from the test case:
$ gcc -Wall ptrace-vfork-traceme.c -o ptrace-vfork-traceme
$ while ./ptrace-vfork-traceme ; do :; done
SUCCESS! :D
SUCCESS! :D
SUCCESS! :D
SUCCESS! :D
SUCCESS! :D
SUCCESS! :D
SUCCESS! :D
SUCCESS! :D
SUCCESS! :D
failure, child exited with 17: Child exited
wait() =3D 12275
status =3D 1407
WIFEXITED =3D 0
WEXITSTATUS =3D 5
WIFSIGNALED =3D 0
WTERMSIG =3D 127 (Unknown signal 127)

i'm testing 2.6.26/2.6.27 atm. both x86_64 and ppc64 seem to behave the sa=
me. =20
while gcc-4.3.2 / glibc-2.8 is in use in both places, i dont think that=20
matters.

also, while the attached test uses vfork(), same behavior can be observed w=
ith=20
fork(). vfork() is used because i like my test cases to work on both MMU a=
nd=20
no-MMU systems.
=2Dmike

--nextPart3480442.bVZSW9GQNi
Content-Type: application/pgp-signature; name=signature.asc
Content-Description: This is a digitally signed message part.

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.9 (GNU/Linux)

iQIcBAABAgAGBQJJBYIEAAoJEEFjO5/oN/WBV7gP/jHcH1Pdyu5xq99Ivtpan6t8
sXBpB02hlFD9D3lTAXHQQl6GfVLhRKirZr5L64TJwoV9MnBvUn5UYjKtVnwu92Jb
jCAYrmFftNoB79+aL82bktf5AK39pIGdqCJBQ5OM+7a/5i4GqzqViHYF71bnf6YH
5bFXe8NwafH7kA/CpYTzUMX5e8iG6aBxDGuXaWiIk3AGRqN7MfmRU4Z5/HoscPb4
pyTXgi0Rebk/mG1UG3dYb1S3gmPfuaNpdKqfz9/0IRChc++bblgZAPnHjzfz7vln
YQBlITzxTjTL3uoDO4S36y2cyzU4tDQO3r1yjbnGMFdbNZ9GDBh30i9dsACxdSz/
jqm8cfmNr5yLjFTMMhEWeEwoTgitgBpEQ8ifEkFKS+VLdE7zzldmctW/x8sDoXSz
sL8XBb6MpLIyRoag3B7JeCYeYrOErexabxJO3glAmpXqW7FhOEkKZ/q8RqKqrCuN
Cj8vl/4ga5+6Exxhhwk5nGQPJzynqMvn9Fwhih/RTQaQHKrlKJfQ35qZ2d6pITkx
kd5p4/n57BM9L+XhaVY/M86ys2IOBgdc9hZhf8uiN6zXpjIViHw9QJ8K+SxDbLBu
tteP/f9GG0X6wo3qUoOWxU6vMdAhVB8osqsFKIcNCdDCNKLNlu82Q+rlhmaswkAy
mXgVYt85olz8JTV/1LDJ
=rqWg
-----END PGP SIGNATURE-----

--nextPart3480442.bVZSW9GQNi--
#define _GNU_SOURCE
#include <errno.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/wait.h>

#define fail(msg, args...) \
do { \
fprintf(stderr, "FAIL:%i: " msg "\n", __LINE__, ## args); \
exit(1); \
} while (0)

static void child_exit(int sig)
{
int status;
printf("failure, child exited with %i: %s\n", sig, strsignal(sig));
printf("wait() = %i\n", wait(&status));
printf("status = %i\n", status);
printf("\tWIFEXITED = %i\n", WIFEXITED(status));
printf("\tWEXITSTATUS = %i\n", WEXITSTATUS(status));
printf("\tWIFSIGNALED = %i\n", WIFSIGNALED(status));
printf("\tWTERMSIG = %i (%s)\n", WTERMSIG(status), strsignal(WTERMSIG(status)));
exit(1);
}

int main(int argc, char *argv[])
{
long pret;
pid_t pid;

/* child process ... shouldnt be executed, but just in case ... */
if (argc > 1 && !strcmp(argv[1], "child"))
fail("kernel should have halted me...");

pid = vfork();
if (pid == -1)
fail("vfork() didnt work: %m");
else if (!pid) {
/* do the child stuff here */
errno = 0;
pret = ptrace(PTRACE_TRACEME, 0, NULL, NULL);
if (pret && errno)
fail("ptrace(PTRACE_TRACEME) = %li: %m", pret);

int eret = execlp(argv[0], argv[0], "child", NULL);
fail("execlp() = %i", eret);
}

/* do the parent stuff here */
signal(SIGCHLD, child_exit);

errno = 0;
pret = ptrace(PTRACE_PEEKUSER, pid, NULL, NULL);
if (pret && errno)
fail("ptrace(PTRACE_PEEKUSER, %i) = %li: %m", pid, pret);

puts("SUCCESS! :D");

return 0;
}
\
 
 \ /
  Last update: 2008-10-27 09:57    [W:0.030 / U:1.440 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site