From 25e40facc12017de2c4df5792f6a0a3f7db39896 Mon Sep 17 00:00:00 2001 From: Eugene Syromyatnikov Date: Tue, 29 Jan 2019 14:40:11 +0100 Subject: [PATCH 18/27] Use accessors for tcp->s_ent, return a stub struct if it is NULL Since code paths are non-trivial, it's an attempt to future-proof and prevent improper access of tcp->s_ent fields. * defs.h (struct tcb): Update the description of s_ent field. (stub_sysent): New declaration. (tcp_sysent, n_args): New macro functions. (indirect_ipccall): Use tcp_sysent() instead of tcp->s_ent. * ipc.c (SYS_FUNC(ipc)): Use n_args() instead of tcp->s_ent->nargs. * linux/alpha/get_syscall_args.c (get_syscall_args): Likewise. * linux/bfin/get_syscall_args.c (get_syscall_args): Likewise. * linux/hppa/get_syscall_args.c (get_syscall_args): Likewise. * linux/ia64/get_syscall_args.c (get_syscall_args): Likewise. * linux/microblaze/get_syscall_args.c (get_syscall_args): Likewise. * linux/mips/get_syscall_args.c (get_syscall_args): Likewise. * linux/sh/get_syscall_args.c (get_syscall_args): Likewise. * linux/sh64/get_syscall_args.c (get_syscall_args): Likewise. * linux/x86_64/get_syscall_args.c (get_syscall_args): Likewise. * linux/xtensa/get_syscall_args.c (get_syscall_args): Likewise. * prctl.c (print_prctl_args): Likewise. * signal.c (SYS_FUNC(sgetmask)): Likewise. * util.c (printargs, printargs_u, printargs_d): Likewise. * syscall.c (decode_ipc_subcall, decode_syscall_subcall: Likewise. (dumpio, tamper_with_syscall_exiting, syscall_entering_decode, syscall_entering_decode, syscall_entering_trace, syscall_entering_trace, syscall_exiting_decode, print_syscall_resume, syscall_exiting_trace, get_syscall_result): Use tcp_sysent() instead of tcp->s_ent. (stub_sysent): New stub sysent. (get_scno): Reset scno, s_ent, qual_flg; initialise s->ent from stub_sysent. * pathtrace.c (pathtrace_match_set): Use tcp_sysent() instead of tcp->s_ent. Co-Authored-by: Dmitry V. Levin Conflicts: defs.h linux/mips/get_syscall_args.c syscall.c --- defs.h | 10 ++++++-- ipc.c | 2 +- linux/alpha/get_syscall_args.c | 2 +- linux/bfin/get_syscall_args.c | 2 +- linux/hppa/get_syscall_args.c | 2 +- linux/ia64/get_syscall_args.c | 2 +- linux/microblaze/get_syscall_args.c | 2 +- linux/mips/get_syscall_args.c | 6 ++--- linux/sh/get_syscall_args.c | 2 +- linux/sh64/get_syscall_args.c | 2 +- linux/x86_64/get_syscall_args.c | 2 +- linux/xtensa/get_syscall_args.c | 2 +- pathtrace.c | 2 +- prctl.c | 2 +- signal.c | 4 +-- syscall.c | 49 +++++++++++++++++++++---------------- util.c | 6 ++--- 17 files changed, 56 insertions(+), 43 deletions(-) diff --git a/defs.h b/defs.h index c7274c8..811bb0d 100644 --- a/defs.h +++ b/defs.h @@ -206,7 +206,9 @@ struct tcb { const char *auxstr; /* Auxiliary info from syscall (see RVAL_STR) */ void *_priv_data; /* Private data for syscall decoding functions */ void (*_free_priv_data)(void *); /* Callback for freeing priv_data */ - const struct_sysent *s_ent; /* sysent[scno] or dummy struct for bad scno */ + const struct_sysent *s_ent; /* sysent[scno] or a stub struct for bad + * scno. Use tcp_sysent() macro for access. + */ const struct_sysent *s_prev_ent; /* for "resuming interrupted SYSCALL" msg */ struct inject_opts *inject_vec[SUPPORTED_PERSONALITIES]; struct timespec stime; /* System time usage as of last process wait */ @@ -283,6 +285,10 @@ struct tcb { #define syscall_delayed(tcp) ((tcp)->flags & TCB_DELAYED) #define syscall_tampered_nofail(tcp) ((tcp)->flags & TCB_TAMPERED_NO_FAIL) +extern const struct_sysent stub_sysent; +#define tcp_sysent(tcp) (tcp->s_ent ?: &stub_sysent) +#define n_args(tcp) (tcp_sysent(tcp)->nargs) + #include "xlat.h" extern const struct xlat addrfams[]; @@ -352,7 +358,7 @@ extern const struct xlat whence_codes[]; #define IOCTL_NUMBER_HANDLED 1 #define IOCTL_NUMBER_STOP_LOOKUP 010 -#define indirect_ipccall(tcp) (tcp->s_ent->sys_flags & TRACE_INDIRECT_SUBCALL) +#define indirect_ipccall(tcp) (tcp_sysent(tcp)->sys_flags & TRACE_INDIRECT_SUBCALL) enum sock_proto { SOCK_PROTO_UNKNOWN, diff --git a/ipc.c b/ipc.c index c35509b..b2b3aa4 100644 --- a/ipc.c +++ b/ipc.c @@ -21,7 +21,7 @@ SYS_FUNC(ipc) printxval_u(ipccalls, call, NULL); unsigned int i; - for (i = 1; i < tcp->s_ent->nargs; ++i) + for (i = 1; i < n_args(tcp); ++i) tprintf(", %#" PRI_klx, tcp->u_arg[i]); return RVAL_DECODED; diff --git a/linux/alpha/get_syscall_args.c b/linux/alpha/get_syscall_args.c index be61abf..c28eb62 100644 --- a/linux/alpha/get_syscall_args.c +++ b/linux/alpha/get_syscall_args.c @@ -4,7 +4,7 @@ get_syscall_args(struct tcb *tcp) { unsigned int i; - for (i = 0; i < tcp->s_ent->nargs; ++i) + for (i = 0; i < n_args(tcp); ++i) if (upeek(tcp, REG_A0+i, &tcp->u_arg[i]) < 0) return -1; return 1; diff --git a/linux/bfin/get_syscall_args.c b/linux/bfin/get_syscall_args.c index 506d3a9..bebaf03 100644 --- a/linux/bfin/get_syscall_args.c +++ b/linux/bfin/get_syscall_args.c @@ -7,7 +7,7 @@ get_syscall_args(struct tcb *tcp) }; unsigned int i; - for (i = 0; i < tcp->s_ent->nargs; ++i) + for (i = 0; i < n_args(tcp); ++i) if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0) return -1; return 1; diff --git a/linux/hppa/get_syscall_args.c b/linux/hppa/get_syscall_args.c index aa938f5..70f2a24 100644 --- a/linux/hppa/get_syscall_args.c +++ b/linux/hppa/get_syscall_args.c @@ -4,7 +4,7 @@ get_syscall_args(struct tcb *tcp) { unsigned int i; - for (i = 0; i < tcp->s_ent->nargs; ++i) + for (i = 0; i < n_args(tcp); ++i) if (upeek(tcp, PT_GR26-4*i, &tcp->u_arg[i]) < 0) return -1; return 1; diff --git a/linux/ia64/get_syscall_args.c b/linux/ia64/get_syscall_args.c index ad73c54..eeeb59c 100644 --- a/linux/ia64/get_syscall_args.c +++ b/linux/ia64/get_syscall_args.c @@ -11,7 +11,7 @@ get_syscall_args(struct tcb *tcp) unsigned long *out0 = ia64_rse_skip_regs(rbs_end, -sof + sol); unsigned int i; - for (i = 0; i < tcp->s_ent->nargs; ++i) { + for (i = 0; i < n_args(tcp); ++i) { if (umove(tcp, (unsigned long) ia64_rse_skip_regs(out0, i), &tcp->u_arg[i]) < 0) { diff --git a/linux/microblaze/get_syscall_args.c b/linux/microblaze/get_syscall_args.c index 1a3a48f..0e249e3 100644 --- a/linux/microblaze/get_syscall_args.c +++ b/linux/microblaze/get_syscall_args.c @@ -4,7 +4,7 @@ get_syscall_args(struct tcb *tcp) { unsigned int i; - for (i = 0; i < tcp->s_ent->nargs; ++i) + for (i = 0; i < n_args(tcp); ++i) if (upeek(tcp, (5 + i) * 4, &tcp->u_arg[i]) < 0) return -1; return 1; diff --git a/linux/mips/get_syscall_args.c b/linux/mips/get_syscall_args.c index 3c9160e..0ff5136 100644 --- a/linux/mips/get_syscall_args.c +++ b/linux/mips/get_syscall_args.c @@ -14,16 +14,16 @@ get_syscall_args(struct tcb *tcp) tcp->u_arg[1] = mips_REG_A1; tcp->u_arg[2] = mips_REG_A2; tcp->u_arg[3] = mips_REG_A3; - if (tcp->s_ent->nargs > 4 + if (n_args(tcp) > 4 && umoven(tcp, mips_REG_SP + 4 * sizeof(tcp->u_arg[0]), - (tcp->s_ent->nargs - 4) * sizeof(tcp->u_arg[0]), + (n_args(tcp) - 4) * sizeof(tcp->u_arg[0]), &tcp->u_arg[4]) < 0) { /* * Let's proceed with the first 4 arguments * instead of reporting the failure. */ memset(&tcp->u_arg[4], 0, - (tcp->s_ent->nargs - 4) * sizeof(tcp->u_arg[0])); + (n_args(tcp) - 4) * sizeof(tcp->u_arg[0])); } #else # error unsupported mips abi diff --git a/linux/sh/get_syscall_args.c b/linux/sh/get_syscall_args.c index b4ee1dd..02593b0 100644 --- a/linux/sh/get_syscall_args.c +++ b/linux/sh/get_syscall_args.c @@ -12,7 +12,7 @@ get_syscall_args(struct tcb *tcp) }; unsigned int i; - for (i = 0; i < tcp->s_ent->nargs; ++i) + for (i = 0; i < n_args(tcp); ++i) if (upeek(tcp, syscall_regs[i], &tcp->u_arg[i]) < 0) return -1; return 1; diff --git a/linux/sh64/get_syscall_args.c b/linux/sh64/get_syscall_args.c index e35c350..241ff09 100644 --- a/linux/sh64/get_syscall_args.c +++ b/linux/sh64/get_syscall_args.c @@ -6,7 +6,7 @@ get_syscall_args(struct tcb *tcp) static const int syscall_regs[MAX_ARGS] = { 2, 3, 4, 5, 6, 7 }; unsigned int i; - for (i = 0; i < tcp->s_ent->nargs; ++i) + for (i = 0; i < n_args(tcp); ++i) if (upeek(tcp, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0) return -1; diff --git a/linux/x86_64/get_syscall_args.c b/linux/x86_64/get_syscall_args.c index f285ac3..8ee8ebd 100644 --- a/linux/x86_64/get_syscall_args.c +++ b/linux/x86_64/get_syscall_args.c @@ -4,7 +4,7 @@ get_syscall_args(struct tcb *tcp) { if (x86_io.iov_len != sizeof(i386_regs)) { /* x86-64 or x32 ABI */ - if (tcp->s_ent->sys_flags & COMPAT_SYSCALL_TYPES) { + if (tcp_sysent(tcp)->sys_flags & COMPAT_SYSCALL_TYPES) { /* * X32 compat syscall: zero-extend from 32 bits. * Use truncate_klong_to_current_wordsize(tcp->u_arg[N]) diff --git a/linux/xtensa/get_syscall_args.c b/linux/xtensa/get_syscall_args.c index 2a20cdb..6903221 100644 --- a/linux/xtensa/get_syscall_args.c +++ b/linux/xtensa/get_syscall_args.c @@ -13,7 +13,7 @@ get_syscall_args(struct tcb *tcp) }; unsigned int i; - for (i = 0; i < tcp->s_ent->nargs; ++i) + for (i = 0; i < n_args(tcp); ++i) if (upeek(tcp, xtensaregs[i], &tcp->u_arg[i]) < 0) return -1; return 1; diff --git a/pathtrace.c b/pathtrace.c index 2cd12e6..5493028 100644 --- a/pathtrace.c +++ b/pathtrace.c @@ -167,7 +167,7 @@ pathtrace_match_set(struct tcb *tcp, struct path_set *set) { const struct_sysent *s; - s = tcp->s_ent; + s = tcp_sysent(tcp); if (!(s->sys_flags & (TRACE_FILE | TRACE_DESC | TRACE_NETWORK))) return false; diff --git a/prctl.c b/prctl.c index 5830f11..c31ea60 100644 --- a/prctl.c +++ b/prctl.c @@ -61,7 +61,7 @@ print_prctl_args(struct tcb *tcp, const unsigned int first) { unsigned int i; - for (i = first; i < tcp->s_ent->nargs; ++i) + for (i = first; i < n_args(tcp); ++i) tprintf(", %#" PRI_klx, tcp->u_arg[i]); } diff --git a/signal.c b/signal.c index 17a3f79..e59a76d 100644 --- a/signal.c +++ b/signal.c @@ -383,10 +383,10 @@ SYS_FUNC(sgetmask) SYS_FUNC(sigsuspend) { #ifdef MIPS - print_sigset_addr_len(tcp, tcp->u_arg[tcp->s_ent->nargs - 1], + print_sigset_addr_len(tcp, tcp->u_arg[n_args(tcp) - 1], current_wordsize); #else - tprint_old_sigmask_val("", tcp->u_arg[tcp->s_ent->nargs - 1]); + tprint_old_sigmask_val("", tcp->u_arg[n_args(tcp) - 1]); #endif return RVAL_DECODED; diff --git a/syscall.c b/syscall.c index 33f6dcd..40fcedb 100644 --- a/syscall.c +++ b/syscall.c @@ -339,7 +339,7 @@ decode_ipc_subcall(struct tcb *tcp) tcp->qual_flg = qual_flags(tcp->scno); tcp->s_ent = &sysent[tcp->scno]; - const unsigned int n = tcp->s_ent->nargs; + const unsigned int n = n_args(tcp); unsigned int i; for (i = 0; i < n; i++) tcp->u_arg[i] = tcp->u_arg[i + 1]; @@ -363,7 +363,7 @@ decode_syscall_subcall(struct tcb *tcp) * and sync_file_range) requires additional code, * see linux/mips/get_syscall_args.c */ - if (tcp->s_ent->nargs == MAX_ARGS) { + if (n_args(tcp) == MAX_ARGS) { if (umoven(tcp, mips_REG_SP + MAX_ARGS * sizeof(tcp->u_arg[0]), sizeof(tcp->u_arg[0]), @@ -382,7 +382,7 @@ dumpio(struct tcb *tcp) return; if (is_number_in_set(fd, write_set)) { - switch (tcp->s_ent->sen) { + switch (tcp_sysent(tcp)->sen) { case SEN_write: case SEN_pwrite: case SEN_send: @@ -409,7 +409,7 @@ dumpio(struct tcb *tcp) return; if (is_number_in_set(fd, read_set)) { - switch (tcp->s_ent->sen) { + switch (tcp_sysent(tcp)->sen) { case SEN_read: case SEN_pread: case SEN_recv: @@ -573,7 +573,7 @@ tamper_with_syscall_exiting(struct tcb *tcp) if (update_tcb) { tcp->u_error = 0; - get_error(tcp, !(tcp->s_ent->sys_flags & SYSCALL_NEVER_FAILS)); + get_error(tcp, !(tcp_sysent(tcp)->sys_flags & SYSCALL_NEVER_FAILS)); } return 0; @@ -593,10 +593,9 @@ syscall_entering_decode(struct tcb *tcp) int res = get_scno(tcp); if (res == 0) return res; - int scno_good = res; if (res != 1 || (res = get_syscall_args(tcp)) != 1) { printleader(tcp); - tprintf("%s(", scno_good == 1 ? tcp->s_ent->sys_name : "????"); + tprintf("%s(", tcp_sysent(tcp)->sys_name); /* * " " will be added later by the code which * detects ptrace errors. @@ -608,7 +607,7 @@ syscall_entering_decode(struct tcb *tcp) || defined SYS_socket_subcall \ || defined SYS_syscall_subcall for (;;) { - switch (tcp->s_ent->sen) { + switch (tcp_sysent(tcp)->sen) { # ifdef SYS_ipc_subcall case SEN_ipc: decode_ipc_subcall(tcp); @@ -622,7 +621,7 @@ syscall_entering_decode(struct tcb *tcp) # ifdef SYS_syscall_subcall case SEN_syscall: decode_syscall_subcall(tcp); - if (tcp->s_ent->sen != SEN_syscall) + if (tcp_sysent(tcp)->sen != SEN_syscall) continue; break; # endif @@ -642,7 +641,7 @@ syscall_entering_trace(struct tcb *tcp, unsigned int *sig) tcp->qual_flg &= ~QUAL_INJECT; } - switch (tcp->s_ent->sen) { + switch (tcp_sysent(tcp)->sen) { case SEN_execve: case SEN_execveat: #if defined SPARC || defined SPARC64 @@ -672,14 +671,14 @@ syscall_entering_trace(struct tcb *tcp, unsigned int *sig) #ifdef ENABLE_STACKTRACE if (stack_trace_enabled) { - if (tcp->s_ent->sys_flags & STACKTRACE_CAPTURE_ON_ENTER) + if (tcp_sysent(tcp)->sys_flags & STACKTRACE_CAPTURE_ON_ENTER) unwind_tcb_capture(tcp); } #endif printleader(tcp); - tprintf("%s(", tcp->s_ent->sys_name); - int res = raw(tcp) ? printargs(tcp) : tcp->s_ent->sys_func(tcp); + tprintf("%s(", tcp_sysent(tcp)->sys_name); + int res = raw(tcp) ? printargs(tcp) : tcp_sysent(tcp)->sys_func(tcp); fflush(tcp->outf); return res; } @@ -709,7 +708,7 @@ syscall_exiting_decode(struct tcb *tcp, struct timespec *pts) if ((Tflag || cflag) && !(filtered(tcp) || hide_log(tcp))) clock_gettime(CLOCK_MONOTONIC, pts); - if (tcp->s_ent->sys_flags & MEMORY_MAPPING_CHANGE) + if (tcp_sysent(tcp)->sys_flags & MEMORY_MAPPING_CHANGE) mmap_notify_report(tcp); if (filtered(tcp) || hide_log(tcp)) @@ -738,7 +737,7 @@ print_syscall_resume(struct tcb *tcp) || (tcp->flags & TCB_REPRINT)) { tcp->flags &= ~TCB_REPRINT; printleader(tcp); - tprintf("<... %s resumed>", tcp->s_ent->sys_name); + tprintf("<... %s resumed>", tcp_sysent(tcp)->sys_name); } } @@ -786,7 +785,7 @@ syscall_exiting_trace(struct tcb *tcp, struct timespec *ts, int res) if (tcp->sys_func_rval & RVAL_DECODED) sys_res = tcp->sys_func_rval; else - sys_res = tcp->s_ent->sys_func(tcp); + sys_res = tcp_sysent(tcp)->sys_func(tcp); } tprints(") "); @@ -1175,6 +1174,13 @@ free_sysent_buf(void *ptr) free(ptr); } +const struct_sysent stub_sysent = { + .nargs = MAX_ARGS, + .sen = SEN_printargs, + .sys_func = printargs, + .sys_name = "????", +}; + /* * Returns: * 0: "ignore this ptrace stop", syscall_entering_decode() should return a "bail @@ -1186,6 +1192,10 @@ free_sysent_buf(void *ptr) int get_scno(struct tcb *tcp) { + tcp->scno = -1; + tcp->s_ent = NULL; + tcp->qual_flg = QUAL_RAW | DEFAULT_QUAL_FLAGS; + if (get_regs(tcp) < 0) return -1; @@ -1202,14 +1212,11 @@ get_scno(struct tcb *tcp) struct sysent_buf *s = xcalloc(1, sizeof(*s)); s->tcp = tcp; - s->ent.nargs = MAX_ARGS; - s->ent.sen = SEN_printargs; - s->ent.sys_func = printargs; + s->ent = stub_sysent; s->ent.sys_name = s->buf; xsprintf(s->buf, "syscall_%#" PRI_klx, shuffle_scno(tcp->scno)); tcp->s_ent = &s->ent; - tcp->qual_flg = QUAL_RAW | DEFAULT_QUAL_FLAGS; set_tcb_priv_data(tcp, s, free_sysent_buf); @@ -1246,7 +1253,7 @@ get_syscall_result(struct tcb *tcp) return -1; tcp->u_error = 0; get_error(tcp, - (!(tcp->s_ent->sys_flags & SYSCALL_NEVER_FAILS) + (!(tcp_sysent(tcp)->sys_flags & SYSCALL_NEVER_FAILS) || syscall_tampered(tcp)) && !syscall_tampered_nofail(tcp)); diff --git a/util.c b/util.c index aefedee..b841c0f 100644 --- a/util.c +++ b/util.c @@ -1161,7 +1161,7 @@ print_array_ex(struct tcb *const tcp, int printargs(struct tcb *tcp) { - const int n = tcp->s_ent->nargs; + const int n = n_args(tcp); int i; for (i = 0; i < n; ++i) tprintf("%s%#" PRI_klx, i ? ", " : "", tcp->u_arg[i]); @@ -1171,7 +1171,7 @@ printargs(struct tcb *tcp) int printargs_u(struct tcb *tcp) { - const int n = tcp->s_ent->nargs; + const int n = n_args(tcp); int i; for (i = 0; i < n; ++i) tprintf("%s%u", i ? ", " : "", @@ -1182,7 +1182,7 @@ printargs_u(struct tcb *tcp) int printargs_d(struct tcb *tcp) { - const int n = tcp->s_ent->nargs; + const int n = n_args(tcp); int i; for (i = 0; i < n; ++i) tprintf("%s%d", i ? ", " : "", -- 2.1.4