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:
Дмитрий Левин 2016-08-09 00:07:53 +00:00
parent c61dd7f4d2
commit 60d7ec80d9
3 changed files with 42 additions and 23 deletions

7
defs.h
View File

@ -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) \

View File

@ -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);

View File

@ -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;