Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

signal: fix information leak in copy_siginfo_from_user32

This function can leak kernel stack data when the user siginfo_t has a
positive si_code value. The top 16 bits of si_code descibe which fields
in the siginfo_t union are active, but they are treated inconsistently
between copy_siginfo_from_user32, copy_siginfo_to_user32 and
copy_siginfo_to_user.

copy_siginfo_from_user32 is called from rt_sigqueueinfo and
rt_tgsigqueueinfo in which the user has full control overthe top 16 bits
of si_code.

This fixes the following information leaks:
x86: 8 bytes leaked when sending a signal from a 32-bit process to
itself. This leak grows to 16 bytes if the process uses x32.
(si_code = __SI_CHLD)
x86: 100 bytes leaked when sending a signal from a 32-bit process to
a 64-bit process. (si_code = -1)
sparc: 4 bytes leaked when sending a signal from a 32-bit process to a
64-bit process. (si_code = any)

parsic and s390 have similar bugs, but they are not vulnerable because
rt_[tg]sigqueueinfo have checks that prevent sending a positive si_code
to a different process. These bugs are also fixed for consistency.

Signed-off-by: Amanieu d'Antras <amanieu@gmail.com>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Russell King <rmk@arm.linux.org.uk>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Chris Metcalf <cmetcalf@ezchip.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Amanieu d'Antras and committed by
Linus Torvalds
3c00cb5e 209f7512

+2 -10
-2
arch/arm64/kernel/signal32.c
··· 201 201 202 202 int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) 203 203 { 204 - memset(to, 0, sizeof *to); 205 - 206 204 if (copy_from_user(to, from, __ARCH_SI_PREAMBLE_SIZE) || 207 205 copy_from_user(to->_sifields._pad, 208 206 from->_sifields._pad, SI_PAD_SIZE))
-2
arch/mips/kernel/signal32.c
··· 409 409 410 410 int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) 411 411 { 412 - memset(to, 0, sizeof *to); 413 - 414 412 if (copy_from_user(to, from, 3*sizeof(int)) || 415 413 copy_from_user(to->_sifields._pad, 416 414 from->_sifields._pad, SI_PAD_SIZE32))
-2
arch/powerpc/kernel/signal_32.c
··· 966 966 967 967 int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from) 968 968 { 969 - memset(to, 0, sizeof *to); 970 - 971 969 if (copy_from_user(to, from, 3*sizeof(int)) || 972 970 copy_from_user(to->_sifields._pad, 973 971 from->_sifields._pad, SI_PAD_SIZE32))
-2
arch/tile/kernel/compat_signal.c
··· 113 113 if (!access_ok(VERIFY_READ, from, sizeof(struct compat_siginfo))) 114 114 return -EFAULT; 115 115 116 - memset(to, 0, sizeof(*to)); 117 - 118 116 err = __get_user(to->si_signo, &from->si_signo); 119 117 err |= __get_user(to->si_errno, &from->si_errno); 120 118 err |= __get_user(to->si_code, &from->si_code);
+2 -2
kernel/signal.c
··· 3017 3017 int, sig, 3018 3018 struct compat_siginfo __user *, uinfo) 3019 3019 { 3020 - siginfo_t info; 3020 + siginfo_t info = {}; 3021 3021 int ret = copy_siginfo_from_user32(&info, uinfo); 3022 3022 if (unlikely(ret)) 3023 3023 return ret; ··· 3061 3061 int, sig, 3062 3062 struct compat_siginfo __user *, uinfo) 3063 3063 { 3064 - siginfo_t info; 3064 + siginfo_t info = {}; 3065 3065 3066 3066 if (copy_siginfo_from_user32(&info, uinfo)) 3067 3067 return -EFAULT;