From 8c36fdf5ed48cc17a257e71e168883307ce89b0e Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 19 Jul 2017 21:30:42 -0500 Subject: signal: Reduce copy_siginfo to just a memcpy The savings for copying just part of struct siginfo appears to be in the noise on modern machines. So remove this ``optimization'' and simplify the code. At the same time mark the second parameter as constant so there is no confusion as to which direction the copy will go. This ensures that a fully initialized siginfo that is sent ends up as a fully initialized siginfo on the signal queue. This full initialization ensures even confused code won't copy unitialized data to userspace, and it prepares for turning copy_siginfo_to_user into a simple copy_to_user. Signed-off-by: "Eric W. Biederman" --- include/linux/signal.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/signal.h b/include/linux/signal.h index 042968dd98f0..8037b503ce91 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -11,13 +11,9 @@ struct task_struct; /* for sysctl */ extern int print_fatal_signals; -static inline void copy_siginfo(struct siginfo *to, struct siginfo *from) +static inline void copy_siginfo(struct siginfo *to, const struct siginfo *from) { - if (from->si_code < 0) - memcpy(to, from, sizeof(*to)); - else - /* _sigchld is currently the largest know union member */ - memcpy(to, from, __ARCH_SI_PREAMBLE_SIZE + sizeof(from->_sifields._sigchld)); + memcpy(to, from, sizeof(*to)); } int copy_siginfo_to_user(struct siginfo __user *to, const struct siginfo *from); -- cgit v1.2.3 From 8c5dbf2ae00bb8667f61c5edc6521c1fa2bbe4d7 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 24 Jul 2017 15:28:56 -0500 Subject: signal: Introduce clear_siginfo Unfortunately struct siginfo has holes both in the common part of the structure, in the union members, and in the lack of padding of the union members. The result of those wholes is that the C standard does not guarantee those bits will be initialized. As struct siginfo is for communication between the kernel and userspace that is a problem. Add the helper function clear_siginfo that is guaranteed to clear all of the bits in struct siginfo so when the structure is copied there is no danger of copying old kernel data and causing a leak of information from kernel space to userspace. Signed-off-by: "Eric W. Biederman" --- include/linux/signal.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'include/linux') diff --git a/include/linux/signal.h b/include/linux/signal.h index 8037b503ce91..87abf0c29ed7 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -16,6 +16,11 @@ static inline void copy_siginfo(struct siginfo *to, const struct siginfo *from) memcpy(to, from, sizeof(*to)); } +static inline void clear_siginfo(struct siginfo *info) +{ + memset(info, 0, sizeof(*info)); +} + int copy_siginfo_to_user(struct siginfo __user *to, const struct siginfo *from); enum siginfo_layout { -- cgit v1.2.3 From 0326e7ef057d214ed43a77557078c24e98b84af9 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 27 Jul 2017 11:59:46 -0500 Subject: signal: Remove unnecessary ifdefs now that there is only one struct siginfo Remove HAVE_ARCH_SIGINFO_T Remove __ARCH_SIGSYS Signed-off-by: "Eric W. Biederman" --- include/linux/signal.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/signal.h b/include/linux/signal.h index 87abf0c29ed7..a9bc7e1b077e 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -30,9 +30,7 @@ enum siginfo_layout { SIL_FAULT, SIL_CHLD, SIL_RT, -#ifdef __ARCH_SIGSYS SIL_SYS, -#endif }; enum siginfo_layout siginfo_layout(int sig, int si_code); -- 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 --- include/linux/compat.h | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) (limited to 'include/linux') 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 b68a68d3dcc15ebbf23cbe91af1abf57591bd96b Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 31 Jul 2017 10:08:59 -0500 Subject: signal: Move addr_lsb into the _sigfault union for clarity The addr_lsb fields is only valid and available when the signal is SIGBUS and the si_code is BUS_MCEERR_AR or BUS_MCEERR_AO. Document this with a comment and place the field in the _sigfault union to make this clear. All of the fields stay in the same physical location so both the old and new definitions of struct siginfo will continue to work. Signed-off-by: "Eric W. Biederman" --- include/linux/compat.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/compat.h b/include/linux/compat.h index 8f8e3ef247de..e698ec1908d9 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -221,15 +221,23 @@ typedef struct compat_siginfo { #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=BUS_MCEERR_AR or + * used when si_code=BUS_MCEERR_AO + */ + short int _addr_lsb; /* Valid LSB of the reported address. */ /* used when si_code=SEGV_BNDERR */ struct { + short _dummy_bnd; compat_uptr_t _lower; compat_uptr_t _upper; } _addr_bnd; /* used when si_code=SEGV_PKUERR */ - u32 _pkey; + struct { + short _dummy_pkey; + u32 _pkey; + } _addr_pkey; }; } _sigfault; -- 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" --- include/linux/compat.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') 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); -- cgit v1.2.3 From f8ec66014ffd95a783b1f9f3b62d7cadb96b78d5 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 18 Jan 2018 14:54:54 -0600 Subject: signal: Add send_sig_fault and force_sig_fault The vast majority of signals sent from architecture specific code are simple faults. Encapsulate this reality with two helper functions so that the nit-picky implementation of preparing a siginfo does not need to be repeated many times on each architecture. As only some architectures support the trapno field, make the trapno arguement only present on those architectures. Similary as ia64 has three fields: imm, flags, and isr that are specific to it. Have those arguments always present on ia64 and no where else. This ensures the architecture specific code always remembers which fields it needs to pass into the siginfo structure. Signed-off-by: "Eric W. Biederman" --- include/linux/sched/signal.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'include/linux') diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h index 0aa4548fb492..375f31eb3b6b 100644 --- a/include/linux/sched/signal.h +++ b/include/linux/sched/signal.h @@ -285,6 +285,26 @@ static inline void kernel_signal_stop(void) schedule(); } +#ifdef __ARCH_SI_TRAPNO +# define ___ARCH_SI_TRAPNO(_a1) , _a1 +#else +# define ___ARCH_SI_TRAPNO(_a1) +#endif +#ifdef __ia64__ +# define ___ARCH_SI_IA64(_a1, _a2, _a3) , _a1, _a2, _a3 +#else +# define ___ARCH_SI_IA64(_a1, _a2, _a3) +#endif + +int force_sig_fault(int sig, int code, void __user *addr + ___ARCH_SI_TRAPNO(int trapno) + ___ARCH_SI_IA64(int imm, unsigned int flags, unsigned long isr) + , struct task_struct *t); +int send_sig_fault(int sig, int code, void __user *addr + ___ARCH_SI_TRAPNO(int trapno) + ___ARCH_SI_IA64(int imm, unsigned int flags, unsigned long isr) + , struct task_struct *t); + extern int send_sig_info(int, struct siginfo *, struct task_struct *); extern int force_sigsegv(int, struct task_struct *); extern int force_sig_info(int, struct siginfo *, struct task_struct *); -- cgit v1.2.3 From 382467358ac9675b1b6814400a9a9e36dc7da14f Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 18 Jan 2018 18:54:31 -0600 Subject: signal: Helpers for faults with specialized siginfo layouts The helpers added are: send_sig_mceerr force_sig_mceerr force_sig_bnderr force_sig_pkuerr Filling out siginfo properly can ge tricky. Especially for these specialized cases where the temptation is to share code with other cases which use a different subset of siginfo fields. Unfortunately that code sharing frequently results in bugs with the wrong siginfo fields filled in, and makes it harder to verify that the siginfo structure was properly initialized. Provide these helpers instead that get all of the details right, and guarantee that siginfo is properly initialized. send_sig_mceerr and force_sig_mceer are a little special as two si codes BUS_MCEERR_AO and BUS_MCEER_AR both use the same extended signinfo layout. Signed-off-by: "Eric W. Biederman" --- include/linux/sched/signal.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'include/linux') diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h index 375f31eb3b6b..944fe6356f4a 100644 --- a/include/linux/sched/signal.h +++ b/include/linux/sched/signal.h @@ -305,6 +305,12 @@ int send_sig_fault(int sig, int code, void __user *addr ___ARCH_SI_IA64(int imm, unsigned int flags, unsigned long isr) , struct task_struct *t); +int force_sig_mceerr(int code, void __user *, short, struct task_struct *); +int send_sig_mceerr(int code, void __user *, short, struct task_struct *); + +int force_sig_bnderr(void __user *addr, void __user *lower, void __user *upper); +int force_sig_pkuerr(void __user *addr, u32 pkey); + extern int send_sig_info(int, struct siginfo *, struct task_struct *); extern int force_sigsegv(int, struct task_struct *); extern int force_sig_info(int, struct siginfo *, struct task_struct *); -- cgit v1.2.3 From f71dd7dc2dc989dc712b246a74d243e4b2c5f8a7 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 22 Jan 2018 14:37:25 -0600 Subject: signal/ptrace: Add force_sig_ptrace_errno_trap and use it where needed There are so many places that build struct siginfo by hand that at least one of them is bound to get it wrong. A handful of cases in the kernel arguably did just that when using the errno field of siginfo to pass no errno values to userspace. The usage is limited to a single si_code so at least does not mess up anything else. Encapsulate this questionable pattern in a helper function so that the userspace ABI is preserved. Update all of the places that use this pattern to use the new helper function. Signed-off-by: "Eric W. Biederman" --- include/linux/sched/signal.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/linux') diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h index 944fe6356f4a..23b4f9cb82db 100644 --- a/include/linux/sched/signal.h +++ b/include/linux/sched/signal.h @@ -311,6 +311,8 @@ int send_sig_mceerr(int code, void __user *, short, struct task_struct *); int force_sig_bnderr(void __user *addr, void __user *lower, void __user *upper); int force_sig_pkuerr(void __user *addr, u32 pkey); +int force_sig_ptrace_errno_trap(int errno, void __user *addr); + extern int send_sig_info(int, struct siginfo *, struct task_struct *); extern int force_sigsegv(int, struct task_struct *); extern int force_sig_info(int, struct siginfo *, struct task_struct *); -- cgit v1.2.3 From 83b57531c58f4173d1c0d0b2c0bc88c853c32ea5 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 9 Jul 2017 18:14:01 -0500 Subject: mm/memory_failure: Remove unused trapno from memory_failure Today 4 architectures set ARCH_SUPPORTS_MEMORY_FAILURE (arm64, parisc, powerpc, and x86), while 4 other architectures set __ARCH_SI_TRAPNO (alpha, metag, sparc, and tile). These two sets of architectures do not interesect so remove the trapno paramater to remove confusion. Signed-off-by: "Eric W. Biederman" --- include/linux/mm.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/mm.h b/include/linux/mm.h index ea818ff739cd..7fc92384977e 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -2570,8 +2570,8 @@ enum mf_flags { MF_MUST_KILL = 1 << 2, MF_SOFT_OFFLINE = 1 << 3, }; -extern int memory_failure(unsigned long pfn, int trapno, int flags); -extern void memory_failure_queue(unsigned long pfn, int trapno, int flags); +extern int memory_failure(unsigned long pfn, int flags); +extern void memory_failure_queue(unsigned long pfn, int flags); extern int unpoison_memory(unsigned long pfn); extern int get_hwpoison_page(struct page *page); #define put_hwpoison_page(page) put_page(page) -- cgit v1.2.3