From: Eugene Syromyatnikov Date: Tue, 29 Jan 2019 13:40:11 +0000 (+0100) Subject: Use accessors for tcp->s_ent, return a stub struct if it is NULL X-Git-Tag: v5.0~69 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=541efab92bacf817a8a96912e198cddf2396b6d3;p=strace 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 --- diff --git a/defs.h b/defs.h index 1f231d34..ca1c39cc 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 */ @@ -285,6 +287,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[]; @@ -355,7 +361,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 c35509bc..b2b3aa42 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 381d75e6..8bebfaa4 100644 --- a/linux/alpha/get_syscall_args.c +++ b/linux/alpha/get_syscall_args.c @@ -11,7 +11,7 @@ arch_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 336b9f6d..2f83c508 100644 --- a/linux/bfin/get_syscall_args.c +++ b/linux/bfin/get_syscall_args.c @@ -14,7 +14,7 @@ arch_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 04040559..8a41e234 100644 --- a/linux/hppa/get_syscall_args.c +++ b/linux/hppa/get_syscall_args.c @@ -11,7 +11,7 @@ arch_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 bf1f71af..9f4e71db 100644 --- a/linux/ia64/get_syscall_args.c +++ b/linux/ia64/get_syscall_args.c @@ -18,7 +18,7 @@ arch_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 6c35994d..409113c1 100644 --- a/linux/microblaze/get_syscall_args.c +++ b/linux/microblaze/get_syscall_args.c @@ -11,7 +11,7 @@ arch_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 e2889f98..b8e8652c 100644 --- a/linux/mips/get_syscall_args.c +++ b/linux/mips/get_syscall_args.c @@ -21,16 +21,16 @@ arch_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 @@ -54,7 +54,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]), diff --git a/linux/sh/get_syscall_args.c b/linux/sh/get_syscall_args.c index 005a45c0..a50ccdf0 100644 --- a/linux/sh/get_syscall_args.c +++ b/linux/sh/get_syscall_args.c @@ -19,7 +19,7 @@ arch_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 d74b7185..197ece99 100644 --- a/linux/sh64/get_syscall_args.c +++ b/linux/sh64/get_syscall_args.c @@ -13,7 +13,7 @@ arch_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 e8e88336..08565415 100644 --- a/linux/x86_64/get_syscall_args.c +++ b/linux/x86_64/get_syscall_args.c @@ -11,7 +11,7 @@ arch_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 25b46ec0..ee54375b 100644 --- a/linux/xtensa/get_syscall_args.c +++ b/linux/xtensa/get_syscall_args.c @@ -20,7 +20,7 @@ arch_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 2cd12e64..54930287 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 75165103..37e29a1b 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 418905f0..dc97819d 100644 --- a/signal.c +++ b/signal.c @@ -405,10 +405,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 5e3733a4..18516ed7 100644 --- a/syscall.c +++ b/syscall.c @@ -341,7 +341,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]; @@ -361,7 +361,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: @@ -388,7 +388,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: @@ -548,10 +548,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. @@ -563,7 +562,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); @@ -577,7 +576,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 @@ -599,7 +598,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: case SEN_execv: @@ -631,14 +630,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; } @@ -668,7 +667,7 @@ syscall_exiting_decode(struct tcb *tcp, struct timespec *pts) if ((Tflag || cflag) && !filtered(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)) @@ -702,7 +701,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); } } @@ -750,7 +749,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(") "); @@ -1237,6 +1236,13 @@ get_syscall_regs(struct tcb *tcp) return get_regs(tcp); } +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 @@ -1248,6 +1254,10 @@ get_syscall_regs(struct tcb *tcp) int get_scno(struct tcb *tcp) { + tcp->scno = -1; + tcp->s_ent = NULL; + tcp->qual_flg = QUAL_RAW | DEFAULT_QUAL_FLAGS; + if (get_syscall_regs(tcp) < 0) return -1; @@ -1275,14 +1285,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); @@ -1308,7 +1315,7 @@ get_syscall_args(struct tcb *tcp) for (unsigned int i = 0; i < ARRAY_SIZE(tcp->u_arg); ++i) tcp->u_arg[i] = ptrace_sci.entry.args[i]; #if SUPPORTED_PERSONALITIES > 1 - if (tcp->s_ent->sys_flags & COMPAT_SYSCALL_TYPES) { + if (tcp_sysent(tcp)->sys_flags & COMPAT_SYSCALL_TYPES) { for (unsigned int i = 0; i < ARRAY_SIZE(tcp->u_arg); ++i) tcp->u_arg[i] = (uint32_t) tcp->u_arg[i]; } @@ -1335,7 +1342,7 @@ get_syscall_result(struct tcb *tcp) if (get_syscall_result_regs(tcp) < 0) return -1; 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)); @@ -1381,7 +1388,7 @@ set_error(struct tcb *tcp, unsigned long new_error) if (ptrace_syscall_info_is_valid()) tcp->u_rval = -1; else - get_error(tcp, !(tcp->s_ent->sys_flags & + get_error(tcp, !(tcp_sysent(tcp)->sys_flags & SYSCALL_NEVER_FAILS)); } } @@ -1405,7 +1412,7 @@ set_success(struct tcb *tcp, kernel_long_t new_rval) if (ptrace_syscall_info_is_valid()) tcp->u_error = 0; else - get_error(tcp, !(tcp->s_ent->sys_flags & + get_error(tcp, !(tcp_sysent(tcp)->sys_flags & SYSCALL_NEVER_FAILS)); } } diff --git a/util.c b/util.c index bbe3fa5a..f0c7c6ae 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 ? ", " : "",