From 09d1415d2454dbcd7cb2fc0b56da8afba8d03dc6 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 9 Jul 2017 17:14:25 -0400 Subject: signal/mips: switch mips to generic siginfo ... having taught the latter that si_errno and si_code might be swapped. Signed-off-by: Al Viro Signed-off-by: Eric W. Biederman --- arch/mips/include/uapi/asm/siginfo.h | 86 +----------------------------------- 1 file changed, 1 insertion(+), 85 deletions(-) (limited to 'arch/mips') diff --git a/arch/mips/include/uapi/asm/siginfo.h b/arch/mips/include/uapi/asm/siginfo.h index f17d8163dec6..262504bd59a5 100644 --- a/arch/mips/include/uapi/asm/siginfo.h +++ b/arch/mips/include/uapi/asm/siginfo.h @@ -14,8 +14,6 @@ #define __ARCH_SIGEV_PREAMBLE_SIZE (sizeof(long) + 2*sizeof(int)) #undef __ARCH_SI_TRAPNO /* exception code needs to fill this ... */ -#define HAVE_ARCH_SIGINFO_T - /* * Careful to keep union _sifields from shifting ... */ @@ -27,92 +25,10 @@ #error _MIPS_SZLONG neither 32 nor 64 #endif -#define __ARCH_SIGSYS +#define __ARCH_HAS_SWAPPED_SIGINFO #include -/* We can't use generic siginfo_t, because our si_code and si_errno are swapped */ -typedef struct siginfo { - int si_signo; - int si_code; - int si_errno; - int __pad0[SI_MAX_SIZE / sizeof(int) - SI_PAD_SIZE - 3]; - - union { - int _pad[SI_PAD_SIZE]; - - /* kill() */ - struct { - __kernel_pid_t _pid; /* sender's pid */ - __ARCH_SI_UID_T _uid; /* sender's uid */ - } _kill; - - /* POSIX.1b timers */ - struct { - __kernel_timer_t _tid; /* timer id */ - int _overrun; /* overrun count */ - char _pad[sizeof( __ARCH_SI_UID_T) - sizeof(int)]; - sigval_t _sigval; /* same as below */ - int _sys_private; /* not to be passed to user */ - } _timer; - - /* POSIX.1b signals */ - struct { - __kernel_pid_t _pid; /* sender's pid */ - __ARCH_SI_UID_T _uid; /* sender's uid */ - sigval_t _sigval; - } _rt; - - /* SIGCHLD */ - struct { - __kernel_pid_t _pid; /* which child */ - __ARCH_SI_UID_T _uid; /* sender's uid */ - int _status; /* exit code */ - __kernel_clock_t _utime; - __kernel_clock_t _stime; - } _sigchld; - - /* IRIX SIGCHLD */ - struct { - __kernel_pid_t _pid; /* which child */ - __kernel_clock_t _utime; - int _status; /* exit code */ - __kernel_clock_t _stime; - } _irix_sigchld; - - /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ - struct { - void __user *_addr; /* faulting insn/memory ref. */ -#ifdef __ARCH_SI_TRAPNO - int _trapno; /* TRAP # which caused the signal */ -#endif - short _addr_lsb; - union { - /* used when si_code=SEGV_BNDERR */ - struct { - void __user *_lower; - void __user *_upper; - } _addr_bnd; - /* used when si_code=SEGV_PKUERR */ - __u32 _pkey; - }; - } _sigfault; - - /* SIGPOLL, SIGXFSZ (To do ...) */ - struct { - __ARCH_SI_BAND_T _band; /* POLL_IN, POLL_OUT, POLL_MSG */ - int _fd; - } _sigpoll; - - /* SIGSYS */ - struct { - void __user *_call_addr; /* calling user insn */ - int _syscall; /* triggering system call number */ - unsigned int _arch; /* AUDIT_ARCH_* of syscall */ - } _sigsys; - } _sifields; -} siginfo_t; - /* * si_code values * Again these have been chosen to be IRIX compatible. -- cgit v1.2.3 From b713da69e4c91d9addada4e58d26df1c9b5cd840 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 9 Jul 2017 15:53:17 -0400 Subject: signal: unify compat_siginfo_t --EWB Added #ifdef CONFIG_X86_X32_ABI to arch/x86/kernel/signal_compat.c Changed #ifdef CONFIG_X86_X32 to #ifdef CONFIG_X86_X32_ABI in linux/compat.h CONFIG_X86_X32 is set when the user requests X32 support. CONFIG_X86_X32_ABI is set when the user requests X32 support and the tool-chain has X32 allowing X32 support to be built. Signed-off-by: Al Viro Signed-off-by: Eric W. Biederman --- arch/arm64/include/asm/compat.h | 63 --------------------------- arch/mips/include/asm/compat.h | 71 ------------------------------ arch/parisc/include/asm/compat.h | 63 --------------------------- arch/powerpc/include/asm/compat.h | 62 --------------------------- arch/s390/include/asm/compat.h | 72 ------------------------------- arch/sparc/include/asm/compat.h | 56 ------------------------ arch/tile/include/asm/compat.h | 58 ------------------------- arch/x86/include/asm/compat.h | 80 ---------------------------------- arch/x86/kernel/signal_compat.c | 4 ++ include/linux/compat.h | 90 +++++++++++++++++++++++++++++++++++++++ 10 files changed, 94 insertions(+), 525 deletions(-) (limited to 'arch/mips') diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h index dd32fe19ec58..c00c62e1a4a3 100644 --- a/arch/arm64/include/asm/compat.h +++ b/arch/arm64/include/asm/compat.h @@ -150,69 +150,6 @@ typedef u32 compat_old_sigset_t; typedef u32 compat_sigset_word; -typedef union compat_sigval { - compat_int_t sival_int; - compat_uptr_t sival_ptr; -} compat_sigval_t; - -typedef struct compat_siginfo { - int si_signo; - int si_errno; - int si_code; - - union { - int _pad[128/sizeof(int) - 3]; - - /* kill() */ - struct { - compat_pid_t _pid; /* sender's pid */ - __compat_uid32_t _uid; /* sender's uid */ - } _kill; - - /* POSIX.1b timers */ - struct { - compat_timer_t _tid; /* timer id */ - int _overrun; /* overrun count */ - compat_sigval_t _sigval; /* same as below */ - } _timer; - - /* POSIX.1b signals */ - struct { - compat_pid_t _pid; /* sender's pid */ - __compat_uid32_t _uid; /* sender's uid */ - compat_sigval_t _sigval; - } _rt; - - /* SIGCHLD */ - struct { - compat_pid_t _pid; /* which child */ - __compat_uid32_t _uid; /* sender's uid */ - int _status; /* exit code */ - compat_clock_t _utime; - compat_clock_t _stime; - } _sigchld; - - /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ - struct { - compat_uptr_t _addr; /* faulting insn/memory ref. */ - short _addr_lsb; /* LSB of the reported address */ - } _sigfault; - - /* SIGPOLL */ - struct { - compat_long_t _band; /* POLL_IN, POLL_OUT, POLL_MSG */ - int _fd; - } _sigpoll; - - /* SIGSYS */ - struct { - compat_uptr_t _call_addr; /* calling user insn */ - int _syscall; /* triggering system call number */ - compat_uint_t _arch; /* AUDIT_ARCH_* of syscall */ - } _sigsys; - } _sifields; -} compat_siginfo_t; - #define COMPAT_OFF_T_MAX 0x7fffffff /* diff --git a/arch/mips/include/asm/compat.h b/arch/mips/include/asm/compat.h index 49691331ada4..fe7d445f675f 100644 --- a/arch/mips/include/asm/compat.h +++ b/arch/mips/include/asm/compat.h @@ -126,79 +126,8 @@ typedef u32 compat_old_sigset_t; /* at least 32 bits */ typedef u32 compat_sigset_word; -typedef union compat_sigval { - compat_int_t sival_int; - compat_uptr_t sival_ptr; -} compat_sigval_t; - -/* Can't use the generic version because si_code and si_errno are swapped */ - #define SI_PAD_SIZE32 (128/sizeof(int) - 3) -typedef struct compat_siginfo { - int si_signo; - int si_code; - int si_errno; - - union { - int _pad[128 / sizeof(int) - 3]; - - /* kill() */ - struct { - compat_pid_t _pid; /* sender's pid */ - __compat_uid32_t _uid; /* sender's uid */ - } _kill; - - /* POSIX.1b timers */ - struct { - compat_timer_t _tid; /* timer id */ - int _overrun; /* overrun count */ - compat_sigval_t _sigval; /* same as below */ - } _timer; - - /* POSIX.1b signals */ - struct { - compat_pid_t _pid; /* sender's pid */ - __compat_uid32_t _uid; /* sender's uid */ - compat_sigval_t _sigval; - } _rt; - - /* SIGCHLD */ - struct { - compat_pid_t _pid; /* which child */ - __compat_uid32_t _uid; /* sender's uid */ - int _status; /* exit code */ - compat_clock_t _utime; - compat_clock_t _stime; - } _sigchld; - - /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ - struct { - compat_uptr_t _addr; /* faulting insn/memory ref. */ -#ifdef __ARCH_SI_TRAPNO - int _trapno; /* TRAP # which caused the signal */ -#endif - short _addr_lsb; /* LSB of the reported address */ - struct { - compat_uptr_t _lower; - compat_uptr_t _upper; - } _addr_bnd; - } _sigfault; - - /* SIGPOLL */ - struct { - compat_long_t _band; /* POLL_IN, POLL_OUT, POLL_MSG */ - int _fd; - } _sigpoll; - - struct { - compat_uptr_t _call_addr; /* calling insn */ - int _syscall; /* triggering system call number */ - compat_uint_t _arch; /* AUDIT_ARCH_* of syscall */ - } _sigsys; - } _sifields; -} compat_siginfo_t; - #define COMPAT_OFF_T_MAX 0x7fffffff /* diff --git a/arch/parisc/include/asm/compat.h b/arch/parisc/include/asm/compat.h index cf3bcacec027..c22db5323244 100644 --- a/arch/parisc/include/asm/compat.h +++ b/arch/parisc/include/asm/compat.h @@ -130,69 +130,6 @@ typedef u32 compat_old_sigset_t; /* at least 32 bits */ typedef u32 compat_sigset_word; -typedef union compat_sigval { - compat_int_t sival_int; - compat_uptr_t sival_ptr; -} compat_sigval_t; - -typedef struct compat_siginfo { - int si_signo; - int si_errno; - int si_code; - - union { - int _pad[128/sizeof(int) - 3]; - - /* kill() */ - struct { - unsigned int _pid; /* sender's pid */ - unsigned int _uid; /* sender's uid */ - } _kill; - - /* POSIX.1b timers */ - struct { - compat_timer_t _tid; /* timer id */ - int _overrun; /* overrun count */ - char _pad[sizeof(unsigned int) - sizeof(int)]; - compat_sigval_t _sigval; /* same as below */ - } _timer; - - /* POSIX.1b signals */ - struct { - unsigned int _pid; /* sender's pid */ - unsigned int _uid; /* sender's uid */ - compat_sigval_t _sigval; - } _rt; - - /* SIGCHLD */ - struct { - unsigned int _pid; /* which child */ - unsigned int _uid; /* sender's uid */ - int _status; /* exit code */ - compat_clock_t _utime; - compat_clock_t _stime; - } _sigchld; - - /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ - struct { - unsigned int _addr; /* faulting insn/memory ref. */ - } _sigfault; - - /* SIGPOLL */ - struct { - int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ - int _fd; - } _sigpoll; - - /* SIGSYS */ - struct { - compat_uptr_t _call_addr; /* calling user insn */ - int _syscall; /* triggering system call number */ - compat_uint_t _arch; /* AUDIT_ARCH_* of syscall */ - } _sigsys; - } _sifields; -} compat_siginfo_t; - #define COMPAT_OFF_T_MAX 0x7fffffff struct compat_ipc64_perm { diff --git a/arch/powerpc/include/asm/compat.h b/arch/powerpc/include/asm/compat.h index e02de2fd56e3..8a2363221b0c 100644 --- a/arch/powerpc/include/asm/compat.h +++ b/arch/powerpc/include/asm/compat.h @@ -119,70 +119,8 @@ typedef u32 compat_old_sigset_t; typedef u32 compat_sigset_word; -typedef union compat_sigval { - compat_int_t sival_int; - compat_uptr_t sival_ptr; -} compat_sigval_t; - #define SI_PAD_SIZE32 (128/sizeof(int) - 3) -typedef struct compat_siginfo { - int si_signo; - int si_errno; - int si_code; - - union { - int _pad[SI_PAD_SIZE32]; - - /* kill() */ - struct { - compat_pid_t _pid; /* sender's pid */ - __compat_uid_t _uid; /* sender's uid */ - } _kill; - - /* POSIX.1b timers */ - struct { - compat_timer_t _tid; /* timer id */ - int _overrun; /* overrun count */ - compat_sigval_t _sigval; /* same as below */ - } _timer; - - /* POSIX.1b signals */ - struct { - compat_pid_t _pid; /* sender's pid */ - __compat_uid_t _uid; /* sender's uid */ - compat_sigval_t _sigval; - } _rt; - - /* SIGCHLD */ - struct { - compat_pid_t _pid; /* which child */ - __compat_uid_t _uid; /* sender's uid */ - int _status; /* exit code */ - compat_clock_t _utime; - compat_clock_t _stime; - } _sigchld; - - /* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGEMT */ - struct { - unsigned int _addr; /* faulting insn/memory ref. */ - } _sigfault; - - /* SIGPOLL */ - struct { - int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ - int _fd; - } _sigpoll; - - /* SIGSYS */ - struct { - unsigned int _call_addr; /* calling insn */ - int _syscall; /* triggering system call number */ - unsigned int _arch; /* AUDIT_ARCH_* of syscall */ - } _sigsys; - } _sifields; -} compat_siginfo_t; - #define COMPAT_OFF_T_MAX 0x7fffffff /* diff --git a/arch/s390/include/asm/compat.h b/arch/s390/include/asm/compat.h index 3a187c4932a5..9830fb6b076e 100644 --- a/arch/s390/include/asm/compat.h +++ b/arch/s390/include/asm/compat.h @@ -189,78 +189,6 @@ typedef u32 compat_old_sigset_t; /* at least 32 bits */ typedef u32 compat_sigset_word; -typedef union compat_sigval { - compat_int_t sival_int; - compat_uptr_t sival_ptr; -} compat_sigval_t; - -typedef struct compat_siginfo { - int si_signo; - int si_errno; - int si_code; - - union { - int _pad[128/sizeof(int) - 3]; - - /* kill() */ - struct { - pid_t _pid; /* sender's pid */ - uid_t _uid; /* sender's uid */ - } _kill; - - /* POSIX.1b timers */ - struct { - compat_timer_t _tid; /* timer id */ - int _overrun; /* overrun count */ - compat_sigval_t _sigval; /* same as below */ - } _timer; - - /* POSIX.1b signals */ - struct { - pid_t _pid; /* sender's pid */ - uid_t _uid; /* sender's uid */ - compat_sigval_t _sigval; - } _rt; - - /* SIGCHLD */ - struct { - pid_t _pid; /* which child */ - uid_t _uid; /* sender's uid */ - int _status;/* exit code */ - compat_clock_t _utime; - compat_clock_t _stime; - } _sigchld; - - /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ - struct { - __u32 _addr; /* faulting insn/memory ref. - pointer */ - } _sigfault; - - /* SIGPOLL */ - struct { - int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ - int _fd; - } _sigpoll; - } _sifields; -} compat_siginfo_t; - -/* - * How these fields are to be accessed. - */ -#define si_pid _sifields._kill._pid -#define si_uid _sifields._kill._uid -#define si_status _sifields._sigchld._status -#define si_utime _sifields._sigchld._utime -#define si_stime _sifields._sigchld._stime -#define si_value _sifields._rt._sigval -#define si_int _sifields._rt._sigval.sival_int -#define si_ptr _sifields._rt._sigval.sival_ptr -#define si_addr _sifields._sigfault._addr -#define si_band _sifields._sigpoll._band -#define si_fd _sifields._sigpoll._fd -#define si_tid _sifields._timer._tid -#define si_overrun _sifields._timer._overrun - #define COMPAT_OFF_T_MAX 0x7fffffff /* diff --git a/arch/sparc/include/asm/compat.h b/arch/sparc/include/asm/compat.h index 2d9f4fd5f74a..c3688ae98b90 100644 --- a/arch/sparc/include/asm/compat.h +++ b/arch/sparc/include/asm/compat.h @@ -149,64 +149,8 @@ typedef u32 compat_old_sigset_t; typedef u32 compat_sigset_word; -typedef union compat_sigval { - compat_int_t sival_int; - compat_uptr_t sival_ptr; -} compat_sigval_t; - #define SI_PAD_SIZE32 (128/sizeof(int) - 3) -typedef struct compat_siginfo { - int si_signo; - int si_errno; - int si_code; - - union { - int _pad[SI_PAD_SIZE32]; - - /* kill() */ - struct { - compat_pid_t _pid; /* sender's pid */ - unsigned int _uid; /* sender's uid */ - } _kill; - - /* POSIX.1b timers */ - struct { - compat_timer_t _tid; /* timer id */ - int _overrun; /* overrun count */ - compat_sigval_t _sigval; /* same as below */ - } _timer; - - /* POSIX.1b signals */ - struct { - compat_pid_t _pid; /* sender's pid */ - unsigned int _uid; /* sender's uid */ - compat_sigval_t _sigval; - } _rt; - - /* SIGCHLD */ - struct { - compat_pid_t _pid; /* which child */ - unsigned int _uid; /* sender's uid */ - int _status; /* exit code */ - compat_clock_t _utime; - compat_clock_t _stime; - } _sigchld; - - /* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGEMT */ - struct { - u32 _addr; /* faulting insn/memory ref. */ - int _trapno; - } _sigfault; - - /* SIGPOLL */ - struct { - int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ - int _fd; - } _sigpoll; - } _sifields; -} compat_siginfo_t; - #define COMPAT_OFF_T_MAX 0x7fffffff /* diff --git a/arch/tile/include/asm/compat.h b/arch/tile/include/asm/compat.h index 59ab9fa784b3..c6b7613256b4 100644 --- a/arch/tile/include/asm/compat.h +++ b/arch/tile/include/asm/compat.h @@ -110,66 +110,8 @@ struct compat_flock64 { typedef u32 compat_sigset_word; -typedef union compat_sigval { - compat_int_t sival_int; - compat_uptr_t sival_ptr; -} compat_sigval_t; - #define COMPAT_SI_PAD_SIZE (128/sizeof(int) - 3) -typedef struct compat_siginfo { - int si_signo; - int si_errno; - int si_code; - - union { - int _pad[COMPAT_SI_PAD_SIZE]; - - /* kill() */ - struct { - unsigned int _pid; /* sender's pid */ - unsigned int _uid; /* sender's uid */ - } _kill; - - /* POSIX.1b timers */ - struct { - compat_timer_t _tid; /* timer id */ - int _overrun; /* overrun count */ - compat_sigval_t _sigval; /* same as below */ - } _timer; - - /* POSIX.1b signals */ - struct { - unsigned int _pid; /* sender's pid */ - unsigned int _uid; /* sender's uid */ - compat_sigval_t _sigval; - } _rt; - - /* SIGCHLD */ - struct { - unsigned int _pid; /* which child */ - unsigned int _uid; /* sender's uid */ - int _status; /* exit code */ - compat_clock_t _utime; - compat_clock_t _stime; - } _sigchld; - - /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ - struct { - unsigned int _addr; /* faulting insn/memory ref. */ -#ifdef __ARCH_SI_TRAPNO - int _trapno; /* TRAP # which caused the signal */ -#endif - } _sigfault; - - /* SIGPOLL */ - struct { - int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ - int _fd; - } _sigpoll; - } _sifields; -} compat_siginfo_t; - #define COMPAT_OFF_T_MAX 0x7fffffff struct compat_ipc64_perm { diff --git a/arch/x86/include/asm/compat.h b/arch/x86/include/asm/compat.h index 1b6886a78562..0b76fc91f672 100644 --- a/arch/x86/include/asm/compat.h +++ b/arch/x86/include/asm/compat.h @@ -127,86 +127,6 @@ typedef u32 compat_old_sigset_t; /* at least 32 bits */ typedef u32 compat_sigset_word; -typedef union compat_sigval { - compat_int_t sival_int; - compat_uptr_t sival_ptr; -} compat_sigval_t; - -typedef struct compat_siginfo { - int si_signo; - int si_errno; - int si_code; - - union { - int _pad[128/sizeof(int) - 3]; - - /* kill() */ - struct { - unsigned int _pid; /* sender's pid */ - unsigned int _uid; /* sender's uid */ - } _kill; - - /* POSIX.1b timers */ - struct { - compat_timer_t _tid; /* timer id */ - int _overrun; /* overrun count */ - compat_sigval_t _sigval; /* same as below */ - } _timer; - - /* POSIX.1b signals */ - struct { - unsigned int _pid; /* sender's pid */ - unsigned int _uid; /* sender's uid */ - compat_sigval_t _sigval; - } _rt; - - /* SIGCHLD */ - struct { - unsigned int _pid; /* which child */ - unsigned int _uid; /* sender's uid */ - int _status; /* exit code */ - compat_clock_t _utime; - compat_clock_t _stime; - } _sigchld; - - /* SIGCHLD (x32 version) */ - struct { - unsigned int _pid; /* which child */ - unsigned int _uid; /* sender's uid */ - int _status; /* exit code */ - compat_s64 _utime; - compat_s64 _stime; - } _sigchld_x32; - - /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ - struct { - unsigned int _addr; /* faulting insn/memory ref. */ - short int _addr_lsb; /* Valid LSB of the reported address. */ - union { - /* used when si_code=SEGV_BNDERR */ - struct { - compat_uptr_t _lower; - compat_uptr_t _upper; - } _addr_bnd; - /* used when si_code=SEGV_PKUERR */ - compat_u32 _pkey; - }; - } _sigfault; - - /* SIGPOLL */ - struct { - int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ - int _fd; - } _sigpoll; - - struct { - unsigned int _call_addr; /* calling insn */ - int _syscall; /* triggering system call number */ - unsigned int _arch; /* AUDIT_ARCH_* of syscall */ - } _sigsys; - } _sifields; -} compat_siginfo_t; - #define COMPAT_OFF_T_MAX 0x7fffffff struct compat_ipc64_perm { diff --git a/arch/x86/kernel/signal_compat.c b/arch/x86/kernel/signal_compat.c index 85425ea30661..27495909932d 100644 --- a/arch/x86/kernel/signal_compat.c +++ b/arch/x86/kernel/signal_compat.c @@ -75,9 +75,11 @@ static inline void signal_compat_build_tests(void) CHECK_CSI_SIZE (_sigchld, 5*sizeof(int)); CHECK_SI_SIZE (_sigchld, 8*sizeof(int)); +#ifdef CONFIG_X86_X32_ABI CHECK_CSI_OFFSET(_sigchld_x32); CHECK_CSI_SIZE (_sigchld_x32, 7*sizeof(int)); /* no _sigchld_x32 in the generic siginfo_t */ +#endif CHECK_CSI_OFFSET(_sigfault); CHECK_CSI_SIZE (_sigfault, 4*sizeof(int)); @@ -169,9 +171,11 @@ int __copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from, if (!x32_ABI) { put_user_ex(from->si_utime, &to->si_utime); put_user_ex(from->si_stime, &to->si_stime); +#ifdef CONFIG_X86_X32_ABI } else { put_user_ex(from->si_utime, &to->_sifields._sigchld_x32._utime); put_user_ex(from->si_stime, &to->_sifields._sigchld_x32._stime); +#endif } put_user_ex(from->si_status, &to->si_status); /* FALL THROUGH */ diff --git a/include/linux/compat.h b/include/linux/compat.h index 0fc36406f32c..8f8e3ef247de 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -157,6 +157,96 @@ struct compat_sigaction { compat_sigset_t sa_mask __packed; }; +typedef union compat_sigval { + compat_int_t sival_int; + compat_uptr_t sival_ptr; +} compat_sigval_t; + +typedef struct compat_siginfo { + int si_signo; +#ifndef __ARCH_HAS_SWAPPED_SIGINFO + int si_errno; + int si_code; +#else + int si_code; + int si_errno; +#endif + + union { + int _pad[128/sizeof(int) - 3]; + + /* kill() */ + struct { + compat_pid_t _pid; /* sender's pid */ + __compat_uid32_t _uid; /* sender's uid */ + } _kill; + + /* POSIX.1b timers */ + struct { + compat_timer_t _tid; /* timer id */ + int _overrun; /* overrun count */ + compat_sigval_t _sigval; /* same as below */ + } _timer; + + /* POSIX.1b signals */ + struct { + compat_pid_t _pid; /* sender's pid */ + __compat_uid32_t _uid; /* sender's uid */ + compat_sigval_t _sigval; + } _rt; + + /* SIGCHLD */ + struct { + compat_pid_t _pid; /* which child */ + __compat_uid32_t _uid; /* sender's uid */ + int _status; /* exit code */ + compat_clock_t _utime; + compat_clock_t _stime; + } _sigchld; + +#ifdef CONFIG_X86_X32_ABI + /* SIGCHLD (x32 version) */ + struct { + compat_pid_t _pid; /* which child */ + __compat_uid32_t _uid; /* sender's uid */ + int _status; /* exit code */ + compat_s64 _utime; + compat_s64 _stime; + } _sigchld_x32; +#endif + + /* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGTRAP, SIGEMT */ + struct { + compat_uptr_t _addr; /* faulting insn/memory ref. */ +#ifdef __ARCH_SI_TRAPNO + int _trapno; /* TRAP # which caused the signal */ +#endif + short int _addr_lsb; /* Valid LSB of the reported address. */ + union { + /* used when si_code=SEGV_BNDERR */ + struct { + compat_uptr_t _lower; + compat_uptr_t _upper; + } _addr_bnd; + /* used when si_code=SEGV_PKUERR */ + u32 _pkey; + }; + } _sigfault; + + /* SIGPOLL */ + struct { + compat_long_t _band; /* POLL_IN, POLL_OUT, POLL_MSG */ + int _fd; + } _sigpoll; + + struct { + compat_uptr_t _call_addr; /* calling user insn */ + int _syscall; /* triggering system call number */ + unsigned int _arch; /* AUDIT_ARCH_* of syscall */ + } _sigsys; + } _sifields; +} compat_siginfo_t; + /* * These functions operate on 32- or 64-bit specs depending on * COMPAT_USE_64BIT_TIME, hence the void user pointer arguments. -- cgit v1.2.3 From 212a36a17efe4d696d1e3c31ebd79a9fb0cbb14b Mon Sep 17 00:00:00 2001 From: Eric W. Biederman Date: Mon, 31 Jul 2017 17:15:31 -0500 Subject: signal: Unify and correct copy_siginfo_from_user32 The function copy_siginfo_from_user32 is used for two things, in ptrace since the dawn of siginfo for arbirarily modifying a signal that user space sees, and in sigqueueinfo to send a signal with arbirary siginfo data. Create a single copy of copy_siginfo_from_user32 that all architectures share, and teach it to handle all of the cases in the siginfo union. In the generic version of copy_siginfo_from_user32 ensure that all of the fields in siginfo are initialized so that the siginfo structure can be safely copied to userspace if necessary. When copying the embedded sigval union copy the si_int member. That ensures the 32bit values passes through the kernel unchanged. Signed-off-by: "Eric W. Biederman" --- arch/arm64/kernel/signal32.c | 10 ----- arch/mips/kernel/signal32.c | 10 ----- arch/parisc/kernel/signal32.c | 44 ---------------------- arch/parisc/kernel/signal32.h | 1 - arch/powerpc/kernel/signal_32.c | 9 ----- arch/s390/kernel/compat_signal.c | 48 ------------------------ arch/sparc/kernel/signal32.c | 16 -------- arch/tile/kernel/compat_signal.c | 18 --------- arch/x86/kernel/signal_compat.c | 21 ----------- include/linux/compat.h | 2 +- kernel/signal.c | 81 ++++++++++++++++++++++++++++++++++++++++ 11 files changed, 82 insertions(+), 178 deletions(-) (limited to 'arch/mips') diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c index 22711ee8e36c..4377907dbb70 100644 --- a/arch/arm64/kernel/signal32.c +++ b/arch/arm64/kernel/signal32.c @@ -195,16 +195,6 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) return err; } -int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) -{ - if (copy_from_user(to, from, __ARCH_SI_PREAMBLE_SIZE) || - copy_from_user(to->_sifields._pad, - from->_sifields._pad, SI_PAD_SIZE)) - return -EFAULT; - - return 0; -} - /* * VFP save/restore code. * diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index cf5c7c05e5a3..500b5e4634ea 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -133,13 +133,3 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) } return err; } - -int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) -{ - if (copy_from_user(to, from, 3*sizeof(int)) || - copy_from_user(to->_sifields._pad, - from->_sifields._pad, SI_PAD_SIZE32)) - return -EFAULT; - - return 0; -} diff --git a/arch/parisc/kernel/signal32.c b/arch/parisc/kernel/signal32.c index 41afa9cd1f55..558e32475c35 100644 --- a/arch/parisc/kernel/signal32.c +++ b/arch/parisc/kernel/signal32.c @@ -261,50 +261,6 @@ setup_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __ return err; } -int -copy_siginfo_from_user32 (siginfo_t *to, compat_siginfo_t __user *from) -{ - compat_uptr_t addr; - int err; - - if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t))) - return -EFAULT; - - err = __get_user(to->si_signo, &from->si_signo); - err |= __get_user(to->si_errno, &from->si_errno); - err |= __get_user(to->si_code, &from->si_code); - - if (to->si_code < 0) - err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); - else { - switch (siginfo_layout(to->si_signo, to->si_code)) { - case SIL_CHLD: - err |= __get_user(to->si_utime, &from->si_utime); - err |= __get_user(to->si_stime, &from->si_stime); - err |= __get_user(to->si_status, &from->si_status); - default: - case SIL_KILL: - err |= __get_user(to->si_pid, &from->si_pid); - err |= __get_user(to->si_uid, &from->si_uid); - break; - case SIL_FAULT: - err |= __get_user(addr, &from->si_addr); - to->si_addr = compat_ptr(addr); - break; - case SIL_POLL: - err |= __get_user(to->si_band, &from->si_band); - err |= __get_user(to->si_fd, &from->si_fd); - break; - case SIL_RT: - err |= __get_user(to->si_pid, &from->si_pid); - err |= __get_user(to->si_uid, &from->si_uid); - err |= __get_user(to->si_int, &from->si_int); - break; - } - } - return err; -} - int copy_siginfo_to_user32 (compat_siginfo_t __user *to, const siginfo_t *from) { diff --git a/arch/parisc/kernel/signal32.h b/arch/parisc/kernel/signal32.h index 719e7417732c..d25858e4db63 100644 --- a/arch/parisc/kernel/signal32.h +++ b/arch/parisc/kernel/signal32.h @@ -35,7 +35,6 @@ struct compat_ucontext { /* ELF32 signal handling */ int copy_siginfo_to_user32 (compat_siginfo_t __user *to, const siginfo_t *from); -int copy_siginfo_from_user32 (siginfo_t *to, compat_siginfo_t __user *from); /* In a deft move of uber-hackery, we decide to carry the top half of all * 64-bit registers in a non-portable, non-ABI, hidden structure. diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 9ffd73296f64..ee62ff7b296c 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -933,15 +933,6 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *d, const siginfo_t *s) #define copy_siginfo_to_user copy_siginfo_to_user32 -int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from) -{ - if (copy_from_user(to, from, 3*sizeof(int)) || - copy_from_user(to->_sifields._pad, - from->_sifields._pad, SI_PAD_SIZE32)) - return -EFAULT; - - return 0; -} #endif /* CONFIG_PPC64 */ /* diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c index ef246940b44c..d77ce14ffa5c 100644 --- a/arch/s390/kernel/compat_signal.c +++ b/arch/s390/kernel/compat_signal.c @@ -102,54 +102,6 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) return err ? -EFAULT : 0; } -int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) -{ - int err; - u32 tmp; - - err = __get_user(to->si_signo, &from->si_signo); - err |= __get_user(to->si_errno, &from->si_errno); - err |= __get_user(to->si_code, &from->si_code); - - if (to->si_code < 0) - err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); - else { - switch (siginfo_layout(to->si_signo, to->si_code)) { - case SIL_RT: - err |= __get_user(to->si_int, &from->si_int); - /* fallthrough */ - case SIL_KILL: - err |= __get_user(to->si_pid, &from->si_pid); - err |= __get_user(to->si_uid, &from->si_uid); - break; - case SIL_CHLD: - err |= __get_user(to->si_pid, &from->si_pid); - err |= __get_user(to->si_uid, &from->si_uid); - err |= __get_user(to->si_utime, &from->si_utime); - err |= __get_user(to->si_stime, &from->si_stime); - err |= __get_user(to->si_status, &from->si_status); - break; - case SIL_FAULT: - err |= __get_user(tmp, &from->si_addr); - to->si_addr = (void __force __user *) - (u64) (tmp & PSW32_ADDR_INSN); - break; - case SIL_POLL: - err |= __get_user(to->si_band, &from->si_band); - err |= __get_user(to->si_fd, &from->si_fd); - break; - case SIL_TIMER: - err |= __get_user(to->si_tid, &from->si_tid); - err |= __get_user(to->si_overrun, &from->si_overrun); - err |= __get_user(to->si_int, &from->si_int); - break; - default: - break; - } - } - return err ? -EFAULT : 0; -} - /* Store registers needed to create the signal frame */ static void store_sigregs(void) { diff --git a/arch/sparc/kernel/signal32.c b/arch/sparc/kernel/signal32.c index 54a6159b9cd8..8022bb4c65a5 100644 --- a/arch/sparc/kernel/signal32.c +++ b/arch/sparc/kernel/signal32.c @@ -123,22 +123,6 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) return err; } -/* CAUTION: This is just a very minimalist implementation for the - * sake of compat_sys_rt_sigqueueinfo() - */ -int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) -{ - if (!access_ok(VERIFY_WRITE, from, sizeof(compat_siginfo_t))) - return -EFAULT; - - if (copy_from_user(to, from, 3*sizeof(int)) || - copy_from_user(to->_sifields._pad, from->_sifields._pad, - SI_PAD_SIZE)) - return -EFAULT; - - return 0; -} - /* Checks if the fp is valid. We always build signal frames which are * 16-byte aligned, therefore we can always enforce that the restore * frame has that property as well. diff --git a/arch/tile/kernel/compat_signal.c b/arch/tile/kernel/compat_signal.c index 971d87a1d8cf..4e7f40a10eb3 100644 --- a/arch/tile/kernel/compat_signal.c +++ b/arch/tile/kernel/compat_signal.c @@ -105,24 +105,6 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *to, const siginfo_t *fr return err; } -int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from) -{ - int err; - - if (!access_ok(VERIFY_READ, from, sizeof(struct compat_siginfo))) - return -EFAULT; - - err = __get_user(to->si_signo, &from->si_signo); - err |= __get_user(to->si_errno, &from->si_errno); - err |= __get_user(to->si_code, &from->si_code); - - err |= __get_user(to->si_pid, &from->si_pid); - err |= __get_user(to->si_uid, &from->si_uid); - err |= __get_user(to->si_int, &from->si_int); - - return err; -} - /* The assembly shim for this function arranges to ignore the return value. */ long compat_sys_rt_sigreturn(void) { diff --git a/arch/x86/kernel/signal_compat.c b/arch/x86/kernel/signal_compat.c index feb3ac135d0c..59148de2d83f 100644 --- a/arch/x86/kernel/signal_compat.c +++ b/arch/x86/kernel/signal_compat.c @@ -207,24 +207,3 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) return __copy_siginfo_to_user32(to, from, in_x32_syscall()); } -int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) -{ - int err = 0; - u32 ptr32; - - if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t))) - return -EFAULT; - - get_user_try { - get_user_ex(to->si_signo, &from->si_signo); - get_user_ex(to->si_errno, &from->si_errno); - get_user_ex(to->si_code, &from->si_code); - - get_user_ex(to->si_pid, &from->si_pid); - get_user_ex(to->si_uid, &from->si_uid); - get_user_ex(ptr32, &from->si_ptr); - to->si_ptr = compat_ptr(ptr32); - } get_user_catch(err); - - return err; -} diff --git a/include/linux/compat.h b/include/linux/compat.h index e698ec1908d9..8a9643857c4a 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -510,7 +510,7 @@ long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask, unsigned long bitmap_size); long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask, unsigned long bitmap_size); -int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from); +int copy_siginfo_from_user32(siginfo_t *to, const struct compat_siginfo __user *from); int copy_siginfo_to_user32(struct compat_siginfo __user *to, const siginfo_t *from); int get_compat_sigevent(struct sigevent *event, const struct compat_sigevent __user *u_event); diff --git a/kernel/signal.c b/kernel/signal.c index 4c3f4448c5f1..5211b1b57163 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -2814,6 +2814,87 @@ int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from) return err; } +#ifdef CONFIG_COMPAT +int copy_siginfo_from_user32(struct siginfo *to, + const struct compat_siginfo __user *ufrom) +{ + struct compat_siginfo from; + + if (copy_from_user(&from, ufrom, sizeof(struct compat_siginfo))) + return -EFAULT; + + clear_siginfo(to); + to->si_signo = from.si_signo; + to->si_errno = from.si_errno; + to->si_code = from.si_code; + switch(siginfo_layout(from.si_signo, from.si_code)) { + case SIL_KILL: + to->si_pid = from.si_pid; + to->si_uid = from.si_uid; + break; + case SIL_TIMER: + to->si_tid = from.si_tid; + to->si_overrun = from.si_overrun; + to->si_int = from.si_int; + break; + case SIL_POLL: + to->si_band = from.si_band; + to->si_fd = from.si_fd; + break; + case SIL_FAULT: + to->si_addr = compat_ptr(from.si_addr); +#ifdef __ARCH_SI_TRAPNO + to->si_trapno = from.si_trapno; +#endif +#ifdef BUS_MCEERR_AR + if ((from.si_signo == SIGBUS) && (from.si_code == BUS_MCEERR_AR)) + to->si_addr_lsb = from.si_addr_lsb; +#endif +#ifdef BUS_MCEER_AO + if ((from.si_signo == SIGBUS) && (from.si_code == BUS_MCEERR_AO)) + to->si_addr_lsb = from.si_addr_lsb; +#endif +#ifdef SEGV_BNDERR + if ((from.si_signo == SIGSEGV) && (from.si_code == SEGV_BNDERR)) { + to->si_lower = compat_ptr(from.si_lower); + to->si_upper = compat_ptr(from.si_upper); + } +#endif +#ifdef SEGV_PKUERR + if ((from.si_signo == SIGSEGV) && (from.si_code == SEGV_PKUERR)) + to->si_pkey = from.si_pkey; +#endif + break; + case SIL_CHLD: + to->si_pid = from.si_pid; + to->si_uid = from.si_uid; + to->si_status = from.si_status; +#ifdef CONFIG_X86_X32_ABI + if (in_x32_syscall()) { + to->si_utime = from._sifields._sigchld_x32._utime; + to->si_stime = from._sifields._sigchld_x32._stime; + } else +#endif + { + to->si_utime = from.si_utime; + to->si_stime = from.si_stime; + } + break; + case SIL_RT: + to->si_pid = from.si_pid; + to->si_uid = from.si_uid; + to->si_int = from.si_int; + break; + case SIL_SYS: + to->si_call_addr = compat_ptr(from.si_call_addr); + to->si_syscall = from.si_syscall; + to->si_arch = from.si_arch; + break; + } + return 0; +} +#endif /* CONFIG_COMPAT */ + /** * do_sigtimedwait - wait for queued signals specified in @which * @which: queued signals to wait for -- cgit v1.2.3 From ea64d5acc8f033cd586182ae31531246cdeaea73 Mon Sep 17 00:00:00 2001 From: Eric W. Biederman Date: Mon, 15 Jan 2018 18:03:33 -0600 Subject: signal: Unify and correct copy_siginfo_to_user32 Among the existing architecture specific versions of copy_siginfo_to_user32 there are several different implementation problems. Some architectures fail to handle all of the cases in in the siginfo union. Some architectures perform a blind copy of the siginfo union when the si_code is negative. A blind copy suggests the data is expected to be in 32bit siginfo format, which means that receiving such a signal via signalfd won't work, or that the data is in 64bit siginfo and the code is copying nonsense to userspace. Create a single instance of copy_siginfo_to_user32 that all of the architectures can share, and teach it to handle all of the cases in the siginfo union correctly, with the assumption that siginfo is stored internally to the kernel is 64bit siginfo format. A special case is made for x86 x32 format. This is needed as presence of both x32 and ia32 on x86_64 results in two different 32bit signal formats. By allowing this small special case there winds up being exactly one code base that needs to be maintained between all of the architectures. Vastly increasing the testing base and the chances of finding bugs. As the x86 copy of copy_siginfo_to_user32 the call of the x86 signal_compat_build_tests were moved into sigaction_compat_abi, so that they will keep running. Signed-off-by: "Eric W. Biederman" --- arch/arm64/kernel/signal32.c | 70 ---------------------------- arch/mips/include/asm/compat.h | 2 - arch/mips/kernel/signal32.c | 57 ----------------------- arch/parisc/kernel/signal32.c | 62 ------------------------- arch/parisc/kernel/signal32.h | 2 - arch/powerpc/include/asm/compat.h | 2 - arch/powerpc/kernel/signal_32.c | 57 ----------------------- arch/s390/kernel/compat_signal.c | 52 --------------------- arch/sparc/include/asm/compat.h | 2 - arch/sparc/kernel/signal32.c | 53 --------------------- arch/tile/include/asm/compat.h | 2 - arch/tile/kernel/compat_signal.c | 55 ---------------------- arch/x86/include/asm/compat.h | 4 ++ arch/x86/include/asm/fpu/signal.h | 6 --- arch/x86/kernel/signal_compat.c | 96 +-------------------------------------- kernel/signal.c | 90 ++++++++++++++++++++++++++++++++++++ 16 files changed, 96 insertions(+), 516 deletions(-) (limited to 'arch/mips') diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c index 4377907dbb70..cbc4edd1b1eb 100644 --- a/arch/arm64/kernel/signal32.c +++ b/arch/arm64/kernel/signal32.c @@ -125,76 +125,6 @@ static inline int get_sigset_t(sigset_t *set, return 0; } -int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) -{ - int err; - - if (!access_ok(VERIFY_WRITE, to, sizeof(*to))) - return -EFAULT; - - /* If you change siginfo_t structure, please be sure - * this code is fixed accordingly. - * It should never copy any pad contained in the structure - * to avoid security leaks, but must copy the generic - * 3 ints plus the relevant union member. - * This routine must convert siginfo from 64bit to 32bit as well - * at the same time. - */ - err = __put_user(from->si_signo, &to->si_signo); - err |= __put_user(from->si_errno, &to->si_errno); - err |= __put_user(from->si_code, &to->si_code); - if (from->si_code < 0) - err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, - SI_PAD_SIZE); - else switch (siginfo_layout(from->si_signo, from->si_code)) { - case SIL_KILL: - err |= __put_user(from->si_pid, &to->si_pid); - err |= __put_user(from->si_uid, &to->si_uid); - break; - case SIL_TIMER: - err |= __put_user(from->si_tid, &to->si_tid); - err |= __put_user(from->si_overrun, &to->si_overrun); - err |= __put_user(from->si_int, &to->si_int); - break; - case SIL_POLL: - err |= __put_user(from->si_band, &to->si_band); - err |= __put_user(from->si_fd, &to->si_fd); - break; - case SIL_FAULT: - err |= __put_user((compat_uptr_t)(unsigned long)from->si_addr, - &to->si_addr); -#ifdef BUS_MCEERR_AO - /* - * Other callers might not initialize the si_lsb field, - * so check explicitly for the right codes here. - */ - if (from->si_signo == SIGBUS && - (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO)) - err |= __put_user(from->si_addr_lsb, &to->si_addr_lsb); -#endif - break; - case SIL_CHLD: - err |= __put_user(from->si_pid, &to->si_pid); - err |= __put_user(from->si_uid, &to->si_uid); - err |= __put_user(from->si_status, &to->si_status); - err |= __put_user(from->si_utime, &to->si_utime); - err |= __put_user(from->si_stime, &to->si_stime); - break; - case SIL_RT: - err |= __put_user(from->si_pid, &to->si_pid); - err |= __put_user(from->si_uid, &to->si_uid); - err |= __put_user(from->si_int, &to->si_int); - break; - case SIL_SYS: - err |= __put_user((compat_uptr_t)(unsigned long) - from->si_call_addr, &to->si_call_addr); - err |= __put_user(from->si_syscall, &to->si_syscall); - err |= __put_user(from->si_arch, &to->si_arch); - break; - } - return err; -} - /* * VFP save/restore code. * diff --git a/arch/mips/include/asm/compat.h b/arch/mips/include/asm/compat.h index fe7d445f675f..946681db8dc3 100644 --- a/arch/mips/include/asm/compat.h +++ b/arch/mips/include/asm/compat.h @@ -126,8 +126,6 @@ typedef u32 compat_old_sigset_t; /* at least 32 bits */ typedef u32 compat_sigset_word; -#define SI_PAD_SIZE32 (128/sizeof(int) - 3) - #define COMPAT_OFF_T_MAX 0x7fffffff /* diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 500b5e4634ea..c4db910a8794 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -76,60 +76,3 @@ SYSCALL_DEFINE3(32_sigaction, long, sig, const struct compat_sigaction __user *, return ret; } - -int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) -{ - int err; - - if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t))) - return -EFAULT; - - /* If you change siginfo_t structure, please be sure - this code is fixed accordingly. - It should never copy any pad contained in the structure - to avoid security leaks, but must copy the generic - 3 ints plus the relevant union member. - This routine must convert siginfo from 64bit to 32bit as well - at the same time. */ - err = __put_user(from->si_signo, &to->si_signo); - err |= __put_user(from->si_errno, &to->si_errno); - err |= __put_user(from->si_code, &to->si_code); - if (from->si_code < 0) - err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); - else { - switch (siginfo_layout(from->si_signo, from->si_code)) { - case SIL_TIMER: - err |= __put_user(from->si_tid, &to->si_tid); - err |= __put_user(from->si_overrun, &to->si_overrun); - err |= __put_user(from->si_int, &to->si_int); - break; - case SIL_CHLD: - err |= __put_user(from->si_utime, &to->si_utime); - err |= __put_user(from->si_stime, &to->si_stime); - err |= __put_user(from->si_status, &to->si_status); - case SIL_KILL: - err |= __put_user(from->si_pid, &to->si_pid); - err |= __put_user(from->si_uid, &to->si_uid); - break; - case SIL_FAULT: - err |= __put_user((unsigned long)from->si_addr, &to->si_addr); - break; - case SIL_POLL: - err |= __put_user(from->si_band, &to->si_band); - err |= __put_user(from->si_fd, &to->si_fd); - break; - case SIL_RT: - err |= __put_user(from->si_pid, &to->si_pid); - err |= __put_user(from->si_uid, &to->si_uid); - err |= __put_user(from->si_int, &to->si_int); - break; - case SIL_SYS: - err |= __copy_to_user(&to->si_call_addr, &from->si_call_addr, - sizeof(compat_uptr_t)); - err |= __put_user(from->si_syscall, &to->si_syscall); - err |= __put_user(from->si_arch, &to->si_arch); - break; - } - } - return err; -} diff --git a/arch/parisc/kernel/signal32.c b/arch/parisc/kernel/signal32.c index 558e32475c35..e8ef3eb69449 100644 --- a/arch/parisc/kernel/signal32.c +++ b/arch/parisc/kernel/signal32.c @@ -260,65 +260,3 @@ setup_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __ return err; } - -int -copy_siginfo_to_user32 (compat_siginfo_t __user *to, const siginfo_t *from) -{ - compat_uptr_t addr; - compat_int_t val; - int err; - - if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t))) - return -EFAULT; - - /* If you change siginfo_t structure, please be sure - this code is fixed accordingly. - It should never copy any pad contained in the structure - to avoid security leaks, but must copy the generic - 3 ints plus the relevant union member. - This routine must convert siginfo from 64bit to 32bit as well - at the same time. */ - err = __put_user(from->si_signo, &to->si_signo); - err |= __put_user(from->si_errno, &to->si_errno); - err |= __put_user(from->si_code, &to->si_code); - if (from->si_code < 0) - err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); - else { - switch (siginfo_layout(from->si_signo, from->si_code)) { - case SIL_CHLD: - err |= __put_user(from->si_utime, &to->si_utime); - err |= __put_user(from->si_stime, &to->si_stime); - err |= __put_user(from->si_status, &to->si_status); - case SIL_KILL: - err |= __put_user(from->si_pid, &to->si_pid); - err |= __put_user(from->si_uid, &to->si_uid); - break; - case SIL_FAULT: - addr = ptr_to_compat(from->si_addr); - err |= __put_user(addr, &to->si_addr); - break; - case SIL_POLL: - err |= __put_user(from->si_band, &to->si_band); - err |= __put_user(from->si_fd, &to->si_fd); - break; - case SIL_TIMER: - err |= __put_user(from->si_tid, &to->si_tid); - err |= __put_user(from->si_overrun, &to->si_overrun); - val = (compat_int_t)from->si_int; - err |= __put_user(val, &to->si_int); - break; - case SIL_RT: - err |= __put_user(from->si_uid, &to->si_uid); - err |= __put_user(from->si_pid, &to->si_pid); - val = (compat_int_t)from->si_int; - err |= __put_user(val, &to->si_int); - break; - case SIL_SYS: - err |= __put_user(ptr_to_compat(from->si_call_addr), &to->si_call_addr); - err |= __put_user(from->si_syscall, &to->si_syscall); - err |= __put_user(from->si_arch, &to->si_arch); - break; - } - } - return err; -} diff --git a/arch/parisc/kernel/signal32.h b/arch/parisc/kernel/signal32.h index d25858e4db63..a271dc0976ce 100644 --- a/arch/parisc/kernel/signal32.h +++ b/arch/parisc/kernel/signal32.h @@ -34,8 +34,6 @@ struct compat_ucontext { /* ELF32 signal handling */ -int copy_siginfo_to_user32 (compat_siginfo_t __user *to, const siginfo_t *from); - /* In a deft move of uber-hackery, we decide to carry the top half of all * 64-bit registers in a non-portable, non-ABI, hidden structure. * Userspace can read the hidden structure if it *wants* but is never diff --git a/arch/powerpc/include/asm/compat.h b/arch/powerpc/include/asm/compat.h index 8a2363221b0c..62168e1158f1 100644 --- a/arch/powerpc/include/asm/compat.h +++ b/arch/powerpc/include/asm/compat.h @@ -119,8 +119,6 @@ typedef u32 compat_old_sigset_t; typedef u32 compat_sigset_word; -#define SI_PAD_SIZE32 (128/sizeof(int) - 3) - #define COMPAT_OFF_T_MAX 0x7fffffff /* diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index ee62ff7b296c..aded81169648 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -873,63 +873,6 @@ static long restore_tm_user_regs(struct pt_regs *regs, #endif #ifdef CONFIG_PPC64 -int copy_siginfo_to_user32(struct compat_siginfo __user *d, const siginfo_t *s) -{ - int err; - - if (!access_ok (VERIFY_WRITE, d, sizeof(*d))) - return -EFAULT; - - /* If you change siginfo_t structure, please be sure - * this code is fixed accordingly. - * It should never copy any pad contained in the structure - * to avoid security leaks, but must copy the generic - * 3 ints plus the relevant union member. - * This routine must convert siginfo from 64bit to 32bit as well - * at the same time. - */ - err = __put_user(s->si_signo, &d->si_signo); - err |= __put_user(s->si_errno, &d->si_errno); - err |= __put_user(s->si_code, &d->si_code); - if (s->si_code < 0) - err |= __copy_to_user(&d->_sifields._pad, &s->_sifields._pad, - SI_PAD_SIZE32); - else switch(siginfo_layout(s->si_signo, s->si_code)) { - case SIL_CHLD: - err |= __put_user(s->si_pid, &d->si_pid); - err |= __put_user(s->si_uid, &d->si_uid); - err |= __put_user(s->si_utime, &d->si_utime); - err |= __put_user(s->si_stime, &d->si_stime); - err |= __put_user(s->si_status, &d->si_status); - break; - case SIL_FAULT: - err |= __put_user((unsigned int)(unsigned long)s->si_addr, - &d->si_addr); - break; - case SIL_POLL: - err |= __put_user(s->si_band, &d->si_band); - err |= __put_user(s->si_fd, &d->si_fd); - break; - case SIL_TIMER: - err |= __put_user(s->si_tid, &d->si_tid); - err |= __put_user(s->si_overrun, &d->si_overrun); - err |= __put_user(s->si_int, &d->si_int); - break; - case SIL_SYS: - err |= __put_user(ptr_to_compat(s->si_call_addr), &d->si_call_addr); - err |= __put_user(s->si_syscall, &d->si_syscall); - err |= __put_user(s->si_arch, &d->si_arch); - break; - case SIL_RT: - err |= __put_user(s->si_int, &d->si_int); - /* fallthrough */ - case SIL_KILL: - err |= __put_user(s->si_pid, &d->si_pid); - err |= __put_user(s->si_uid, &d->si_uid); - break; - } - return err; -} #define copy_siginfo_to_user copy_siginfo_to_user32 diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c index d77ce14ffa5c..18c1eeb847b2 100644 --- a/arch/s390/kernel/compat_signal.c +++ b/arch/s390/kernel/compat_signal.c @@ -50,58 +50,6 @@ typedef struct struct ucontext32 uc; } rt_sigframe32; -int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) -{ - int err; - - /* If you change siginfo_t structure, please be sure - this code is fixed accordingly. - It should never copy any pad contained in the structure - to avoid security leaks, but must copy the generic - 3 ints plus the relevant union member. - This routine must convert siginfo from 64bit to 32bit as well - at the same time. */ - err = __put_user(from->si_signo, &to->si_signo); - err |= __put_user(from->si_errno, &to->si_errno); - err |= __put_user(from->si_code, &to->si_code); - if (from->si_code < 0) - err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); - else { - switch (siginfo_layout(from->si_signo, from->si_code)) { - case SIL_RT: - err |= __put_user(from->si_int, &to->si_int); - /* fallthrough */ - case SIL_KILL: - err |= __put_user(from->si_pid, &to->si_pid); - err |= __put_user(from->si_uid, &to->si_uid); - break; - case SIL_CHLD: - err |= __put_user(from->si_pid, &to->si_pid); - err |= __put_user(from->si_uid, &to->si_uid); - err |= __put_user(from->si_utime, &to->si_utime); - err |= __put_user(from->si_stime, &to->si_stime); - err |= __put_user(from->si_status, &to->si_status); - break; - case SIL_FAULT: - err |= __put_user((unsigned long) from->si_addr, - &to->si_addr); - break; - case SIL_POLL: - err |= __put_user(from->si_band, &to->si_band); - err |= __put_user(from->si_fd, &to->si_fd); - break; - case SIL_TIMER: - err |= __put_user(from->si_tid, &to->si_tid); - err |= __put_user(from->si_overrun, &to->si_overrun); - err |= __put_user(from->si_int, &to->si_int); - break; - default: - break; - } - } - return err ? -EFAULT : 0; -} - /* Store registers needed to create the signal frame */ static void store_sigregs(void) { diff --git a/arch/sparc/include/asm/compat.h b/arch/sparc/include/asm/compat.h index c3688ae98b90..615283e16f22 100644 --- a/arch/sparc/include/asm/compat.h +++ b/arch/sparc/include/asm/compat.h @@ -149,8 +149,6 @@ typedef u32 compat_old_sigset_t; typedef u32 compat_sigset_word; -#define SI_PAD_SIZE32 (128/sizeof(int) - 3) - #define COMPAT_OFF_T_MAX 0x7fffffff /* diff --git a/arch/sparc/kernel/signal32.c b/arch/sparc/kernel/signal32.c index 8022bb4c65a5..44d379db3f64 100644 --- a/arch/sparc/kernel/signal32.c +++ b/arch/sparc/kernel/signal32.c @@ -70,59 +70,6 @@ struct rt_signal_frame32 { /* __siginfo_rwin_t * */u32 rwin_save; } __attribute__((aligned(8))); -int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) -{ - int err; - - if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t))) - return -EFAULT; - - /* If you change siginfo_t structure, please be sure - this code is fixed accordingly. - It should never copy any pad contained in the structure - to avoid security leaks, but must copy the generic - 3 ints plus the relevant union member. - This routine must convert siginfo from 64bit to 32bit as well - at the same time. */ - err = __put_user(from->si_signo, &to->si_signo); - err |= __put_user(from->si_errno, &to->si_errno); - err |= __put_user(from->si_code, &to->si_code); - if (from->si_code < 0) - err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); - else { - switch (siginfo_layout(from->si_signo, from->si_code)) { - case SIL_TIMER: - err |= __put_user(from->si_tid, &to->si_tid); - err |= __put_user(from->si_overrun, &to->si_overrun); - err |= __put_user(from->si_int, &to->si_int); - break; - case SIL_CHLD: - err |= __put_user(from->si_utime, &to->si_utime); - err |= __put_user(from->si_stime, &to->si_stime); - err |= __put_user(from->si_status, &to->si_status); - default: - case SIL_KILL: - err |= __put_user(from->si_pid, &to->si_pid); - err |= __put_user(from->si_uid, &to->si_uid); - break; - case SIL_FAULT: - err |= __put_user(from->si_trapno, &to->si_trapno); - err |= __put_user((unsigned long)from->si_addr, &to->si_addr); - break; - case SIL_POLL: - err |= __put_user(from->si_band, &to->si_band); - err |= __put_user(from->si_fd, &to->si_fd); - break; - case SIL_RT: - err |= __put_user(from->si_pid, &to->si_pid); - err |= __put_user(from->si_uid, &to->si_uid); - err |= __put_user(from->si_int, &to->si_int); - break; - } - } - return err; -} - /* Checks if the fp is valid. We always build signal frames which are * 16-byte aligned, therefore we can always enforce that the restore * frame has that property as well. diff --git a/arch/tile/include/asm/compat.h b/arch/tile/include/asm/compat.h index c6b7613256b4..769ff6ac0bf5 100644 --- a/arch/tile/include/asm/compat.h +++ b/arch/tile/include/asm/compat.h @@ -110,8 +110,6 @@ struct compat_flock64 { typedef u32 compat_sigset_word; -#define COMPAT_SI_PAD_SIZE (128/sizeof(int) - 3) - #define COMPAT_OFF_T_MAX 0x7fffffff struct compat_ipc64_perm { diff --git a/arch/tile/kernel/compat_signal.c b/arch/tile/kernel/compat_signal.c index 4e7f40a10eb3..a703bd0e0488 100644 --- a/arch/tile/kernel/compat_signal.c +++ b/arch/tile/kernel/compat_signal.c @@ -50,61 +50,6 @@ struct compat_rt_sigframe { struct compat_ucontext uc; }; -int copy_siginfo_to_user32(struct compat_siginfo __user *to, const siginfo_t *from) -{ - int err; - - if (!access_ok(VERIFY_WRITE, to, sizeof(struct compat_siginfo))) - return -EFAULT; - - /* If you change siginfo_t structure, please make sure that - this code is fixed accordingly. - It should never copy any pad contained in the structure - to avoid security leaks, but must copy the generic - 3 ints plus the relevant union member. */ - err = __put_user(from->si_signo, &to->si_signo); - err |= __put_user(from->si_errno, &to->si_errno); - err |= __put_user(from->si_code, &to->si_code); - - if (from->si_code < 0) { - err |= __put_user(from->si_pid, &to->si_pid); - err |= __put_user(from->si_uid, &to->si_uid); - err |= __put_user(from->si_int, &to->si_int); - } else { - /* - * First 32bits of unions are always present: - * si_pid === si_band === si_tid === si_addr(LS half) - */ - err |= __put_user(from->_sifields._pad[0], - &to->_sifields._pad[0]); - switch (siginfo_layout(from->si_signo, from->si_code)) { - case SIL_FAULT: - break; - case SIL_CHLD: - err |= __put_user(from->si_utime, &to->si_utime); - err |= __put_user(from->si_stime, &to->si_stime); - err |= __put_user(from->si_status, &to->si_status); - /* FALL THROUGH */ - default: - case SIL_KILL: - err |= __put_user(from->si_uid, &to->si_uid); - break; - case SIL_POLL: - err |= __put_user(from->si_fd, &to->si_fd); - break; - case SIL_TIMER: - err |= __put_user(from->si_overrun, &to->si_overrun); - err |= __put_user(from->si_int, &to->si_int); - break; - case SIL_RT: - err |= __put_user(from->si_uid, &to->si_uid); - err |= __put_user(from->si_int, &to->si_int); - break; - } - } - return err; -} - /* The assembly shim for this function arranges to ignore the return value. */ long compat_sys_rt_sigreturn(void) { diff --git a/arch/x86/include/asm/compat.h b/arch/x86/include/asm/compat.h index 0b76fc91f672..e1c8dab86670 100644 --- a/arch/x86/include/asm/compat.h +++ b/arch/x86/include/asm/compat.h @@ -249,4 +249,8 @@ static inline bool in_compat_syscall(void) } #define in_compat_syscall in_compat_syscall /* override the generic impl */ +struct compat_siginfo; +int __copy_siginfo_to_user32(struct compat_siginfo __user *to, + const siginfo_t *from, bool x32_ABI); + #endif /* _ASM_X86_COMPAT_H */ diff --git a/arch/x86/include/asm/fpu/signal.h b/arch/x86/include/asm/fpu/signal.h index 4df2754ef380..44bbc39a57b3 100644 --- a/arch/x86/include/asm/fpu/signal.h +++ b/arch/x86/include/asm/fpu/signal.h @@ -20,12 +20,6 @@ int ia32_setup_frame(int sig, struct ksignal *ksig, # define ia32_setup_rt_frame __setup_rt_frame #endif -#ifdef CONFIG_COMPAT -int __copy_siginfo_to_user32(compat_siginfo_t __user *to, - const siginfo_t *from, bool x32_ABI); -#endif - - extern void convert_from_fxsr(struct user_i387_ia32_struct *env, struct task_struct *tsk); extern void convert_to_fxsr(struct task_struct *tsk, diff --git a/arch/x86/kernel/signal_compat.c b/arch/x86/kernel/signal_compat.c index 59148de2d83f..ac057f9b0763 100644 --- a/arch/x86/kernel/signal_compat.c +++ b/arch/x86/kernel/signal_compat.c @@ -98,6 +98,8 @@ static inline void signal_compat_build_tests(void) void sigaction_compat_abi(struct k_sigaction *act, struct k_sigaction *oact) { + signal_compat_build_tests(); + /* Don't leak in-kernel non-uapi flags to user-space */ if (oact) oact->sa.sa_flags &= ~(SA_IA32_ABI | SA_X32_ABI); @@ -113,97 +115,3 @@ void sigaction_compat_abi(struct k_sigaction *act, struct k_sigaction *oact) if (in_x32_syscall()) act->sa.sa_flags |= SA_X32_ABI; } - -int __copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from, - bool x32_ABI) -{ - int err = 0; - - signal_compat_build_tests(); - - if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t))) - return -EFAULT; - - put_user_try { - /* If you change siginfo_t structure, please make sure that - this code is fixed accordingly. - It should never copy any pad contained in the structure - to avoid security leaks, but must copy the generic - 3 ints plus the relevant union member. */ - put_user_ex(from->si_signo, &to->si_signo); - put_user_ex(from->si_errno, &to->si_errno); - put_user_ex(from->si_code, &to->si_code); - - if (from->si_code < 0) { - put_user_ex(from->si_pid, &to->si_pid); - put_user_ex(from->si_uid, &to->si_uid); - put_user_ex(ptr_to_compat(from->si_ptr), &to->si_ptr); - } else { - /* - * First 32bits of unions are always present: - * si_pid === si_band === si_tid === si_addr(LS half) - */ - put_user_ex(from->_sifields._pad[0], - &to->_sifields._pad[0]); - switch (siginfo_layout(from->si_signo, from->si_code)) { - case SIL_FAULT: - if (from->si_signo == SIGBUS && - (from->si_code == BUS_MCEERR_AR || - from->si_code == BUS_MCEERR_AO)) - put_user_ex(from->si_addr_lsb, &to->si_addr_lsb); - - if (from->si_signo == SIGSEGV) { - if (from->si_code == SEGV_BNDERR) { - compat_uptr_t lower = (unsigned long)from->si_lower; - compat_uptr_t upper = (unsigned long)from->si_upper; - put_user_ex(lower, &to->si_lower); - put_user_ex(upper, &to->si_upper); - } - if (from->si_code == SEGV_PKUERR) - put_user_ex(from->si_pkey, &to->si_pkey); - } - break; - case SIL_SYS: - put_user_ex(from->si_syscall, &to->si_syscall); - put_user_ex(from->si_arch, &to->si_arch); - break; - case SIL_CHLD: - if (!x32_ABI) { - put_user_ex(from->si_utime, &to->si_utime); - put_user_ex(from->si_stime, &to->si_stime); -#ifdef CONFIG_X86_X32_ABI - } else { - put_user_ex(from->si_utime, &to->_sifields._sigchld_x32._utime); - put_user_ex(from->si_stime, &to->_sifields._sigchld_x32._stime); -#endif - } - put_user_ex(from->si_status, &to->si_status); - /* FALL THROUGH */ - case SIL_KILL: - put_user_ex(from->si_uid, &to->si_uid); - break; - case SIL_POLL: - put_user_ex(from->si_fd, &to->si_fd); - break; - case SIL_TIMER: - put_user_ex(from->si_overrun, &to->si_overrun); - put_user_ex(ptr_to_compat(from->si_ptr), - &to->si_ptr); - break; - case SIL_RT: - put_user_ex(from->si_uid, &to->si_uid); - put_user_ex(from->si_int, &to->si_int); - break; - } - } - } put_user_catch(err); - - return err; -} - -/* from syscall's path, where we know the ABI */ -int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) -{ - return __copy_siginfo_to_user32(to, from, in_x32_syscall()); -} - diff --git a/kernel/signal.c b/kernel/signal.c index bebe44265b8b..4976f05aa09b 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -2815,6 +2815,96 @@ int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from) } #ifdef CONFIG_COMPAT +int copy_siginfo_to_user32(struct compat_siginfo __user *to, + const struct siginfo *from) +#if defined(CONFIG_X86_X32_ABI) || defined(CONFIG_IA32_EMULATION) +{ + return __copy_siginfo_to_user32(to, from, in_x32_syscall()); +} +int __copy_siginfo_to_user32(struct compat_siginfo __user *to, + const struct siginfo *from, bool x32_ABI) +#endif +{ + struct compat_siginfo new; + memset(&new, 0, sizeof(new)); + + new.si_signo = from->si_signo; + new.si_errno = from->si_errno; + new.si_code = from->si_code; + switch(siginfo_layout(from->si_signo, from->si_code)) { + case SIL_KILL: + new.si_pid = from->si_pid; + new.si_uid = from->si_uid; + break; + case SIL_TIMER: + new.si_tid = from->si_tid; + new.si_overrun = from->si_overrun; + new.si_int = from->si_int; + break; + case SIL_POLL: + new.si_band = from->si_band; + new.si_fd = from->si_fd; + break; + case SIL_FAULT: + new.si_addr = ptr_to_compat(from->si_addr); +#ifdef __ARCH_SI_TRAPNO + new.si_trapno = from->si_trapno; +#endif +#ifdef BUS_MCEERR_AR + if ((from->si_signo == SIGBUS) && (from->si_code == BUS_MCEERR_AR)) + new.si_addr_lsb = from->si_addr_lsb; +#endif +#ifdef BUS_MCEERR_AO + if ((from->si_signo == SIGBUS) && (from->si_code == BUS_MCEERR_AO)) + new.si_addr_lsb = from->si_addr_lsb; +#endif +#ifdef SEGV_BNDERR + if ((from->si_signo == SIGSEGV) && + (from->si_code == SEGV_BNDERR)) { + new.si_lower = ptr_to_compat(from->si_lower); + new.si_upper = ptr_to_compat(from->si_upper); + } +#endif +#ifdef SEGV_PKUERR + if ((from->si_signo == SIGSEGV) && + (from->si_code == SEGV_PKUERR)) + new.si_pkey = from->si_pkey; +#endif + + break; + case SIL_CHLD: + new.si_pid = from->si_pid; + new.si_uid = from->si_uid; + new.si_status = from->si_status; +#ifdef CONFIG_X86_X32_ABI + if (x32_ABI) { + new._sifields._sigchld_x32._utime = from->si_utime; + new._sifields._sigchld_x32._stime = from->si_stime; + } else +#endif + { + new.si_utime = from->si_utime; + new.si_stime = from->si_stime; + } + break; + case SIL_RT: + new.si_pid = from->si_pid; + new.si_uid = from->si_uid; + new.si_int = from->si_int; + break; + case SIL_SYS: + new.si_call_addr = ptr_to_compat(from->si_call_addr); + new.si_syscall = from->si_syscall; + new.si_arch = from->si_arch; + break; + } + + if (copy_to_user(to, &new, sizeof(struct compat_siginfo))) + return -EFAULT; + + return 0; +} + int copy_siginfo_from_user32(struct siginfo *to, const struct compat_siginfo __user *ufrom) { -- cgit v1.2.3 From 5f74972ce69fdc6473f74253283408af75a3be15 Mon Sep 17 00:00:00 2001 From: Eric W. Biederman Date: Mon, 22 Jan 2018 14:58:57 -0600 Subject: signal: Don't use structure initializers for struct siginfo The siginfo structure has all manners of holes with the result that a structure initializer is not guaranteed to initialize all of the bits. As we have to copy the structure to userspace don't even try to use a structure initializer. Instead use clear_siginfo followed by initializing selected fields. This gives a guarantee that uninitialized kernel memory is not copied to userspace. Signed-off-by: "Eric W. Biederman" --- arch/arc/kernel/traps.c | 14 +++++++----- arch/arm64/kernel/debug-monitors.c | 13 ++++++----- arch/arm64/kernel/ptrace.c | 13 ++++++----- arch/m68k/mm/fault.c | 3 ++- arch/mips/kernel/traps.c | 29 ++++++++++++++++-------- arch/tile/kernel/single_step.c | 24 +++++++++++--------- arch/tile/kernel/traps.c | 4 +++- arch/tile/kernel/unaligned.c | 46 +++++++++++++++++++++----------------- kernel/signal.c | 3 ++- 9 files changed, 89 insertions(+), 60 deletions(-) (limited to 'arch/mips') diff --git a/arch/arc/kernel/traps.c b/arch/arc/kernel/traps.c index bcd7c9fc5d0f..c7206789e9ce 100644 --- a/arch/arc/kernel/traps.c +++ b/arch/arc/kernel/traps.c @@ -65,12 +65,14 @@ unhandled_exception(const char *str, struct pt_regs *regs, siginfo_t *info) #define DO_ERROR_INFO(signr, str, name, sicode) \ int name(unsigned long address, struct pt_regs *regs) \ { \ - siginfo_t info = { \ - .si_signo = signr, \ - .si_errno = 0, \ - .si_code = sicode, \ - .si_addr = (void __user *)address, \ - }; \ + siginfo_t info; \ + \ + clear_siginfo(&info); \ + info.si_signo = signr; \ + info.si_errno = 0; \ + info.si_code = sicode; \ + info.si_addr = (void __user *)address; \ + \ return unhandled_exception(str, regs, &info);\ } diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c index a88b6ccebbb4..53781f5687c5 100644 --- a/arch/arm64/kernel/debug-monitors.c +++ b/arch/arm64/kernel/debug-monitors.c @@ -209,12 +209,13 @@ NOKPROBE_SYMBOL(call_step_hook); static void send_user_sigtrap(int si_code) { struct pt_regs *regs = current_pt_regs(); - siginfo_t info = { - .si_signo = SIGTRAP, - .si_errno = 0, - .si_code = si_code, - .si_addr = (void __user *)instruction_pointer(regs), - }; + siginfo_t info; + + clear_siginfo(&info); + info.si_signo = SIGTRAP; + info.si_errno = 0; + info.si_code = si_code; + info.si_addr = (void __user *)instruction_pointer(regs); if (WARN_ON(!user_mode(regs))) return; diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index 0a1cf830e4b3..95daa1478a7c 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -180,12 +180,13 @@ static void ptrace_hbptriggered(struct perf_event *bp, struct pt_regs *regs) { struct arch_hw_breakpoint *bkpt = counter_arch_bp(bp); - siginfo_t info = { - .si_signo = SIGTRAP, - .si_errno = 0, - .si_code = TRAP_HWBKPT, - .si_addr = (void __user *)(bkpt->trigger), - }; + siginfo_t info; + + clear_siginfo(&info); + info.si_signo = SIGTRAP; + info.si_errno = 0; + info.si_code = TRAP_HWBKPT; + info.si_addr = (void __user *)(bkpt->trigger); #ifdef CONFIG_COMPAT if (is_compat_task()) { diff --git a/arch/m68k/mm/fault.c b/arch/m68k/mm/fault.c index 127d7c1f2090..03253c4f8e6a 100644 --- a/arch/m68k/mm/fault.c +++ b/arch/m68k/mm/fault.c @@ -21,8 +21,9 @@ extern void die_if_kernel(char *, struct pt_regs *, long); int send_fault_sig(struct pt_regs *regs) { - siginfo_t siginfo = { 0, 0, 0, }; + siginfo_t siginfo; + clear_siginfo(&siginfo); siginfo.si_signo = current->thread.signo; siginfo.si_code = current->thread.code; siginfo.si_addr = (void *)current->thread.faddr; diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 5d19ed07e99d..0ae4a731cc12 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -699,11 +699,12 @@ static int simulate_sync(struct pt_regs *regs, unsigned int opcode) asmlinkage void do_ov(struct pt_regs *regs) { enum ctx_state prev_state; - siginfo_t info = { - .si_signo = SIGFPE, - .si_code = FPE_INTOVF, - .si_addr = (void __user *)regs->cp0_epc, - }; + siginfo_t info; + + clear_siginfo(&info); + info.si_signo = SIGFPE; + info.si_code = FPE_INTOVF; + info.si_addr = (void __user *)regs->cp0_epc; prev_state = exception_enter(); die_if_kernel("Integer overflow", regs); @@ -721,7 +722,11 @@ asmlinkage void do_ov(struct pt_regs *regs) void force_fcr31_sig(unsigned long fcr31, void __user *fault_addr, struct task_struct *tsk) { - struct siginfo si = { .si_addr = fault_addr, .si_signo = SIGFPE }; + struct siginfo si; + + clear_siginfo(&si); + si.si_addr = fault_addr; + si.si_signo = SIGFPE; if (fcr31 & FPU_CSR_INV_X) si.si_code = FPE_FLTINV; @@ -739,9 +744,10 @@ void force_fcr31_sig(unsigned long fcr31, void __user *fault_addr, int process_fpemu_return(int sig, void __user *fault_addr, unsigned long fcr31) { - struct siginfo si = { 0 }; + struct siginfo si; struct vm_area_struct *vma; + clear_siginfo(&si); switch (sig) { case 0: return 0; @@ -890,9 +896,10 @@ out: void do_trap_or_bp(struct pt_regs *regs, unsigned int code, int si_code, const char *str) { - siginfo_t info = { 0 }; + siginfo_t info; char b[40]; + clear_siginfo(&info); #ifdef CONFIG_KGDB_LOW_LEVEL_TRAP if (kgdb_ll_trap(DIE_TRAP, str, regs, code, current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP) @@ -1499,9 +1506,13 @@ asmlinkage void do_mdmx(struct pt_regs *regs) */ asmlinkage void do_watch(struct pt_regs *regs) { - siginfo_t info = { .si_signo = SIGTRAP, .si_code = TRAP_HWBKPT }; + siginfo_t info; enum ctx_state prev_state; + clear_siginfo(&info); + info.si_signo = SIGTRAP; + info.si_code = TRAP_HWBKPT; + prev_state = exception_enter(); /* * Clear WP (bit 22) bit of cause register so we don't loop diff --git a/arch/tile/kernel/single_step.c b/arch/tile/kernel/single_step.c index de3eae813e52..479d8033a801 100644 --- a/arch/tile/kernel/single_step.c +++ b/arch/tile/kernel/single_step.c @@ -163,11 +163,13 @@ static tilepro_bundle_bits rewrite_load_store_unaligned( * actual bad address in an SPR, which it doesn't. */ if (align_ctl == 0) { - siginfo_t info = { - .si_signo = SIGBUS, - .si_code = BUS_ADRALN, - .si_addr = addr - }; + siginfo_t info; + + clear_siginfo(&info); + info.si_signo = SIGBUS; + info.si_code = BUS_ADRALN; + info.si_addr = addr; + trace_unhandled_signal("unaligned trap", regs, (unsigned long)addr, SIGBUS); force_sig_info(info.si_signo, &info, current); @@ -210,11 +212,13 @@ static tilepro_bundle_bits rewrite_load_store_unaligned( } if (err) { - siginfo_t info = { - .si_signo = SIGBUS, - .si_code = BUS_ADRALN, - .si_addr = addr - }; + siginfo_t info; + + clear_siginfo(&info); + info.si_signo = SIGBUS; + info.si_code = BUS_ADRALN; + info.si_addr = addr; + trace_unhandled_signal("bad address for unaligned fixup", regs, (unsigned long)addr, SIGBUS); force_sig_info(info.si_signo, &info, current); diff --git a/arch/tile/kernel/traps.c b/arch/tile/kernel/traps.c index 9b08c6055f15..83a7186198d7 100644 --- a/arch/tile/kernel/traps.c +++ b/arch/tile/kernel/traps.c @@ -256,12 +256,14 @@ static int do_bpt(struct pt_regs *regs) void __kprobes do_trap(struct pt_regs *regs, int fault_num, unsigned long reason) { - siginfo_t info = { 0 }; + siginfo_t info; int signo, code; unsigned long address = 0; tile_bundle_bits instr; int is_kernel = !user_mode(regs); + clear_siginfo(&info); + /* Handle breakpoints, etc. */ if (is_kernel && fault_num == INT_ILL && do_bpt(regs)) return; diff --git a/arch/tile/kernel/unaligned.c b/arch/tile/kernel/unaligned.c index 8149c38f67b6..77a0b6b6a2a1 100644 --- a/arch/tile/kernel/unaligned.c +++ b/arch/tile/kernel/unaligned.c @@ -980,11 +980,13 @@ void jit_bundle_gen(struct pt_regs *regs, tilegx_bundle_bits bundle, } if ((align_ctl == 0) || unexpected) { - siginfo_t info = { - .si_signo = SIGBUS, - .si_code = BUS_ADRALN, - .si_addr = (unsigned char __user *)0 - }; + siginfo_t info; + + clear_siginfo(&info); + info.si_signo = SIGBUS; + info.si_code = BUS_ADRALN; + info.si_addr = (unsigned char __user *)0; + if (unaligned_printk) pr_info("Unalign bundle: unexp @%llx, %llx\n", (unsigned long long)regs->pc, @@ -1396,11 +1398,12 @@ void jit_bundle_gen(struct pt_regs *regs, tilegx_bundle_bits bundle, &frag, sizeof(frag)); if (status) { /* Fail to copy JIT into user land. send SIGSEGV. */ - siginfo_t info = { - .si_signo = SIGSEGV, - .si_code = SEGV_MAPERR, - .si_addr = (void __user *)&jit_code_area[idx] - }; + siginfo_t info; + + clear_siginfo(&info); + info.si_signo = SIGSEGV; + info.si_code = SEGV_MAPERR; + info.si_addr = (void __user *)&jit_code_area[idx]; pr_warn("Unalign fixup: pid=%d %s jit_code_area=%llx\n", current->pid, current->comm, @@ -1511,11 +1514,12 @@ void do_unaligned(struct pt_regs *regs, int vecnum) * If so, we will trigger SIGBUS. */ if ((regs->sp & 0x7) || (regs->ex1) || (align_ctl < 0)) { - siginfo_t info = { - .si_signo = SIGBUS, - .si_code = BUS_ADRALN, - .si_addr = (unsigned char __user *)0 - }; + siginfo_t info; + + clear_siginfo(&info); + info.si_signo = SIGBUS; + info.si_code = BUS_ADRALN; + info.si_addr = (unsigned char __user *)0; if (unaligned_printk) pr_info("Unalign fixup: %d %llx @%llx\n", @@ -1535,11 +1539,13 @@ void do_unaligned(struct pt_regs *regs, int vecnum) pc = (tilegx_bundle_bits __user *)(regs->pc); if (get_user(bundle, pc) != 0) { /* Probably never be here since pc is valid user address.*/ - siginfo_t info = { - .si_signo = SIGSEGV, - .si_code = SEGV_MAPERR, - .si_addr = (void __user *)pc - }; + siginfo_t info; + + clear_siginfo(&info); + info.si_signo = SIGSEGV; + info.si_code = SEGV_MAPERR; + info.si_addr = (void __user *)pc; + pr_err("Couldn't read instruction at %p trying to step\n", pc); trace_unhandled_signal("segfault in unalign fixup", regs, (unsigned long)info.si_addr, SIGSEGV); diff --git a/kernel/signal.c b/kernel/signal.c index 4976f05aa09b..f14492ff976f 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -3163,8 +3163,9 @@ do_send_specific(pid_t tgid, pid_t pid, int sig, struct siginfo *info) static int do_tkill(pid_t tgid, pid_t pid, int sig) { - struct siginfo info = {}; + struct siginfo info; + clear_siginfo(&info); info.si_signo = sig; info.si_errno = 0; info.si_code = SI_TKILL; -- cgit v1.2.3