diff mbox series

[RFC] NT_FILE/NT_SIGINFO breakage on mips compat coredumps

Message ID 20201224194438.GY3579531@ZenIV.linux.org.uk (mailing list archive)
State Accepted
Commit 698222457465ce343443be81c5512edda86e5914
Headers show
Series [RFC] NT_FILE/NT_SIGINFO breakage on mips compat coredumps | expand

Commit Message

Al Viro Dec. 24, 2020, 7:44 p.m. UTC
On Wed, Dec 23, 2020 at 07:12:13AM +0000, Al Viro wrote:
> On Wed, Dec 23, 2020 at 07:03:20AM +0000, Al Viro wrote:
> 
> 	Argh....  Wrong commit blamed - the parent of the correct one.
> It's actually 2aa362c49c31 ("coredump: extend core dump note section to
> contain file names of mapped files").  My apologies - fat-fingered
> cut'n'paste...
> 
> 	siginfo commit does suffer the same problem, but it becomes an issue
> only for 32bit processes under mips64 big-endian kernel (there it yields
> e.g. zero .__sigfault.si_addr in $_siginfo when using gdb with a coredump
> of 32bit process, whatever the actual faulting address had been).  And
> b-e mips64 is rather uncommon, so that's less of an issue.

	FWIW, here's debian/mips image (stretch) booted with
qemu-system-mips64 -M malta -cpu 5KEc:
root@mips:~# uname -a
Linux mips 4.9.0-13-5kc-malta #1 Debian 4.9.228-1 (2020-07-05) mips64 GNU/Linux
root@mips:~# cat a.c
main()
{
        *(char *)0x0123 = 0;
}
root@mips:~# gcc a.c 
a.c:1:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
 main()
 ^~~~
root@mips:~# ulimit -c unlimited
root@mips:~# ./a.out 
[  519.744983] do_page_fault(): sending SIGSEGV to a.out for invalid write access to 0000000000000123
[  519.746735] epc = 00000000558477c0 in a.out[55847000+1000]
[  519.747758] ra  = 000000007792f4a8 in libc-2.24.so[77916000+16a000]
Segmentation fault (core dumped)
root@mips:~# gdb a.out core 
GNU gdb (Debian 7.12-6) 7.12.0.20161007-git
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "mips-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from a.out...(no debugging symbols found)...done.
[New LWP 1202]
Core was generated by `./a.out'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x55dde7c0 in main ()
(gdb) print $_siginfo
$1 = {si_signo = 11, si_errno = 1, si_code = 0, _sifields = {_pad = {0, 0, 
      291, 0 <repeats 26 times>}, _kill = {si_pid = 0, si_uid = 0}, _timer = {
      si_tid = 0, si_overrun = 0, si_sigval = {sival_int = 291, 
        sival_ptr = 0x123}}, _rt = {si_pid = 0, si_uid = 0, si_sigval = {
        sival_int = 291, sival_ptr = 0x123}}, _sigchld = {si_pid = 0, 
      si_uid = 0, si_status = 291, si_utime = 0, si_stime = 0}, _sigfault = {
      si_addr = 0x0}, _sigpoll = {si_band = 0, si_fd = 0}}}
(gdb) quit


Note the wrong value in _sigfault.si_addr - it should've been 0x123, not 0.

root@mips:~# readelf -n core

Displaying notes found at file offset 0x00000234 with length 0x000005f4:
  Owner                 Data size       Description
  CORE                 0x00000100       NT_PRSTATUS (prstatus structure)
  CORE                 0x00000080       NT_PRPSINFO (prpsinfo structure)
  CORE                 0x00000080       NT_SIGINFO (siginfo_t data)
  CORE                 0x00000090       NT_AUXV (auxiliary vector)
  CORE                 0x000001e1       NT_FILE (mapped files)
    Page size: 9
         Start         End Page Offset
  CORE                 0x00000108       NT_FPREGSET (floating point registers)

For comparison, exact same image booted with qemu-system-mips -M malta:

root@mips:~# uname -a
Linux mips 4.9.0-13-4kc-malta #1 Debian 4.9.228-1 (2020-07-05) mips GNU/Linux
root@mips:~# ulimit -c unlimited
root@mips:~# ./a.out
[   83.380870] do_page_fault(): sending SIGSEGV to a.out for invalid write access to 00000123
[   83.390678] epc = 55e0e7c0 in a.out[55e0e000+1000]
[   83.391525] ra  = 76f644a8 in libc-2.24.so[76f4b000+16a000]
Segmentation fault (core dumped)
root@mips:~# gdb a.out core
GNU gdb (Debian 7.12-6) 7.12.0.20161007-git
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "mips-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from a.out...(no debugging symbols found)...done.
[New LWP 1184]
Core was generated by `./a.out'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x55e0e7c0 in main ()
(gdb) print $_siginfo
$1 = {si_signo = 11, si_errno = 1, si_code = 0, _sifields = {_pad = {291, 
      0 <repeats 28 times>}, _kill = {si_pid = 291, si_uid = 0}, _timer = {
      si_tid = 291, si_overrun = 0, si_sigval = {sival_int = 0, 
        sival_ptr = 0x0}}, _rt = {si_pid = 291, si_uid = 0, si_sigval = {
        sival_int = 0, sival_ptr = 0x0}}, _sigchld = {si_pid = 291, 
      si_uid = 0, si_status = 0, si_utime = 0, si_stime = 0}, _sigfault = {
      si_addr = 0x123}, _sigpoll = {si_band = 291, si_fd = 0}}}
(gdb) quit
root@mips:~# readelf -n core

Displaying notes found at file offset 0x00000234 with length 0x00000580:
  Owner                 Data size       Description
  CORE                 0x00000100       NT_PRSTATUS (prstatus structure)
  CORE                 0x00000080       NT_PRPSINFO (prpsinfo structure)
  CORE                 0x00000080       NT_SIGINFO (siginfo_t data)
  CORE                 0x00000090       NT_AUXV (auxiliary vector)
  CORE                 0x0000016d       NT_FILE (mapped files)
    Page size: 4096
         Start         End Page Offset
    0x55e0e000  0x55e0f000  0x00000000
        /root/a.out
    0x55e1e000  0x55e1f000  0x00000000
        /root/a.out
    0x76f4b000  0x770b5000  0x00000000
        /lib/mips-linux-gnu/libc-2.24.so
    0x770b5000  0x770c5000  0x0000016a
        /lib/mips-linux-gnu/libc-2.24.so
    0x770c5000  0x770c8000  0x0000016a
        /lib/mips-linux-gnu/libc-2.24.so
    0x770c8000  0x770cb000  0x0000016d
        /lib/mips-linux-gnu/libc-2.24.so
    0x770cd000  0x770f0000  0x00000000
        /lib/mips-linux-gnu/ld-2.24.so
    0x770ff000  0x77100000  0x00000022
        /lib/mips-linux-gnu/ld-2.24.so
    0x77100000  0x77101000  0x00000023
        /lib/mips-linux-gnu/ld-2.24.so
  CORE                 0x00000108       NT_FPREGSET (floating point registers)

So that's not so theoretical - big-endian mips64 userland is unsupported,
but booting the big-endian mips32 userland on mips64 hardware is clearly
meant to work - they even ship a 64bit kernel built for that.

IOW, both O32 and N32 coredumps in 64bit mips kernels have broken
NT_FILE and NT_SIGINFO.  And while NT_SIGINFO breakage is really
visible only on b-e, NT_FILE one is common to b-e and l-e.  One of
the effects of the latter is that current gdb fails to work with
threaded coredumps of 32bit processes produced on boxen with 64bit
kernels.  Coredumps generated by gcore(1) are fine...

I think the following ought to be applied.  Comments?

[mips] fix malformed NT_FILE and NT_SIGINFO in 32bit coredumps

	Patches that introduced NT_FILE and NT_SIGINFO notes back in 2012
had taken care of native (fs/binfmt_elf.c) and compat (fs/compat_binfmt_elf.c)
coredumps; unfortunately, compat on mips (which does not go through the
usual compat_binfmt_elf.c) had not been noticed.

	As the result, both N32 and O32 coredumps on 64bit mips kernels
have those sections malformed enough to confuse the living hell out of
all gdb and readelf versions (up to and including the tip of binutils-gdb.git).

	Longer term solution is to make both O32 and N32 compat use the
regular compat_binfmt_elf.c, but that's too much for backports.  The minimal
solution is to do in arch/mips/kernel/binfmt_elf[on]32.c the same thing
those patches have done in fs/compat_binfmt_elf.c

Cc: stable@kernel.org # v3.7+
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---

Comments

Thomas Bogendoerfer Dec. 29, 2020, 3:09 p.m. UTC | #1
On Thu, Dec 24, 2020 at 07:44:38PM +0000, Al Viro wrote:
> [mips] fix malformed NT_FILE and NT_SIGINFO in 32bit coredumps
> 
> 	Patches that introduced NT_FILE and NT_SIGINFO notes back in 2012
> had taken care of native (fs/binfmt_elf.c) and compat (fs/compat_binfmt_elf.c)
> coredumps; unfortunately, compat on mips (which does not go through the
> usual compat_binfmt_elf.c) had not been noticed.
> 
> 	As the result, both N32 and O32 coredumps on 64bit mips kernels
> have those sections malformed enough to confuse the living hell out of
> all gdb and readelf versions (up to and including the tip of binutils-gdb.git).
> 
> 	Longer term solution is to make both O32 and N32 compat use the
> regular compat_binfmt_elf.c, but that's too much for backports.  The minimal
> solution is to do in arch/mips/kernel/binfmt_elf[on]32.c the same thing
> those patches have done in fs/compat_binfmt_elf.c
> 
> Cc: stable@kernel.org # v3.7+
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
> diff --git a/arch/mips/kernel/binfmt_elfn32.c b/arch/mips/kernel/binfmt_elfn32.c
> index 6ee3f7218c67..c4441416e96b 100644
> --- a/arch/mips/kernel/binfmt_elfn32.c
> +++ b/arch/mips/kernel/binfmt_elfn32.c
> @@ -103,4 +103,11 @@ jiffies_to_old_timeval32(unsigned long jiffies, struct old_timeval32 *value)
>  #undef ns_to_kernel_old_timeval
>  #define ns_to_kernel_old_timeval ns_to_old_timeval32
>  
> +/*
> + * Some data types as stored in coredump.
> + */
> +#define user_long_t             compat_long_t
> +#define user_siginfo_t          compat_siginfo_t
> +#define copy_siginfo_to_external        copy_siginfo_to_external32
> +
>  #include "../../../fs/binfmt_elf.c"
> diff --git a/arch/mips/kernel/binfmt_elfo32.c b/arch/mips/kernel/binfmt_elfo32.c
> index 6dd103d3cebb..7b2a23f48c1a 100644
> --- a/arch/mips/kernel/binfmt_elfo32.c
> +++ b/arch/mips/kernel/binfmt_elfo32.c
> @@ -106,4 +106,11 @@ jiffies_to_old_timeval32(unsigned long jiffies, struct old_timeval32 *value)
>  #undef ns_to_kernel_old_timeval
>  #define ns_to_kernel_old_timeval ns_to_old_timeval32
>  
> +/*
> + * Some data types as stored in coredump.
> + */
> +#define user_long_t             compat_long_t
> +#define user_siginfo_t          compat_siginfo_t
> +#define copy_siginfo_to_external        copy_siginfo_to_external32
> +
>  #include "../../../fs/binfmt_elf.c"

LGTM, I've applied it to mips-fixes.

Thomas.
diff mbox series

Patch

diff --git a/arch/mips/kernel/binfmt_elfn32.c b/arch/mips/kernel/binfmt_elfn32.c
index 6ee3f7218c67..c4441416e96b 100644
--- a/arch/mips/kernel/binfmt_elfn32.c
+++ b/arch/mips/kernel/binfmt_elfn32.c
@@ -103,4 +103,11 @@  jiffies_to_old_timeval32(unsigned long jiffies, struct old_timeval32 *value)
 #undef ns_to_kernel_old_timeval
 #define ns_to_kernel_old_timeval ns_to_old_timeval32
 
+/*
+ * Some data types as stored in coredump.
+ */
+#define user_long_t             compat_long_t
+#define user_siginfo_t          compat_siginfo_t
+#define copy_siginfo_to_external        copy_siginfo_to_external32
+
 #include "../../../fs/binfmt_elf.c"
diff --git a/arch/mips/kernel/binfmt_elfo32.c b/arch/mips/kernel/binfmt_elfo32.c
index 6dd103d3cebb..7b2a23f48c1a 100644
--- a/arch/mips/kernel/binfmt_elfo32.c
+++ b/arch/mips/kernel/binfmt_elfo32.c
@@ -106,4 +106,11 @@  jiffies_to_old_timeval32(unsigned long jiffies, struct old_timeval32 *value)
 #undef ns_to_kernel_old_timeval
 #define ns_to_kernel_old_timeval ns_to_old_timeval32
 
+/*
+ * Some data types as stored in coredump.
+ */
+#define user_long_t             compat_long_t
+#define user_siginfo_t          compat_siginfo_t
+#define copy_siginfo_to_external        copy_siginfo_to_external32
+
 #include "../../../fs/binfmt_elf.c"