aboutsummaryrefslogtreecommitdiffstats
path: root/fs/binfmt_elf.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/binfmt_elf.c')
-rw-r--r--fs/binfmt_elf.c151
1 files changed, 90 insertions, 61 deletions
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index fd5b2ea5d299..535e763ab1a6 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -31,6 +31,7 @@
31#include <linux/random.h> 31#include <linux/random.h>
32#include <linux/elf.h> 32#include <linux/elf.h>
33#include <linux/utsname.h> 33#include <linux/utsname.h>
34#include <linux/coredump.h>
34#include <asm/uaccess.h> 35#include <asm/uaccess.h>
35#include <asm/param.h> 36#include <asm/param.h>
36#include <asm/page.h> 37#include <asm/page.h>
@@ -1085,36 +1086,6 @@ out:
1085 * Modelled on fs/exec.c:aout_core_dump() 1086 * Modelled on fs/exec.c:aout_core_dump()
1086 * Jeremy Fitzhardinge <jeremy@sw.oz.au> 1087 * Jeremy Fitzhardinge <jeremy@sw.oz.au>
1087 */ 1088 */
1088/*
1089 * These are the only things you should do on a core-file: use only these
1090 * functions to write out all the necessary info.
1091 */
1092static int dump_write(struct file *file, const void *addr, int nr)
1093{
1094 return file->f_op->write(file, addr, nr, &file->f_pos) == nr;
1095}
1096
1097static int dump_seek(struct file *file, loff_t off)
1098{
1099 if (file->f_op->llseek && file->f_op->llseek != no_llseek) {
1100 if (file->f_op->llseek(file, off, SEEK_CUR) < 0)
1101 return 0;
1102 } else {
1103 char *buf = (char *)get_zeroed_page(GFP_KERNEL);
1104 if (!buf)
1105 return 0;
1106 while (off > 0) {
1107 unsigned long n = off;
1108 if (n > PAGE_SIZE)
1109 n = PAGE_SIZE;
1110 if (!dump_write(file, buf, n))
1111 return 0;
1112 off -= n;
1113 }
1114 free_page((unsigned long)buf);
1115 }
1116 return 1;
1117}
1118 1089
1119/* 1090/*
1120 * Decide what to dump of a segment, part, all or none. 1091 * Decide what to dump of a segment, part, all or none.
@@ -1249,11 +1220,6 @@ static int writenote(struct memelfnote *men, struct file *file,
1249} 1220}
1250#undef DUMP_WRITE 1221#undef DUMP_WRITE
1251 1222
1252#define DUMP_WRITE(addr, nr) \
1253 if ((size += (nr)) > cprm->limit || \
1254 !dump_write(cprm->file, (addr), (nr))) \
1255 goto end_coredump;
1256
1257static void fill_elf_header(struct elfhdr *elf, int segs, 1223static void fill_elf_header(struct elfhdr *elf, int segs,
1258 u16 machine, u32 flags, u8 osabi) 1224 u16 machine, u32 flags, u8 osabi)
1259{ 1225{
@@ -1872,6 +1838,34 @@ static struct vm_area_struct *next_vma(struct vm_area_struct *this_vma,
1872 return gate_vma; 1838 return gate_vma;
1873} 1839}
1874 1840
1841static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum,
1842 elf_addr_t e_shoff, int segs)
1843{
1844 elf->e_shoff = e_shoff;
1845 elf->e_shentsize = sizeof(*shdr4extnum);
1846 elf->e_shnum = 1;
1847 elf->e_shstrndx = SHN_UNDEF;
1848
1849 memset(shdr4extnum, 0, sizeof(*shdr4extnum));
1850
1851 shdr4extnum->sh_type = SHT_NULL;
1852 shdr4extnum->sh_size = elf->e_shnum;
1853 shdr4extnum->sh_link = elf->e_shstrndx;
1854 shdr4extnum->sh_info = segs;
1855}
1856
1857static size_t elf_core_vma_data_size(struct vm_area_struct *gate_vma,
1858 unsigned long mm_flags)
1859{
1860 struct vm_area_struct *vma;
1861 size_t size = 0;
1862
1863 for (vma = first_vma(current, gate_vma); vma != NULL;
1864 vma = next_vma(vma, gate_vma))
1865 size += vma_dump_size(vma, mm_flags);
1866 return size;
1867}
1868
1875/* 1869/*
1876 * Actual dumper 1870 * Actual dumper
1877 * 1871 *
@@ -1888,8 +1882,11 @@ static int elf_core_dump(struct coredump_params *cprm)
1888 struct vm_area_struct *vma, *gate_vma; 1882 struct vm_area_struct *vma, *gate_vma;
1889 struct elfhdr *elf = NULL; 1883 struct elfhdr *elf = NULL;
1890 loff_t offset = 0, dataoff, foffset; 1884 loff_t offset = 0, dataoff, foffset;
1891 unsigned long mm_flags;
1892 struct elf_note_info info; 1885 struct elf_note_info info;
1886 struct elf_phdr *phdr4note = NULL;
1887 struct elf_shdr *shdr4extnum = NULL;
1888 Elf_Half e_phnum;
1889 elf_addr_t e_shoff;
1893 1890
1894 /* 1891 /*
1895 * We no longer stop all VM operations. 1892 * We no longer stop all VM operations.
@@ -1912,20 +1909,25 @@ static int elf_core_dump(struct coredump_params *cprm)
1912 * Please check DEFAULT_MAX_MAP_COUNT definition when you modify here. 1909 * Please check DEFAULT_MAX_MAP_COUNT definition when you modify here.
1913 */ 1910 */
1914 segs = current->mm->map_count; 1911 segs = current->mm->map_count;
1915#ifdef ELF_CORE_EXTRA_PHDRS 1912 segs += elf_core_extra_phdrs();
1916 segs += ELF_CORE_EXTRA_PHDRS;
1917#endif
1918 1913
1919 gate_vma = get_gate_vma(current); 1914 gate_vma = get_gate_vma(current);
1920 if (gate_vma != NULL) 1915 if (gate_vma != NULL)
1921 segs++; 1916 segs++;
1922 1917
1918 /* for notes section */
1919 segs++;
1920
1921 /* If segs > PN_XNUM(0xffff), then e_phnum overflows. To avoid
1922 * this, kernel supports extended numbering. Have a look at
1923 * include/linux/elf.h for further information. */
1924 e_phnum = segs > PN_XNUM ? PN_XNUM : segs;
1925
1923 /* 1926 /*
1924 * Collect all the non-memory information about the process for the 1927 * Collect all the non-memory information about the process for the
1925 * notes. This also sets up the file header. 1928 * notes. This also sets up the file header.
1926 */ 1929 */
1927 if (!fill_note_info(elf, segs + 1, /* including notes section */ 1930 if (!fill_note_info(elf, e_phnum, &info, cprm->signr, cprm->regs))
1928 &info, cprm->signr, cprm->regs))
1929 goto cleanup; 1931 goto cleanup;
1930 1932
1931 has_dumped = 1; 1933 has_dumped = 1;
@@ -1934,31 +1936,47 @@ static int elf_core_dump(struct coredump_params *cprm)
1934 fs = get_fs(); 1936 fs = get_fs();
1935 set_fs(KERNEL_DS); 1937 set_fs(KERNEL_DS);
1936 1938
1937 DUMP_WRITE(elf, sizeof(*elf));
1938 offset += sizeof(*elf); /* Elf header */ 1939 offset += sizeof(*elf); /* Elf header */
1939 offset += (segs + 1) * sizeof(struct elf_phdr); /* Program headers */ 1940 offset += segs * sizeof(struct elf_phdr); /* Program headers */
1940 foffset = offset; 1941 foffset = offset;
1941 1942
1942 /* Write notes phdr entry */ 1943 /* Write notes phdr entry */
1943 { 1944 {
1944 struct elf_phdr phdr;
1945 size_t sz = get_note_info_size(&info); 1945 size_t sz = get_note_info_size(&info);
1946 1946
1947 sz += elf_coredump_extra_notes_size(); 1947 sz += elf_coredump_extra_notes_size();
1948 1948
1949 fill_elf_note_phdr(&phdr, sz, offset); 1949 phdr4note = kmalloc(sizeof(*phdr4note), GFP_KERNEL);
1950 if (!phdr4note)
1951 goto end_coredump;
1952
1953 fill_elf_note_phdr(phdr4note, sz, offset);
1950 offset += sz; 1954 offset += sz;
1951 DUMP_WRITE(&phdr, sizeof(phdr));
1952 } 1955 }
1953 1956
1954 dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); 1957 dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
1955 1958
1956 /* 1959 offset += elf_core_vma_data_size(gate_vma, cprm->mm_flags);
1957 * We must use the same mm->flags while dumping core to avoid 1960 offset += elf_core_extra_data_size();
1958 * inconsistency between the program headers and bodies, otherwise an 1961 e_shoff = offset;
1959 * unusable core file can be generated. 1962
1960 */ 1963 if (e_phnum == PN_XNUM) {
1961 mm_flags = current->mm->flags; 1964 shdr4extnum = kmalloc(sizeof(*shdr4extnum), GFP_KERNEL);
1965 if (!shdr4extnum)
1966 goto end_coredump;
1967 fill_extnum_info(elf, shdr4extnum, e_shoff, segs);
1968 }
1969
1970 offset = dataoff;
1971
1972 size += sizeof(*elf);
1973 if (size > cprm->limit || !dump_write(cprm->file, elf, sizeof(*elf)))
1974 goto end_coredump;
1975
1976 size += sizeof(*phdr4note);
1977 if (size > cprm->limit
1978 || !dump_write(cprm->file, phdr4note, sizeof(*phdr4note)))
1979 goto end_coredump;
1962 1980
1963 /* Write program headers for segments dump */ 1981 /* Write program headers for segments dump */
1964 for (vma = first_vma(current, gate_vma); vma != NULL; 1982 for (vma = first_vma(current, gate_vma); vma != NULL;
@@ -1969,7 +1987,7 @@ static int elf_core_dump(struct coredump_params *cprm)
1969 phdr.p_offset = offset; 1987 phdr.p_offset = offset;
1970 phdr.p_vaddr = vma->vm_start; 1988 phdr.p_vaddr = vma->vm_start;
1971 phdr.p_paddr = 0; 1989 phdr.p_paddr = 0;
1972 phdr.p_filesz = vma_dump_size(vma, mm_flags); 1990 phdr.p_filesz = vma_dump_size(vma, cprm->mm_flags);
1973 phdr.p_memsz = vma->vm_end - vma->vm_start; 1991 phdr.p_memsz = vma->vm_end - vma->vm_start;
1974 offset += phdr.p_filesz; 1992 offset += phdr.p_filesz;
1975 phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; 1993 phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0;
@@ -1979,12 +1997,14 @@ static int elf_core_dump(struct coredump_params *cprm)
1979 phdr.p_flags |= PF_X; 1997 phdr.p_flags |= PF_X;
1980 phdr.p_align = ELF_EXEC_PAGESIZE; 1998 phdr.p_align = ELF_EXEC_PAGESIZE;
1981 1999
1982 DUMP_WRITE(&phdr, sizeof(phdr)); 2000 size += sizeof(phdr);
2001 if (size > cprm->limit
2002 || !dump_write(cprm->file, &phdr, sizeof(phdr)))
2003 goto end_coredump;
1983 } 2004 }
1984 2005
1985#ifdef ELF_CORE_WRITE_EXTRA_PHDRS 2006 if (!elf_core_write_extra_phdrs(cprm->file, offset, &size, cprm->limit))
1986 ELF_CORE_WRITE_EXTRA_PHDRS; 2007 goto end_coredump;
1987#endif
1988 2008
1989 /* write out the notes section */ 2009 /* write out the notes section */
1990 if (!write_note_info(&info, cprm->file, &foffset)) 2010 if (!write_note_info(&info, cprm->file, &foffset))
@@ -2002,7 +2022,7 @@ static int elf_core_dump(struct coredump_params *cprm)
2002 unsigned long addr; 2022 unsigned long addr;
2003 unsigned long end; 2023 unsigned long end;
2004 2024
2005 end = vma->vm_start + vma_dump_size(vma, mm_flags); 2025 end = vma->vm_start + vma_dump_size(vma, cprm->mm_flags);
2006 2026
2007 for (addr = vma->vm_start; addr < end; addr += PAGE_SIZE) { 2027 for (addr = vma->vm_start; addr < end; addr += PAGE_SIZE) {
2008 struct page *page; 2028 struct page *page;
@@ -2023,15 +2043,24 @@ static int elf_core_dump(struct coredump_params *cprm)
2023 } 2043 }
2024 } 2044 }
2025 2045
2026#ifdef ELF_CORE_WRITE_EXTRA_DATA 2046 if (!elf_core_write_extra_data(cprm->file, &size, cprm->limit))
2027 ELF_CORE_WRITE_EXTRA_DATA; 2047 goto end_coredump;
2028#endif 2048
2049 if (e_phnum == PN_XNUM) {
2050 size += sizeof(*shdr4extnum);
2051 if (size > cprm->limit
2052 || !dump_write(cprm->file, shdr4extnum,
2053 sizeof(*shdr4extnum)))
2054 goto end_coredump;
2055 }
2029 2056
2030end_coredump: 2057end_coredump:
2031 set_fs(fs); 2058 set_fs(fs);
2032 2059
2033cleanup: 2060cleanup:
2034 free_note_info(&info); 2061 free_note_info(&info);
2062 kfree(shdr4extnum);
2063 kfree(phdr4note);
2035 kfree(elf); 2064 kfree(elf);
2036out: 2065out:
2037 return has_dumped; 2066 return has_dumped;