]> granicus.if.org Git - strace/commitdiff
Use accessors for tcp->s_ent, return a stub struct if it is NULL
authorEugene Syromyatnikov <evgsyr@gmail.com>
Tue, 29 Jan 2019 13:40:11 +0000 (14:40 +0100)
committerDmitry V. Levin <ldv@altlinux.org>
Sat, 9 Feb 2019 22:44:40 +0000 (22:44 +0000)
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 <ldv@altlinux.org>
17 files changed:
defs.h
ipc.c
linux/alpha/get_syscall_args.c
linux/bfin/get_syscall_args.c
linux/hppa/get_syscall_args.c
linux/ia64/get_syscall_args.c
linux/microblaze/get_syscall_args.c
linux/mips/get_syscall_args.c
linux/sh/get_syscall_args.c
linux/sh64/get_syscall_args.c
linux/x86_64/get_syscall_args.c
linux/xtensa/get_syscall_args.c
pathtrace.c
prctl.c
signal.c
syscall.c
util.c

diff --git a/defs.h b/defs.h
index 1f231d3460dd35837f7a99f11469e2e83c1a3eb8..ca1c39cc057ef50d25c6941f22e4056590a77f62 100644 (file)
--- 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 c35509bc5e8b80a9c75c243fcdb24e2677caf086..b2b3aa42960ecd6df67d3fbca65f4595837297f1 100644 (file)
--- 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;
index 381d75e67aa941d85df58fc44166970699bcdcae..8bebfaa4fcf4b3e598096cada67c250dcc6b5414 100644 (file)
@@ -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;
index 336b9f6d9f354a45b4284b0f194cf50ab8fd5ed5..2f83c508aa01cd08fce7436d1bddbddf52cc6d53 100644 (file)
@@ -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;
index 040405597ce53f7eeaae8498731a09dba08b8713..8a41e234245341702d136df3ad8383018eb646da 100644 (file)
@@ -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;
index bf1f71af309418e055969f035d422e52f2574cb5..9f4e71db87633f9f2c272b541ac44f1134caf2cd 100644 (file)
@@ -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) {
index 6c35994d84f8a0cfe3e102b71cd60814799f3ec6..409113c1bbe9cd2a33f8faac1cbfe16907410e17 100644 (file)
@@ -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;
index e2889f98532e5e272a40709be0d4635aa9f644af..b8e8652ca6314e0019be25524a4885372330e286 100644 (file)
@@ -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]),
index 005a45c09021c3780718bbbb147f87fd7ab0b14f..a50ccdf0e1f54f91306b6bb3f58c4ccb444ea639 100644 (file)
@@ -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;
index d74b7185b37d29c81a800b6c49cfc1b9f4bc82f4..197ece99cefa02f2ec8f76817af32e8d45bd7f55 100644 (file)
@@ -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;
index e8e88336862151060375eedf60dab3c3da325cb8..0856541501ee530cdd4fd3709f2511fc1d8c5b02 100644 (file)
@@ -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])
index 25b46ec02b9c2bc14c84466cb27181d8aa6ce196..ee54375bd498604dea8e23ab950e46599008f616 100644 (file)
@@ -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;
index 2cd12e6423713eedf107f4a0fff2fcd24d5889a9..5493028760a8bba69e3861da7d51522572235e4e 100644 (file)
@@ -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 75165103fa2664daf95dfd7d751ff2ce6afc3b9a..37e29a1b314a4d7ae3c2beefa4a7df3afcb89a76 100644 (file)
--- 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]);
 }
 
index 418905f0f3c51e5a803fed3dfbc4254baf2a2d60..dc97819d9d706012e08504b9c31064dfbb27d9d3 100644 (file)
--- 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;
index 5e3733a45372810a7be6fa05675530d47f758472..18516ed79910e35d59c083bbd75b8bf201f1685a 100644 (file)
--- 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);
                /*
                 * " <unavailable>" 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 bbe3fa5a5d6c12526c0812efd1bd2ccf7e7aecd2..f0c7c6ae80b6c9048e3db32503546891db3742c7 100644 (file)
--- 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 ? ", " : "",