commit: a9bc1a93890ac28224fd423a2f0cc580108c7ddd
parent d707cec7daf1f8ce513cd751e9ea7936bd6f9347
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date: Tue, 8 Apr 2025 00:44:42 +0200
split between syscall entry and exit
This way in the case of syscalls like nanosleep(2) where values
get modified, we cleanly have both before and after.
Diffstat:
4 files changed, 73 insertions(+), 33 deletions(-)
diff --git a/mstrace.c b/mstrace.c
@@ -14,7 +14,8 @@
#include <sys/wait.h>
#include <unistd.h> // getpid, fork, execvp
-extern void print_syscall(__u64 nr, __u64 args[6]);
+extern void print_syscall_entry(__u64 nr, __u64 args[6]);
+extern void print_syscall_exit(__u64 nr, __u64 args[6]);
pid_t child = -1;
@@ -71,7 +72,6 @@ main(int argc, char *argv[])
return 1;
}
- bool neednl = false;
struct
{
__u64 nr;
@@ -106,17 +106,10 @@ main(int argc, char *argv[])
for(int i = 0; i < 6; i++)
entry.args[i] = syscall_info.entry.args[i];
- // print execve(2) at entry time because parameters passed gets cleaned up
- // meanwhile getcwd(2) pass a buffer and so needs to be printed at return time
- if(entry.nr == SYS_execve)
- {
- print_syscall(entry.nr, entry.args);
- neednl = true;
- }
-
+ print_syscall_entry(entry.nr, entry.args);
break;
case PTRACE_SYSCALL_INFO_EXIT:
- if(entry.nr != SYS_execve) print_syscall(entry.nr, entry.args);
+ if(entry.nr != SYS_execve) print_syscall_exit(entry.nr, entry.args);
if(syscall_info.exit.is_error)
{
@@ -129,32 +122,22 @@ main(int argc, char *argv[])
{
fprintf(stderr, " = %" PRIi64 "\n", (int64_t)syscall_info.exit.rval);
}
- neednl = false;
entry.nr = 0;
break;
case PTRACE_SYSCALL_INFO_SECCOMP:
- print_syscall(syscall_info.seccomp.nr, syscall_info.seccomp.args);
- neednl = true;
+ print_syscall_exit(syscall_info.seccomp.nr, syscall_info.seccomp.args);
// TODO: Check how strace manages this
fprintf(stderr, " [seccomp_ret = %" PRIu32 "]", syscall_info.seccomp.ret_data);
break;
case PTRACE_SYSCALL_INFO_NONE:
- if(neednl) fprintf(stderr, "\n");
-
fprintf(stderr, "[syscall-info] none\n");
- neednl = false;
break;
}
}
if(entry.nr != 0)
- {
- print_syscall(entry.nr, entry.args);
- neednl = true;
- }
-
- if(neednl) fprintf(stderr, "\n");
+ print_syscall_exit(entry.nr, entry.args);
if(WIFEXITED(status))
{
diff --git a/print_syscall.c b/print_syscall.c
@@ -18,6 +18,12 @@
extern pid_t child;
+union u8_timespec
+{
+ struct timespec ts;
+ uint8_t buf[sizeof(struct timespec)];
+};
+
static char *
read_str(intptr_t addr, size_t len)
{
@@ -44,6 +50,22 @@ read_str(intptr_t addr, size_t len)
return str_buf;
}
+static struct timespec *
+read_timespec(intptr_t addr)
+{
+ static union u8_timespec local;
+
+ for(size_t i = 0; i < sizeof(struct timespec);)
+ {
+ unsigned long tmp = ptrace(PTRACE_PEEKDATA, child, addr + i);
+
+ memcpy(local.buf + i, &tmp, sizeof(tmp));
+ i += sizeof(tmp);
+ }
+
+ return &(local.ts);
+}
+
#define Pri_str "\"%s\""
#define Pri_i "%" PRIi64
#define Pri_u "%" PRIu64
@@ -51,21 +73,62 @@ read_str(intptr_t addr, size_t len)
#define Pri_x "0x%" PRIx64
void
-print_syscall(__u64 nr, __u64 args[6])
+print_syscall_entry(__u64 nr, __u64 args[6])
+{
+ switch(nr)
+ {
+ case SYS_execve:
+ fprintf(stderr, "<%s("Pri_str ", " Pri_x ", " Pri_x ")\n", str_syscalls[nr], read_str(args[0], PATH_MAX), (int64_t)args[1], (int64_t)args[2]);
+ return;
+ case SYS_nanosleep:
+ {
+ struct timespec *rqtp = read_timespec(args[0]);
+ struct timespec *rmtp = read_timespec(args[1]);
+
+ fprintf(stderr,
+ "<%s({tv_sec = " Pri_i ", tv_nsec = " Pri_i "}, {tv_sec = " Pri_i ", tv_nsec = " Pri_i
+ "})\n",
+ str_syscalls[nr],
+ rqtp->tv_sec,
+ rqtp->tv_nsec,
+ rmtp->tv_sec,
+ rmtp->tv_nsec);
+ return;
+ }
+ }
+}
+
+void
+print_syscall_exit(__u64 nr, __u64 args[6])
{
switch(nr)
{
#include "syscalls_cases.h"
+ case SYS_nanosleep:
+ {
+ struct timespec *rqtp = read_timespec(args[0]);
+ struct timespec *rmtp = read_timespec(args[1]);
+
+ fprintf(stderr,
+ ">%s({tv_sec = " Pri_i ", tv_nsec = " Pri_i "}, {tv_sec = " Pri_i ", tv_nsec = " Pri_i
+ "})",
+ str_syscalls[nr],
+ rqtp->tv_sec,
+ rqtp->tv_nsec,
+ rmtp->tv_sec,
+ rmtp->tv_nsec);
+ break;
+ }
// fallback
default:
assert(nr < SYSCALLS_MAX);
if(str_syscalls[nr] != NULL)
{
- fprintf(stderr, "%s(", str_syscalls[nr]);
+ fprintf(stderr, ">%s(", str_syscalls[nr]);
}
else
{
- fprintf(stderr, "syscall(%" PRIu64 ", ", (uint64_t)nr);
+ fprintf(stderr, ">syscall(%" PRIu64 ", ", (uint64_t)nr);
}
fprintf(stderr,
diff --git a/syscalls.sh b/syscalls.sh
@@ -2,7 +2,7 @@
while read syscall args
do
- fmt='"%s("'
+ fmt='">%s("'
fmt_args='str_syscalls[nr]'
fmt_sep=''
@@ -40,10 +40,6 @@ do
fmt="${fmt}${fmt_sep}Pri_str"
fmt_args="${fmt_args}, read_str(args[$n], PATH_MAX)"
;;
- timespec)
- fmt="${fmt}${fmt_sep}\"{tv_sec=\"Pri_i\", tv_nsec=\"Pri_i\"}\""
- fmt_args="${fmt_args}, (int64_t)(((const struct timespec *)args[$n])->tv_sec), (int64_t)(((const struct timespec *)args[$n])->tv_nsec)"
- ;;
*)
echo "syscalls.sh: error: Unhandled type ${i}" >&2
exit 1
diff --git a/syscalls.txt b/syscalls.txt
@@ -29,7 +29,6 @@ close int
creat path oct
dup int
dup2 int int
-execve path hex hex
exit_group int
faccessat int path oct oct
fchmod int oct
@@ -65,4 +64,3 @@ unlink path
unlinkat int path
vfork
write int buf size
-nanosleep timespec timespec