From: Dmitry V. Levin Date: Tue, 20 Dec 2016 01:52:20 +0000 (+0000) Subject: x32: implement automatic argument truncation for compat syscalls X-Git-Tag: v4.16~320 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6a360e2f3e63419eb36eea7c69268c7a1f5342b0;p=strace x32: implement automatic argument truncation for compat syscalls x32 syscalls starting with number 512 are compat syscalls that operate on compat types. Set COMPAT_SYSCALL_TYPES flag to these syscall entries and make get_syscall_args truncate arguments of syscalls that have this flag set, to avoid unpleasant alternative of adding multiple widen_to_ulong invocations to individual syscall parsers. preadv, pwritev, preadv2, and pwritev2 are exceptions: while these syscalls operate on compat types, the offset argument has a regular 64-bit type, so the automatic argument truncation cannot be applied. * defs.h (COMPAT_SYSCALL_TYPES): New macro. * syscall.c (CST): New macro, defined to COMPAT_SYSCALL_TYPES. * linux/ia64/syscallent.h: Do not include "../i386/syscallent.h" unless [CST > 0]. * linux/x32/syscallent.h [512..533, 536..545]: Add CST flag. * linux/x86_64/get_syscall_args.c (get_syscall_args): Truncate arguments of compat syscalls to 32-bit values. * tests/ksysent.c (CST): New macro, defined to 0. * tests/nsyscalls.c (CST): Likewise. --- diff --git a/defs.h b/defs.h index 06b1dcd3..2b6ca9d1 100644 --- a/defs.h +++ b/defs.h @@ -356,6 +356,7 @@ extern const struct xlat whence_codes[]; #define STACKTRACE_INVALIDATE_CACHE 0400 /* Trigger proc/maps cache updating */ #define STACKTRACE_CAPTURE_ON_ENTER 01000 /* Capture stacktrace on "entering" stage */ #define TRACE_INDIRECT_SUBCALL 02000 /* Syscall is an indirect socket/ipc subcall. */ +#define COMPAT_SYSCALL_TYPES 04000 /* A compat syscall that uses compat types. */ #define IOCTL_NUMBER_UNKNOWN 0 #define IOCTL_NUMBER_HANDLED 1 diff --git a/linux/ia64/syscallent.h b/linux/ia64/syscallent.h index 5ba6afb0..d3cb3d6a 100644 --- a/linux/ia64/syscallent.h +++ b/linux/ia64/syscallent.h @@ -30,16 +30,17 @@ * IA-32 syscalls that have pointer arguments which are incompatible * with 64-bit layout get redirected to printargs. */ -#undef SYS_FUNC_NAME -#define SYS_FUNC_NAME(syscall_name) printargs -#include "../i386/syscallent.h" -#undef SYS_FUNC_NAME -#define SYS_FUNC_NAME(syscall_name) MPERS_FUNC_NAME(syscall_name) +#if CST > 0 +# undef SYS_FUNC_NAME +# define SYS_FUNC_NAME(syscall_name) printargs +# include "../i386/syscallent.h" +# undef SYS_FUNC_NAME +# define SYS_FUNC_NAME(syscall_name) MPERS_FUNC_NAME(syscall_name) +#endif /* You must be careful to check ../i386/syscallent.h so that this table starts where that one leaves off. */ -[(SYS_ipc_subcall + SYS_ipc_nsubcalls) ... 1023] = { }, [1024] = { 0, 0, SEN(printargs), "ni_syscall" }, [1025] = { 1, TP|SE, SEN(exit), "exit" }, [1026] = { 3, TD, SEN(read), "read" }, diff --git a/linux/x32/syscallent.h b/linux/x32/syscallent.h index 8749b9de..107aa2bb 100644 --- a/linux/x32/syscallent.h +++ b/linux/x32/syscallent.h @@ -335,39 +335,39 @@ * x32-specific system call numbers start at 512 to avoid cache impact * for native 64-bit operation. */ -[512] = { 4, TS, SEN(rt_sigaction), "rt_sigaction" }, -[513] = { 0, TS, SEN(sigreturn), "rt_sigreturn" }, -[514] = { 3, TD, SEN(ioctl), "ioctl" }, -[515] = { 3, TD, SEN(readv), "readv" }, -[516] = { 3, TD, SEN(writev), "writev" }, -[517] = { 6, TN, SEN(recvfrom), "recvfrom" }, -[518] = { 3, TN, SEN(sendmsg), "sendmsg" }, -[519] = { 3, TN, SEN(recvmsg), "recvmsg" }, -[520] = { 3, TF|TP|SE|SI, SEN(execve), "execve" }, -[521] = { 4, 0, SEN(ptrace), "ptrace" }, -[522] = { 2, TS, SEN(rt_sigpending), "rt_sigpending" }, -[523] = { 4, TS, SEN(rt_sigtimedwait), "rt_sigtimedwait" }, -[524] = { 3, TS, SEN(rt_sigqueueinfo), "rt_sigqueueinfo" }, -[525] = { 2, TS, SEN(sigaltstack), "sigaltstack" }, -[526] = { 3, 0, SEN(timer_create), "timer_create" }, -[527] = { 2, 0, SEN(mq_notify), "mq_notify" }, -[528] = { 4, 0, SEN(kexec_load), "kexec_load" }, -[529] = { 5, TP, SEN(waitid), "waitid" }, -[530] = { 2, 0, SEN(set_robust_list), "set_robust_list" }, -[531] = { 3, 0, SEN(get_robust_list), "get_robust_list" }, -[532] = { 4, TD, SEN(vmsplice), "vmsplice" }, -[533] = { 6, TM, SEN(move_pages), "move_pages" }, +[512] = { 4, CST|TS, SEN(rt_sigaction), "rt_sigaction" }, +[513] = { 0, CST|TS, SEN(sigreturn), "rt_sigreturn" }, +[514] = { 3, CST|TD, SEN(ioctl), "ioctl" }, +[515] = { 3, CST|TD, SEN(readv), "readv" }, +[516] = { 3, CST|TD, SEN(writev), "writev" }, +[517] = { 6, CST|TN, SEN(recvfrom), "recvfrom" }, +[518] = { 3, CST|TN, SEN(sendmsg), "sendmsg" }, +[519] = { 3, CST|TN, SEN(recvmsg), "recvmsg" }, +[520] = { 3, CST|TF|TP|SE|SI,SEN(execve), "execve" }, +[521] = { 4, CST, SEN(ptrace), "ptrace" }, +[522] = { 2, CST|TS, SEN(rt_sigpending), "rt_sigpending" }, +[523] = { 4, CST|TS, SEN(rt_sigtimedwait), "rt_sigtimedwait" }, +[524] = { 3, CST|TS, SEN(rt_sigqueueinfo), "rt_sigqueueinfo" }, +[525] = { 2, CST|TS, SEN(sigaltstack), "sigaltstack" }, +[526] = { 3, CST, SEN(timer_create), "timer_create" }, +[527] = { 2, CST, SEN(mq_notify), "mq_notify" }, +[528] = { 4, CST, SEN(kexec_load), "kexec_load" }, +[529] = { 5, CST|TP, SEN(waitid), "waitid" }, +[530] = { 2, CST, SEN(set_robust_list), "set_robust_list" }, +[531] = { 3, CST, SEN(get_robust_list), "get_robust_list" }, +[532] = { 4, CST|TD, SEN(vmsplice), "vmsplice" }, +[533] = { 6, CST|TM, SEN(move_pages), "move_pages" }, [534] = { 4, TD, SEN(preadv), "preadv" }, [535] = { 4, TD, SEN(pwritev), "pwritev" }, -[536] = { 4, TP|TS, SEN(rt_tgsigqueueinfo), "rt_tgsigqueueinfo" }, -[537] = { 5, TN, SEN(recvmmsg), "recvmmsg" }, -[538] = { 4, TN, SEN(sendmmsg), "sendmmsg" }, -[539] = { 6, 0, SEN(process_vm_readv), "process_vm_readv" }, -[540] = { 6, 0, SEN(process_vm_writev), "process_vm_writev" }, -[541] = { 5, TN, SEN(setsockopt), "setsockopt" }, -[542] = { 5, TN, SEN(getsockopt), "getsockopt" }, -[543] = { 2, TM, SEN(io_setup), "io_setup" }, -[544] = { 3, 0, SEN(io_submit), "io_submit" }, -[545] = { 5, TD|TF|TP|SE|SI, SEN(execveat), "execveat", }, +[536] = { 4, CST|TP|TS, SEN(rt_tgsigqueueinfo), "rt_tgsigqueueinfo" }, +[537] = { 5, CST|TN, SEN(recvmmsg), "recvmmsg" }, +[538] = { 4, CST|TN, SEN(sendmmsg), "sendmmsg" }, +[539] = { 6, CST, SEN(process_vm_readv), "process_vm_readv" }, +[540] = { 6, CST, SEN(process_vm_writev), "process_vm_writev" }, +[541] = { 5, CST|TN, SEN(setsockopt), "setsockopt" }, +[542] = { 5, CST|TN, SEN(getsockopt), "getsockopt" }, +[543] = { 2, CST|TM, SEN(io_setup), "io_setup" }, +[544] = { 3, CST, SEN(io_submit), "io_submit" }, +[545] = { 5, CST|TD|TF|TP|SE|SI, SEN(execveat), "execveat", }, [546] = { 6, TD, SEN(preadv2), "preadv2" }, [547] = { 6, TD, SEN(pwritev2), "pwritev2" }, diff --git a/linux/x86_64/get_syscall_args.c b/linux/x86_64/get_syscall_args.c index fa591fb6..51d03f5d 100644 --- a/linux/x86_64/get_syscall_args.c +++ b/linux/x86_64/get_syscall_args.c @@ -4,32 +4,56 @@ get_syscall_args(struct tcb *tcp) { if (x86_io.iov_len != sizeof(i386_regs)) { /* x86-64 or x32 ABI */ - tcp->u_arg[0] = x86_64_regs.rdi; - tcp->u_arg[1] = x86_64_regs.rsi; - tcp->u_arg[2] = x86_64_regs.rdx; - tcp->u_arg[3] = x86_64_regs.r10; - tcp->u_arg[4] = x86_64_regs.r8; - tcp->u_arg[5] = x86_64_regs.r9; + if (tcp->s_ent->sys_flags & COMPAT_SYSCALL_TYPES) { + /* + * X32 compat syscall: zero-extend from 32 bits. + * Use widen_to_long(tcp->u_arg[N]) in syscall handlers + * if you need to use *sign-extended* parameter. + */ #ifdef X32 - tcp->ext_arg[0] = x86_64_regs.rdi; - tcp->ext_arg[1] = x86_64_regs.rsi; - tcp->ext_arg[2] = x86_64_regs.rdx; - tcp->ext_arg[3] = x86_64_regs.r10; - tcp->ext_arg[4] = x86_64_regs.r8; - tcp->ext_arg[5] = x86_64_regs.r9; + tcp->u_arg[0] = tcp->ext_arg[0] = (uint32_t) x86_64_regs.rdi; + tcp->u_arg[1] = tcp->ext_arg[1] = (uint32_t) x86_64_regs.rsi; + tcp->u_arg[2] = tcp->ext_arg[2] = (uint32_t) x86_64_regs.rdx; + tcp->u_arg[3] = tcp->ext_arg[3] = (uint32_t) x86_64_regs.r10; + tcp->u_arg[4] = tcp->ext_arg[4] = (uint32_t) x86_64_regs.r8; + tcp->u_arg[5] = tcp->ext_arg[5] = (uint32_t) x86_64_regs.r9; +#else + tcp->u_arg[0] = (uint32_t) x86_64_regs.rdi; + tcp->u_arg[1] = (uint32_t) x86_64_regs.rsi; + tcp->u_arg[2] = (uint32_t) x86_64_regs.rdx; + tcp->u_arg[3] = (uint32_t) x86_64_regs.r10; + tcp->u_arg[4] = (uint32_t) x86_64_regs.r8; + tcp->u_arg[5] = (uint32_t) x86_64_regs.r9; #endif + } else { +#ifdef X32 + tcp->u_arg[0] = tcp->ext_arg[0] = x86_64_regs.rdi; + tcp->u_arg[1] = tcp->ext_arg[1] = x86_64_regs.rsi; + tcp->u_arg[2] = tcp->ext_arg[2] = x86_64_regs.rdx; + tcp->u_arg[3] = tcp->ext_arg[3] = x86_64_regs.r10; + tcp->u_arg[4] = tcp->ext_arg[4] = x86_64_regs.r8; + tcp->u_arg[5] = tcp->ext_arg[5] = x86_64_regs.r9; +#else + tcp->u_arg[0] = x86_64_regs.rdi; + tcp->u_arg[1] = x86_64_regs.rsi; + tcp->u_arg[2] = x86_64_regs.rdx; + tcp->u_arg[3] = x86_64_regs.r10; + tcp->u_arg[4] = x86_64_regs.r8; + tcp->u_arg[5] = x86_64_regs.r9; +#endif + } } else { - /* i386 ABI */ - /* Zero-extend from 32 bits */ - /* Use widen_to_long(tcp->u_arg[N]) in syscall handlers + /* + * i386 ABI: zero-extend from 32 bits. + * Use widen_to_long(tcp->u_arg[N]) in syscall handlers * if you need to use *sign-extended* parameter. */ - tcp->u_arg[0] = (long)(uint32_t)i386_regs.ebx; - tcp->u_arg[1] = (long)(uint32_t)i386_regs.ecx; - tcp->u_arg[2] = (long)(uint32_t)i386_regs.edx; - tcp->u_arg[3] = (long)(uint32_t)i386_regs.esi; - tcp->u_arg[4] = (long)(uint32_t)i386_regs.edi; - tcp->u_arg[5] = (long)(uint32_t)i386_regs.ebp; + tcp->u_arg[0] = (uint32_t) i386_regs.ebx; + tcp->u_arg[1] = (uint32_t) i386_regs.ecx; + tcp->u_arg[2] = (uint32_t) i386_regs.edx; + tcp->u_arg[3] = (uint32_t) i386_regs.esi; + tcp->u_arg[4] = (uint32_t) i386_regs.edi; + tcp->u_arg[5] = (uint32_t) i386_regs.ebp; } return 1; } diff --git a/syscall.c b/syscall.c index e3924c58..c27c669d 100644 --- a/syscall.c +++ b/syscall.c @@ -82,6 +82,7 @@ #define MA MAX_ARGS #define SI STACKTRACE_INVALIDATE_CACHE #define SE STACKTRACE_CAPTURE_ON_ENTER +#define CST COMPAT_SYSCALL_TYPES #define SEN(syscall_name) SEN_ ## syscall_name, SYS_FUNC_NAME(sys_ ## syscall_name) @@ -116,6 +117,7 @@ static const struct_sysent sysent2[] = { #undef MA #undef SI #undef SE +#undef CST /* * `ioctlent[012].h' files are automatically generated by the auxiliary diff --git a/tests/ksysent.c b/tests/ksysent.c index 66b4ffb4..9b7bf49b 100644 --- a/tests/ksysent.c +++ b/tests/ksysent.c @@ -39,6 +39,7 @@ #define MA 0 #define SI 0 #define SE 0 +#define CST 0 #define SEN(arg) 0,0 static const struct_sysent syscallent[] = { diff --git a/tests/nsyscalls.c b/tests/nsyscalls.c index 9c8b30a7..9a4d72af 100644 --- a/tests/nsyscalls.c +++ b/tests/nsyscalls.c @@ -41,6 +41,7 @@ #define MA 0 #define SI 0 #define SE 0 +#define CST 0 #define SEN(arg) 0,0 static const struct_sysent syscallent[] = {