Ptrace options dont set the correct status when the desired systemcalls resume in the parent process. I can only use whats seen here no PEEKUSER, SYSGOOD or SYSCALL. Ive read the ptrace man and looked for examples for the past few days, Im mentally exhausted.
Any ideas/tips, no matter how small, are welcome. thanks.
argument: /bin/bash -c "echo 'first test' | wc -c"
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
int wait_for_syscall(pid_t child) {
int status;
while (1) {
ptrace(PTRACE_CONT, child, 0, 0);
waitpid(child, &status, 0);
if (WIFSTOPPED(status) && WSTOPSIG(status) | 0x80)
return 0;
if (WIFEXITED(status))
return 1;
}
}
int main(int argc, char *argv[]) {
int status;
int counter = 0;
pid_t pid = fork();
if (pid < 0)
exit(1);
else if (pid == 0) {
ptrace(PTRACE_TRACEME, pid, NULL, NULL);
raise(SIGSTOP);
return execve(argv[1], &argv[1], NULL);
} else {
wait(&status);
ptrace(PTRACE_SETOPTIONS, pid, 0, PTRACE_O_EXITKILL | PTRACE_O_TRACEEXEC | PTRACE_O_TRACESECCOMP);
while (1) {
if (wait_for_syscall(pid) != 0) break;
if (status >> 8 == (SIGTRAP | (PTRACE_EVENT_EXEC << 8)))
counter++;
if (status >> 8 == (SIGTRAP | (PTRACE_EVENT_SECCOMP << 8)))
counter++;
if (wait_for_syscall(pid) != 0) break;
}
}
return 0;
}
In your primary loop, you use a status
that is scoped to main
.
This is not the same status
you are setting in wait_for_syscall
(which has its own private copy of status
).
So, the status
in main
is never updated.
To fix, you can pass a pointer to wait_for_syscall
I've left it as is, but I believe that the second call to wait_for_syscall
in the loop is extraneous and may actually silently absorb a syscall.
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
int
wait_for_syscall(pid_t child,int *stp)
{
int status;
while (1) {
ptrace(PTRACE_CONT, child, 0, 0);
waitpid(child, &status, 0);
*stp = status;
if (WIFSTOPPED(status) && WSTOPSIG(status) | 0x80)
return 0;
if (WIFEXITED(status))
return 1;
}
}
int
main(int argc, char *argv[])
{
int status;
int counter = 0;
pid_t pid = fork();
if (pid < 0)
exit(1);
if (pid == 0) {
ptrace(PTRACE_TRACEME, pid, NULL, NULL);
raise(SIGSTOP);
return execve(argv[1], &argv[1], NULL);
}
wait(&status);
ptrace(PTRACE_SETOPTIONS, pid, 0, PTRACE_O_EXITKILL | PTRACE_O_TRACEEXEC | PTRACE_O_TRACESECCOMP | PTRACE_O_TRACECLONE);
while (1) {
if (wait_for_syscall(pid,&status) != 0)
break;
if (status >> 8 == (SIGTRAP | (PTRACE_EVENT_EXEC << 8)))
counter++;
if (status >> 8 == (SIGTRAP | (PTRACE_EVENT_SECCOMP << 8)))
counter++;
if (status >> 8 == (SIGTRAP | (PTRACE_EVENT_CLONE << 8)))
counter++;
if (wait_for_syscall(pid,&status) != 0)
break;
}
return 0;
}
UPDATE:
I see. Its close bc now it only does one iteration in the while then it stops. So it doesnt continue/go to the next systemcall. :( – Olivia22
Okay, I've played with some variations a bit. Here's some changes:
PTRACE_O_TRACEFORK
is needed in addition to PTRACE_O_TRACECLONE
(this is a big deal ;-)
Use execvp
to preserve environment variables (e.g. PATH
)
waitpid
should get -1
for pid to catch subchildren, etc.
I added debug printing (dbgprt
)
Added signo
to the ptrace(PTRACE_CONT,...)
Here's the refactored code (with lots of debug):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#define SHOW(_sym) \
dbgprt(#_sym ": %8.8X %8.8X\n",_sym,SIGTRAP | (_sym << 8))
#define dbgprt(_fmt...) \
do { \
int sverr = errno; \
printf(_fmt); \
errno = sverr; \
} while (0)
#define ONERR(_expr) \
do { \
if (! (_expr)) \
break; \
dbgprt("ONERR " #_expr " line %d -- %s\n",__LINE__,strerror(errno)); \
exit(1); \
} while (0)
int
main(int argc, char *argv[])
{
int status;
int counter = 0;
long err;
pid_t pidm = getpid();
pid_t pid0 = fork();
if (pid0 < 0)
exit(1);
if (pid0 == 0) {
ptrace(PTRACE_TRACEME, pid0, NULL, NULL);
//raise(SIGSTOP);
#if 0
execve(argv[1], &argv[1], NULL);
#else
execvp(argv[1], &argv[1]);
#endif
exit(97);
}
dbgprt("main: pid0=%d/%d\n",pid0,pid0 - pidm);
dbgprt("main: SIGSTOP %d\n",SIGSTOP);
dbgprt("main: SIGTRAP %d\n",SIGTRAP);
SHOW(PTRACE_EVENT_EXEC);
SHOW(PTRACE_EVENT_SECCOMP);
SHOW(PTRACE_EVENT_CLONE);
#if 0
err = ptrace(PTRACE_ATTACH,pid0,0,0);
ONERR(err < 0);
#endif
err = waitpid(-1,&status,0);
ONERR(err < 0);
#if 1
unsigned int opt = 0;
opt |= PTRACE_O_EXITKILL;
opt |= PTRACE_O_TRACEEXEC;
opt |= PTRACE_O_TRACESECCOMP;
opt |= PTRACE_O_TRACECLONE;
opt |= PTRACE_O_TRACEFORK;
err = ptrace(PTRACE_SETOPTIONS, pid0, 0, opt);
ONERR(err < 0);
#endif
err = ptrace(PTRACE_CONT,pid0,0,0);
ONERR(err < 0);
while (1) {
#if 1
pid_t pid = waitpid(-1, &status, 0);
#else
pid_t pid = wait(&status);
#endif
unsigned int evmsk = status >> 16;
dbgprt("waitpid: pid=%d/%d status=%8.8X\n",pid,pid - pidm,status);
dbgprt("waitpid: status %8.8X %8.8X evmsk=%8.8X\n",
status >> 8,status & 0x7F,evmsk);
if (pid < 0) {
dbgprt("waitpid: errno=%d -- %s\n",errno,strerror(errno));
break;
}
if (WIFEXITED(status)) {
dbgprt("waitpid: WIFEXITED code=%d\n",WEXITSTATUS(status));
continue;
}
int signo = 0;
do {
if (WIFSTOPPED(status)) {
signo = WSTOPSIG(status);
dbgprt("waitpid: WIFSTOPPED signo=%d\n",signo);
}
if (WIFSIGNALED(status)) {
signo = WTERMSIG(status);
dbgprt("waitpid: WIFSIGNALED signo=%d\n",signo);
}
} while (0);
#if 0
if (WIFSTOPPED(status) && WSTOPSIG(status) | 0x80)
return 0;
if (WIFEXITED(status))
return 1;
#endif
if (status >> 8 == (SIGTRAP | (PTRACE_EVENT_EXEC << 8))) {
dbgprt("EXEC\n");
counter++;
}
if (status >> 8 == (SIGTRAP | (PTRACE_EVENT_SECCOMP << 8))) {
dbgprt("SECCOMP\n");
counter++;
}
if (status >> 8 == (SIGTRAP | (PTRACE_EVENT_CLONE << 8))) {
dbgprt("CLONE\n");
counter++;
}
dbgprt("main: counter=%d\n",counter);
err = ptrace(PTRACE_CONT, pid, 0, signo);
ONERR(err < 0);
}
return 0;
}
Here's the program invocation and output:
+ ./fix3 /bin/bash -c 'cat /bin/bash | wc -c'
main: pid0=1905216/1
main: SIGSTOP 19
main: SIGTRAP 5
PTRACE_EVENT_EXEC: 00000004 00000405
PTRACE_EVENT_SECCOMP: 00000007 00000705
PTRACE_EVENT_CLONE: 00000003 00000305
waitpid: pid=1905216/1 status=0001057F
waitpid: status 00000105 0000007F evmsk=00000001
waitpid: WIFSTOPPED signo=5
main: counter=0
waitpid: pid=1905217/2 status=0000137F
waitpid: status 00000013 0000007F evmsk=00000000
waitpid: WIFSTOPPED signo=19
main: counter=0
waitpid: pid=1905217/2 status=0000137F
waitpid: status 00000013 0000007F evmsk=00000000
waitpid: WIFSTOPPED signo=19
main: counter=0
waitpid: pid=1905216/1 status=0000117F
waitpid: status 00000011 0000007F evmsk=00000000
waitpid: WIFSTOPPED signo=17
main: counter=0
waitpid: pid=1905217/2 status=00000000
waitpid: status 00000000 00000000 evmsk=00000000
waitpid: WIFEXITED code=0
waitpid: pid=1905216/1 status=0000117F
waitpid: status 00000011 0000007F evmsk=00000000
waitpid: WIFSTOPPED signo=17
main: counter=0
waitpid: pid=1905216/1 status=0001057F
waitpid: status 00000105 0000007F evmsk=00000001
waitpid: WIFSTOPPED signo=5
main: counter=0
waitpid: pid=1905218/3 status=0000137F
waitpid: status 00000013 0000007F evmsk=00000000
waitpid: WIFSTOPPED signo=19
main: counter=0
waitpid: pid=1905218/3 status=0000137F
waitpid: status 00000013 0000007F evmsk=00000000
waitpid: WIFSTOPPED signo=19
main: counter=0
waitpid: pid=1905216/1 status=0000117F
waitpid: status 00000011 0000007F evmsk=00000000
waitpid: WIFSTOPPED signo=17
main: counter=0
waitpid: pid=1905218/3 status=00000000
waitpid: status 00000000 00000000 evmsk=00000000
waitpid: WIFEXITED code=0
waitpid: pid=1905216/1 status=0000117F
waitpid: status 00000011 0000007F evmsk=00000000
waitpid: WIFSTOPPED signo=17
main: counter=0
waitpid: pid=1905216/1 status=0001057F
waitpid: status 00000105 0000007F evmsk=00000001
waitpid: WIFSTOPPED signo=5
main: counter=0
waitpid: pid=1905219/4 status=0000137F
waitpid: status 00000013 0000007F evmsk=00000000
waitpid: WIFSTOPPED signo=19
main: counter=0
waitpid: pid=1905219/4 status=0000137F
waitpid: status 00000013 0000007F evmsk=00000000
waitpid: WIFSTOPPED signo=19
main: counter=0
waitpid: pid=1905216/1 status=0000117F
waitpid: status 00000011 0000007F evmsk=00000000
waitpid: WIFSTOPPED signo=17
main: counter=0
waitpid: pid=1905220/5 status=0000137F
waitpid: status 00000013 0000007F evmsk=00000000
waitpid: WIFSTOPPED signo=19
main: counter=0
waitpid: pid=1905219/4 status=0001057F
waitpid: status 00000105 0000007F evmsk=00000001
waitpid: WIFSTOPPED signo=5
main: counter=0
waitpid: pid=1905220/5 status=0000137F
waitpid: status 00000013 0000007F evmsk=00000000
waitpid: WIFSTOPPED signo=19
main: counter=0
waitpid: pid=1905219/4 status=0000117F
waitpid: status 00000011 0000007F evmsk=00000000
waitpid: WIFSTOPPED signo=17
main: counter=0
waitpid: pid=1905220/5 status=0004057F
waitpid: status 00000405 0000007F evmsk=00000004
waitpid: WIFSTOPPED signo=5
EXEC
main: counter=1
waitpid: pid=1905220/5 status=00000000
waitpid: status 00000000 00000000 evmsk=00000000
waitpid: WIFEXITED code=0
waitpid: pid=1905219/4 status=0000117F
waitpid: status 00000011 0000007F evmsk=00000000
waitpid: WIFSTOPPED signo=17
main: counter=1
waitpid: pid=1905219/4 status=00000000
waitpid: status 00000000 00000000 evmsk=00000000
waitpid: WIFEXITED code=0
waitpid: pid=1905216/1 status=0000117F
waitpid: status 00000011 0000007F evmsk=00000000
waitpid: WIFSTOPPED signo=17
main: counter=1
waitpid: pid=1905216/1 status=0001057F
waitpid: status 00000105 0000007F evmsk=00000001
waitpid: WIFSTOPPED signo=5
main: counter=1
waitpid: pid=1905221/6 status=0000137F
waitpid: status 00000013 0000007F evmsk=00000000
waitpid: WIFSTOPPED signo=19
main: counter=1
waitpid: pid=1905221/6 status=0000137F
waitpid: status 00000013 0000007F evmsk=00000000
waitpid: WIFSTOPPED signo=19
main: counter=1
waitpid: pid=1905216/1 status=0000117F
waitpid: status 00000011 0000007F evmsk=00000000
waitpid: WIFSTOPPED signo=17
main: counter=1
waitpid: pid=1905221/6 status=0001057F
waitpid: status 00000105 0000007F evmsk=00000001
waitpid: WIFSTOPPED signo=5
main: counter=1
waitpid: pid=191190216
05222/7 status=0000137F
waitpid: status 00000013 0000007F evmsk=00000000
waitpid: WIFSTOPPED signo=19
main: counter=1
waitpid: pid=1905222/7 status=0000137F
waitpid: status 00000013 0000007F evmsk=00000000
waitpid: WIFSTOPPED signo=19
main: counter=1
waitpid: pid=1905221/6 status=0000117F
waitpid: status 00000011 0000007F evmsk=00000000
waitpid: WIFSTOPPED signo=17
main: counter=1
waitpid: pid=1905222/7 status=0004057F
waitpid: status 00000405 0000007F evmsk=00000004
waitpid: WIFSTOPPED signo=5
EXEC
main: counter=2
waitpid: pid=1905222/7 status=00000000
waitpid: status 00000000 00000000 evmsk=00000000
waitpid: WIFEXITED code=0
waitpid: pid=1905221/6 status=0000117F
waitpid: status 00000011 0000007F evmsk=00000000
waitpid: WIFSTOPPED signo=17
main: counter=2
waitpid: pid=1905221/6 status=00000000
waitpid: status 00000000 00000000 evmsk=00000000
waitpid: WIFEXITED code=0
waitpid: pid=1905216/1 status=0000117F
waitpid: status 00000011 0000007F evmsk=00000000
waitpid: WIFSTOPPED signo=17
main: counter=2
waitpid: pid=1905216/1 status=0001057F
waitpid: status 00000105 0000007F evmsk=00000001
waitpid: WIFSTOPPED signo=5
main: counter=2
waitpid: pid=1905223/8 status=0000137F
waitpid: status 00000013 0000007F evmsk=00000000
waitpid: WIFSTOPPED signo=19
main: counter=2
waitpid: pid=1905223/8 status=0000137F
waitpid: status 00000013 0000007F evmsk=00000000
waitpid: WIFSTOPPED signo=19
main: counter=2
waitpid: pid=1905216/1 status=0001057F
waitpid: status 00000105 0000007F evmsk=00000001
waitpid: WIFSTOPPED signo=5
main: counter=2
waitpid: pid=1905224/9 status=0000137F
waitpid: status 00000013 0000007F evmsk=00000000
waitpid: WIFSTOPPED signo=19
main: counter=2
waitpid: pid=1905224/9 status=0000137F
waitpid: status 00000013 0000007F evmsk=00000000
waitpid: WIFSTOPPED signo=19
main: counter=2
waitpid: pid=1905223/8 status=0004057F
waitpid: status 00000405 0000007F evmsk=00000004
waitpid: WIFSTOPPED signo=5
EXEC
main: counter=3
waitpid: pid=1905224/9 status=0004057F
waitpid: status 00000405 0000007F evmsk=00000004
waitpid: WIFSTOPPED signo=5
EXEC
main: counter=4
waitpid: pid=1905223/8 status=00000000
waitpid: status 00000000 00000000 evmsk=00000000
waitpid: WIFEXITED code=0
waitpid: pid=1905224/9 status=00000000
waitpid: status 00000000 00000000 evmsk=00000000
waitpid: WIFEXITED code=0
waitpid: pid=1905216/1 status=0000117F
waitpid: status 00000011 0000007F evmsk=00000000
waitpid: WIFSTOPPED signo=17
main: counter=4
waitpid: pid=1905216/1 status=00000000
waitpid: status 00000000 00000000 evmsk=00000000
waitpid: WIFEXITED code=0
waitpid: pid=-1/-1905216 status=00000000
waitpid: status 00000000 00000000 evmsk=00000000
waitpid: errno=10 -- No child processes
UPDATE #2:
Thanks alot, Ill go study it and see how it works. Just one thing what does if 0 and if 1 mean here? – Olivia22
For illustration here, I use cpp
conditionals to denote old vs. new code:
#if 0
// old code
#else
// new code
#endif
#if 1
// new code
#endif
Sometimes, I'll put in some experimental code, but it will turn out to be "not so good". So, I'll wrap it in a #if 0
. I'll keep it for a while to remind myself that I did it and it didn't work (e.g. the PTRACE_ATTACH
block).
The conditionals are quick way to "comment out" code that is cleaner than using (e.g.) a /*
and */
pair.
When I'm done and I think the code is final, I'll remove the conditionals as appropriate.
An easy way to do this is to run the code through unifdef -k
(and we get):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#define SHOW(_sym) \
dbgprt(#_sym ": %8.8X %8.8X\n",_sym,SIGTRAP | (_sym << 8))
#define dbgprt(_fmt...) \
do { \
int sverr = errno; \
printf(_fmt); \
errno = sverr; \
} while (0)
#define ONERR(_expr) \
do { \
if (! (_expr)) \
break; \
dbgprt("ONERR " #_expr " line %d -- %s\n",__LINE__,strerror(errno)); \
exit(1); \
} while (0)
int
main(int argc, char *argv[])
{
int status;
int counter = 0;
long err;
pid_t pidm = getpid();
pid_t pid0 = fork();
if (pid0 < 0)
exit(1);
if (pid0 == 0) {
ptrace(PTRACE_TRACEME, pid0, NULL, NULL);
//raise(SIGSTOP);
execvp(argv[1], &argv[1]);
exit(97);
}
dbgprt("main: pid0=%d/%d\n",pid0,pid0 - pidm);
dbgprt("main: SIGSTOP %d\n",SIGSTOP);
dbgprt("main: SIGTRAP %d\n",SIGTRAP);
SHOW(PTRACE_EVENT_EXEC);
SHOW(PTRACE_EVENT_SECCOMP);
SHOW(PTRACE_EVENT_CLONE);
err = waitpid(-1,&status,0);
ONERR(err < 0);
unsigned int opt = 0;
opt |= PTRACE_O_EXITKILL;
opt |= PTRACE_O_TRACEEXEC;
opt |= PTRACE_O_TRACESECCOMP;
opt |= PTRACE_O_TRACECLONE;
opt |= PTRACE_O_TRACEFORK;
err = ptrace(PTRACE_SETOPTIONS, pid0, 0, opt);
ONERR(err < 0);
err = ptrace(PTRACE_CONT,pid0,0,0);
ONERR(err < 0);
while (1) {
pid_t pid = waitpid(-1, &status, 0);
unsigned int evmsk = status >> 16;
dbgprt("waitpid: pid=%d/%d status=%8.8X\n",pid,pid - pidm,status);
dbgprt("waitpid: status %8.8X %8.8X evmsk=%8.8X\n",
status >> 8,status & 0x7F,evmsk);
if (pid < 0) {
dbgprt("waitpid: errno=%d -- %s\n",errno,strerror(errno));
break;
}
if (WIFEXITED(status)) {
dbgprt("waitpid: WIFEXITED code=%d\n",WEXITSTATUS(status));
continue;
}
int signo = 0;
do {
if (WIFSTOPPED(status)) {
signo = WSTOPSIG(status);
dbgprt("waitpid: WIFSTOPPED signo=%d\n",signo);
}
if (WIFSIGNALED(status)) {
signo = WTERMSIG(status);
dbgprt("waitpid: WIFSIGNALED signo=%d\n",signo);
}
} while (0);
if (status >> 8 == (SIGTRAP | (PTRACE_EVENT_EXEC << 8))) {
dbgprt("EXEC\n");
counter++;
}
if (status >> 8 == (SIGTRAP | (PTRACE_EVENT_SECCOMP << 8))) {
dbgprt("SECCOMP\n");
counter++;
}
if (status >> 8 == (SIGTRAP | (PTRACE_EVENT_CLONE << 8))) {
dbgprt("CLONE\n");
counter++;
}
dbgprt("main: counter=%d\n",counter);
err = ptrace(PTRACE_CONT, pid, 0, signo);
ONERR(err < 0);
}
return 0;
}