aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2012-10-04 20:15:35 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-05 14:05:16 -0400
commit49ae4d4b113be03dc4a2ec5f2a1f573ff0fcddb3 (patch)
tree5c172a0ef5cbf57abf969bc13b0a4e3b4c50aefd
parent751f409db6216ebd134a94f6dcd97779933a5106 (diff)
coredump: add a new elf note with siginfo of the signal
Existing PRSTATUS note contains only si_signo, si_code, si_errno fields from the siginfo of the signal which caused core to be dumped. There are tools which try to analyze crashes for possible security implications, and they want to use, among other data, si_addr field from the SIGSEGV. This patch adds a new elf note, NT_SIGINFO, which contains the complete siginfo_t of the signal which killed the process. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> Reviewed-by: Oleg Nesterov <oleg@redhat.com> Cc: Amerigo Wang <amwang@redhat.com> Cc: "Jonathan M. Foote" <jmfoote@cert.org> Cc: Roland McGrath <roland@hack.frob.com> Cc: Pedro Alves <palves@redhat.com> Cc: Fengguang Wu <fengguang.wu@intel.com> Cc: Stephen Rothwell <sfr@canb.auug.org.au> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/binfmt_elf.c27
-rw-r--r--fs/compat_binfmt_elf.c6
-rw-r--r--include/linux/elf.h5
3 files changed, 36 insertions, 2 deletions
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 4450e82a05aa..865f9be6a2d3 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -37,6 +37,10 @@
37#include <asm/page.h> 37#include <asm/page.h>
38#include <asm/exec.h> 38#include <asm/exec.h>
39 39
40#ifndef user_siginfo_t
41#define user_siginfo_t siginfo_t
42#endif
43
40static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs); 44static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs);
41static int load_elf_library(struct file *); 45static int load_elf_library(struct file *);
42static unsigned long elf_map(struct file *, unsigned long, struct elf_phdr *, 46static unsigned long elf_map(struct file *, unsigned long, struct elf_phdr *,
@@ -1372,6 +1376,16 @@ static void fill_auxv_note(struct memelfnote *note, struct mm_struct *mm)
1372 fill_note(note, "CORE", NT_AUXV, i * sizeof(elf_addr_t), auxv); 1376 fill_note(note, "CORE", NT_AUXV, i * sizeof(elf_addr_t), auxv);
1373} 1377}
1374 1378
1379static void fill_siginfo_note(struct memelfnote *note, user_siginfo_t *csigdata,
1380 siginfo_t *siginfo)
1381{
1382 mm_segment_t old_fs = get_fs();
1383 set_fs(KERNEL_DS);
1384 copy_siginfo_to_user((user_siginfo_t __user *) csigdata, siginfo);
1385 set_fs(old_fs);
1386 fill_note(note, "CORE", NT_SIGINFO, sizeof(*csigdata), csigdata);
1387}
1388
1375#ifdef CORE_DUMP_USE_REGSET 1389#ifdef CORE_DUMP_USE_REGSET
1376#include <linux/regset.h> 1390#include <linux/regset.h>
1377 1391
@@ -1385,7 +1399,9 @@ struct elf_thread_core_info {
1385struct elf_note_info { 1399struct elf_note_info {
1386 struct elf_thread_core_info *thread; 1400 struct elf_thread_core_info *thread;
1387 struct memelfnote psinfo; 1401 struct memelfnote psinfo;
1402 struct memelfnote signote;
1388 struct memelfnote auxv; 1403 struct memelfnote auxv;
1404 user_siginfo_t csigdata;
1389 size_t size; 1405 size_t size;
1390 int thread_notes; 1406 int thread_notes;
1391}; 1407};
@@ -1559,6 +1575,9 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
1559 fill_psinfo(psinfo, dump_task->group_leader, dump_task->mm); 1575 fill_psinfo(psinfo, dump_task->group_leader, dump_task->mm);
1560 info->size += notesize(&info->psinfo); 1576 info->size += notesize(&info->psinfo);
1561 1577
1578 fill_siginfo_note(&info->signote, &info->csigdata, siginfo);
1579 info->size += notesize(&info->signote);
1580
1562 fill_auxv_note(&info->auxv, current->mm); 1581 fill_auxv_note(&info->auxv, current->mm);
1563 info->size += notesize(&info->auxv); 1582 info->size += notesize(&info->auxv);
1564 1583
@@ -1588,6 +1607,8 @@ static int write_note_info(struct elf_note_info *info,
1588 1607
1589 if (first && !writenote(&info->psinfo, file, foffset)) 1608 if (first && !writenote(&info->psinfo, file, foffset))
1590 return 0; 1609 return 0;
1610 if (first && !writenote(&info->signote, file, foffset))
1611 return 0;
1591 if (first && !writenote(&info->auxv, file, foffset)) 1612 if (first && !writenote(&info->auxv, file, foffset))
1592 return 0; 1613 return 0;
1593 1614
@@ -1681,6 +1702,7 @@ struct elf_note_info {
1681#ifdef ELF_CORE_COPY_XFPREGS 1702#ifdef ELF_CORE_COPY_XFPREGS
1682 elf_fpxregset_t *xfpu; 1703 elf_fpxregset_t *xfpu;
1683#endif 1704#endif
1705 user_siginfo_t csigdata;
1684 int thread_status_size; 1706 int thread_status_size;
1685 int numnote; 1707 int numnote;
1686}; 1708};
@@ -1690,8 +1712,8 @@ static int elf_note_info_init(struct elf_note_info *info)
1690 memset(info, 0, sizeof(*info)); 1712 memset(info, 0, sizeof(*info));
1691 INIT_LIST_HEAD(&info->thread_list); 1713 INIT_LIST_HEAD(&info->thread_list);
1692 1714
1693 /* Allocate space for six ELF notes */ 1715 /* Allocate space for ELF notes */
1694 info->notes = kmalloc(6 * sizeof(struct memelfnote), GFP_KERNEL); 1716 info->notes = kmalloc(7 * sizeof(struct memelfnote), GFP_KERNEL);
1695 if (!info->notes) 1717 if (!info->notes)
1696 return 0; 1718 return 0;
1697 info->psinfo = kmalloc(sizeof(*info->psinfo), GFP_KERNEL); 1719 info->psinfo = kmalloc(sizeof(*info->psinfo), GFP_KERNEL);
@@ -1763,6 +1785,7 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
1763 1785
1764 info->numnote = 2; 1786 info->numnote = 2;
1765 1787
1788 fill_siginfo_note(&info->notes[info->numnote++], &info->csigdata, siginfo);
1766 fill_auxv_note(&info->notes[info->numnote++], current->mm); 1789 fill_auxv_note(&info->notes[info->numnote++], current->mm);
1767 1790
1768 /* Try to dump the FPU. */ 1791 /* Try to dump the FPU. */
diff --git a/fs/compat_binfmt_elf.c b/fs/compat_binfmt_elf.c
index 112e45a17e99..0fbcf6347437 100644
--- a/fs/compat_binfmt_elf.c
+++ b/fs/compat_binfmt_elf.c
@@ -38,6 +38,12 @@
38#define elf_addr_t Elf32_Addr 38#define elf_addr_t Elf32_Addr
39 39
40/* 40/*
41 * Some data types as stored in coredump.
42 */
43#define user_siginfo_t compat_siginfo_t
44#define copy_siginfo_to_user copy_siginfo_to_user32
45
46/*
41 * The machine-dependent core note format types are defined in elfcore-compat.h, 47 * The machine-dependent core note format types are defined in elfcore-compat.h,
42 * which requires asm/elf.h to define compat_elf_gregset_t et al. 48 * which requires asm/elf.h to define compat_elf_gregset_t et al.
43 */ 49 */
diff --git a/include/linux/elf.h b/include/linux/elf.h
index 0a05051a8924..dc62da7447ca 100644
--- a/include/linux/elf.h
+++ b/include/linux/elf.h
@@ -372,6 +372,11 @@ typedef struct elf64_shdr {
372#define NT_PRPSINFO 3 372#define NT_PRPSINFO 3
373#define NT_TASKSTRUCT 4 373#define NT_TASKSTRUCT 4
374#define NT_AUXV 6 374#define NT_AUXV 6
375/*
376 * Note to userspace developers: size of NT_SIGINFO note may increase
377 * in the future to accomodate more fields, don't assume it is fixed!
378 */
379#define NT_SIGINFO 0x53494749
375#define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */ 380#define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */
376#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */ 381#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */
377#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */ 382#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */