Fix decoding of invalid syscalls mapped to indirect subcalls
When the syscall number returned by arch_get_scno is a mapped indirect subcall (i.e. mapped subcall of socketcall or ipc syscall), do not mistakenly treat it as a valid indirect subcall. * defs.h (SCNO_IS_VALID): Treat scno with TRACE_INDIRECT_SUBCALL flag as invalid. * syscall.c (syscall_name): Do no shuffle scno. (trace_syscall_entering, trace_syscall_exiting): Use tcp->s_ent->sys_name instead of syscall_name. (get_scno): In case of invalid syscall, allocate a dynamic struct sysent containing an appropriate .sys_name. * tests/nsyscalls.c (main) [SYS_socket_subcall]: Check decoding of direct syscall number SYS_socket_subcall+1. (main) [SYS_ipc_subcall]: Check decoding of direct syscall number SYS_ipc_subcall+1.
This commit is contained in:
parent
c61dd7f4d2
commit
60d7ec80d9
7
defs.h
7
defs.h
@ -790,10 +790,13 @@ extern unsigned num_quals;
|
||||
#endif /* !IN_MPERS_BOOTSTRAP */
|
||||
|
||||
/*
|
||||
* If you need non-NULL sysent[scno].sys_func and sysent[scno].sys_name
|
||||
* If you need non-NULL sysent[scno].sys_func, non-NULL sysent[scno].sys_name,
|
||||
* and non-indirect sysent[scno].sys_flags.
|
||||
*/
|
||||
#define SCNO_IS_VALID(scno) \
|
||||
((unsigned long)(scno) < nsyscalls && sysent[scno].sys_func)
|
||||
((unsigned long)(scno) < nsyscalls \
|
||||
&& sysent[scno].sys_func \
|
||||
&& !(sysent[scno].sys_flags & TRACE_INDIRECT_SUBCALL))
|
||||
|
||||
/* Only ensures that sysent[scno] isn't out of range */
|
||||
#define SCNO_IN_RANGE(scno) \
|
||||
|
31
syscall.c
31
syscall.c
@ -753,7 +753,7 @@ syscall_name(long scno)
|
||||
if (SCNO_IS_VALID(scno))
|
||||
return sysent[scno].sys_name;
|
||||
else {
|
||||
sprintf(buf, "syscall_%lu", shuffle_scno(scno));
|
||||
sprintf(buf, "syscall_%lu", scno);
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
@ -787,10 +787,7 @@ trace_syscall_entering(struct tcb *tcp)
|
||||
|
||||
if (res != 1) {
|
||||
printleader(tcp);
|
||||
if (scno_good != 1)
|
||||
tprints("????" /* anti-trigraph gap */ "(");
|
||||
else
|
||||
tprintf("%s(", syscall_name(tcp->scno));
|
||||
tprintf("%s(", scno_good == 1 ? tcp->s_ent->sys_name : "????");
|
||||
/*
|
||||
* " <unavailable>" will be added later by the code which
|
||||
* detects ptrace errors.
|
||||
@ -849,7 +846,7 @@ trace_syscall_entering(struct tcb *tcp)
|
||||
#endif
|
||||
|
||||
printleader(tcp);
|
||||
tprintf("%s(", syscall_name(tcp->scno));
|
||||
tprintf("%s(", tcp->s_ent->sys_name);
|
||||
if ((tcp->qual_flg & QUAL_RAW) && SEN_exit != tcp->s_ent->sen)
|
||||
res = printargs(tcp);
|
||||
else
|
||||
@ -910,7 +907,7 @@ trace_syscall_exiting(struct tcb *tcp)
|
||||
if ((followfork < 2 && printing_tcp != tcp) || (tcp->flags & TCB_REPRINT)) {
|
||||
tcp->flags &= ~TCB_REPRINT;
|
||||
printleader(tcp);
|
||||
tprintf("<... %s resumed> ", syscall_name(tcp->scno));
|
||||
tprintf("<... %s resumed> ", tcp->s_ent->sys_name);
|
||||
}
|
||||
printing_tcp = tcp;
|
||||
|
||||
@ -1299,13 +1296,19 @@ get_scno(struct tcb *tcp)
|
||||
tcp->s_ent = &sysent[tcp->scno];
|
||||
tcp->qual_flg = qual_flags[tcp->scno];
|
||||
} else {
|
||||
static const struct_sysent unknown = {
|
||||
.nargs = MAX_ARGS,
|
||||
.sys_flags = 0,
|
||||
.sys_func = printargs,
|
||||
.sys_name = "system call",
|
||||
};
|
||||
tcp->s_ent = &unknown;
|
||||
struct {
|
||||
struct_sysent ent;
|
||||
char buf[sizeof("syscall_%lu") + sizeof(long) * 3];
|
||||
} *s = xcalloc(1, sizeof(*s));
|
||||
set_tcb_priv_data(tcp, s, free);
|
||||
|
||||
sprintf(s->buf, "syscall_%lu", shuffle_scno(tcp->scno));
|
||||
s->ent.nargs = MAX_ARGS;
|
||||
s->ent.sen = SEN_printargs;
|
||||
s->ent.sys_func = printargs;
|
||||
s->ent.sys_name = s->buf;
|
||||
|
||||
tcp->s_ent = &s->ent;
|
||||
tcp->qual_flg = QUAL_RAW | DEFAULT_QUAL_FLAGS;
|
||||
if (debug_flag)
|
||||
error_msg("pid %d invalid syscall %ld", tcp->pid, tcp->scno);
|
||||
|
@ -57,10 +57,8 @@ static const struct_sysent syscallent[] = {
|
||||
# define SYSCALL_BIT 0
|
||||
#endif
|
||||
|
||||
static const unsigned long nr = ARRAY_SIZE(syscallent) | SYSCALL_BIT;
|
||||
|
||||
int
|
||||
main(void)
|
||||
static void
|
||||
test_syscall(const unsigned long nr)
|
||||
{
|
||||
static const kernel_ulong_t a[] = {
|
||||
(kernel_ulong_t) 0xface0fedbadc0ded,
|
||||
@ -71,14 +69,15 @@ main(void)
|
||||
(kernel_ulong_t) 0xface5fedbadc5ded
|
||||
};
|
||||
|
||||
long rc = syscall(nr, a[0], a[1], a[2], a[3], a[4], a[5]);
|
||||
long rc = syscall(nr | SYSCALL_BIT,
|
||||
a[0], a[1], a[2], a[3], a[4], a[5]);
|
||||
#ifdef LINUX_MIPSO32
|
||||
printf("syscall(%#lx, %#lx, %#lx, %#lx, %#lx, %#lx, %#lx)"
|
||||
" = %ld ENOSYS (%m)\n", nr,
|
||||
" = %ld ENOSYS (%m)\n", nr | SYSCALL_BIT,
|
||||
a[0], a[1], a[2], a[3], a[4], a[5], rc);
|
||||
#else
|
||||
printf("syscall_%lu(%#llx, %#llx, %#llx, %#llx, %#llx, %#llx)"
|
||||
" = %ld (errno %d)\n", nr & (~SYSCALL_BIT),
|
||||
" = %ld (errno %d)\n", nr,
|
||||
(unsigned long long) a[0],
|
||||
(unsigned long long) a[1],
|
||||
(unsigned long long) a[2],
|
||||
@ -87,6 +86,20 @@ main(void)
|
||||
(unsigned long long) a[5],
|
||||
rc, errno);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
test_syscall(ARRAY_SIZE(syscallent));
|
||||
|
||||
#ifdef SYS_socket_subcall
|
||||
test_syscall(SYS_socket_subcall + 1);
|
||||
#endif
|
||||
|
||||
#ifdef SYS_ipc_subcall
|
||||
test_syscall(SYS_ipc_subcall + 1);
|
||||
#endif
|
||||
|
||||
puts("+++ exited with 0 +++");
|
||||
return 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user