]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
coredump: Only sort VMAs when core_sort_vma sysctl is set
authorKees Cook <kees@kernel.org>
Wed, 19 Feb 2025 19:53:16 +0000 (11:53 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 13 Mar 2025 12:02:01 +0000 (13:02 +0100)
[ Upstream commit 39ec9eaaa165d297d008d1fa385748430bd18e4d ]

The sorting of VMAs by size in commit 7d442a33bfe8 ("binfmt_elf: Dump
smaller VMAs first in ELF cores") breaks elfutils[1]. Instead, sort
based on the setting of the new sysctl, core_sort_vma, which defaults
to 0, no sorting.

Reported-by: Michael Stapelberg <michael@stapelberg.ch>
Closes: https://lore.kernel.org/all/20250218085407.61126-1-michael@stapelberg.de/ [1]
Fixes: 7d442a33bfe8 ("binfmt_elf: Dump smaller VMAs first in ELF cores")
Signed-off-by: Kees Cook <kees@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Documentation/admin-guide/sysctl/kernel.rst
fs/coredump.c

index f8bc1630eba0565937e154fe9bcda6af7c895fcf..fa21cdd610b21ae046c7f74c75f31813a635b510 100644 (file)
@@ -212,6 +212,17 @@ pid>/``).
 This value defaults to 0.
 
 
+core_sort_vma
+=============
+
+The default coredump writes VMAs in address order. By setting
+``core_sort_vma`` to 1, VMAs will be written from smallest size
+to largest size. This is known to break at least elfutils, but
+can be handy when dealing with very large (and truncated)
+coredumps where the more useful debugging details are included
+in the smaller VMAs.
+
+
 core_uses_pid
 =============
 
index 45737b43dda5c8a0f52bb925e21d8334d8c4138f..2b8c36c9660c5c1e2bab2b3fc9d613c6102de24f 100644 (file)
@@ -63,6 +63,7 @@ static void free_vma_snapshot(struct coredump_params *cprm);
 
 static int core_uses_pid;
 static unsigned int core_pipe_limit;
+static unsigned int core_sort_vma;
 static char core_pattern[CORENAME_MAX_SIZE] = "core";
 static int core_name_size = CORENAME_MAX_SIZE;
 unsigned int core_file_note_size_limit = CORE_FILE_NOTE_SIZE_DEFAULT;
@@ -1025,6 +1026,15 @@ static struct ctl_table coredump_sysctls[] = {
                .extra1         = (unsigned int *)&core_file_note_size_min,
                .extra2         = (unsigned int *)&core_file_note_size_max,
        },
+       {
+               .procname       = "core_sort_vma",
+               .data           = &core_sort_vma,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_douintvec_minmax,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
+       },
 };
 
 static int __init init_fs_coredump_sysctls(void)
@@ -1255,8 +1265,9 @@ static bool dump_vma_snapshot(struct coredump_params *cprm)
                cprm->vma_data_size += m->dump_size;
        }
 
-       sort(cprm->vma_meta, cprm->vma_count, sizeof(*cprm->vma_meta),
-               cmp_vma_size, NULL);
+       if (core_sort_vma)
+               sort(cprm->vma_meta, cprm->vma_count, sizeof(*cprm->vma_meta),
+                    cmp_vma_size, NULL);
 
        return true;
 }