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.c66
1 files changed, 63 insertions, 3 deletions
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 6fc49b6ed936..78de530cfb02 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -1838,6 +1838,34 @@ static struct vm_area_struct *next_vma(struct vm_area_struct *this_vma,
1838 return gate_vma; 1838 return gate_vma;
1839} 1839}
1840 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
1841/* 1869/*
1842 * Actual dumper 1870 * Actual dumper
1843 * 1871 *
@@ -1857,6 +1885,9 @@ static int elf_core_dump(struct coredump_params *cprm)
1857 unsigned long mm_flags; 1885 unsigned long mm_flags;
1858 struct elf_note_info info; 1886 struct elf_note_info info;
1859 struct elf_phdr *phdr4note = NULL; 1887 struct elf_phdr *phdr4note = NULL;
1888 struct elf_shdr *shdr4extnum = NULL;
1889 Elf_Half e_phnum;
1890 elf_addr_t e_shoff;
1860 1891
1861 /* 1892 /*
1862 * We no longer stop all VM operations. 1893 * We no longer stop all VM operations.
@@ -1885,12 +1916,19 @@ static int elf_core_dump(struct coredump_params *cprm)
1885 if (gate_vma != NULL) 1916 if (gate_vma != NULL)
1886 segs++; 1917 segs++;
1887 1918
1919 /* for notes section */
1920 segs++;
1921
1922 /* If segs > PN_XNUM(0xffff), then e_phnum overflows. To avoid
1923 * this, kernel supports extended numbering. Have a look at
1924 * include/linux/elf.h for further information. */
1925 e_phnum = segs > PN_XNUM ? PN_XNUM : segs;
1926
1888 /* 1927 /*
1889 * Collect all the non-memory information about the process for the 1928 * Collect all the non-memory information about the process for the
1890 * notes. This also sets up the file header. 1929 * notes. This also sets up the file header.
1891 */ 1930 */
1892 if (!fill_note_info(elf, segs + 1, /* including notes section */ 1931 if (!fill_note_info(elf, e_phnum, &info, cprm->signr, cprm->regs))
1893 &info, cprm->signr, cprm->regs))
1894 goto cleanup; 1932 goto cleanup;
1895 1933
1896 has_dumped = 1; 1934 has_dumped = 1;
@@ -1900,7 +1938,7 @@ static int elf_core_dump(struct coredump_params *cprm)
1900 set_fs(KERNEL_DS); 1938 set_fs(KERNEL_DS);
1901 1939
1902 offset += sizeof(*elf); /* Elf header */ 1940 offset += sizeof(*elf); /* Elf header */
1903 offset += (segs + 1) * sizeof(struct elf_phdr); /* Program headers */ 1941 offset += segs * sizeof(struct elf_phdr); /* Program headers */
1904 foffset = offset; 1942 foffset = offset;
1905 1943
1906 /* Write notes phdr entry */ 1944 /* Write notes phdr entry */
@@ -1926,6 +1964,19 @@ static int elf_core_dump(struct coredump_params *cprm)
1926 */ 1964 */
1927 mm_flags = current->mm->flags; 1965 mm_flags = current->mm->flags;
1928 1966
1967 offset += elf_core_vma_data_size(gate_vma, mm_flags);
1968 offset += elf_core_extra_data_size();
1969 e_shoff = offset;
1970
1971 if (e_phnum == PN_XNUM) {
1972 shdr4extnum = kmalloc(sizeof(*shdr4extnum), GFP_KERNEL);
1973 if (!shdr4extnum)
1974 goto end_coredump;
1975 fill_extnum_info(elf, shdr4extnum, e_shoff, segs);
1976 }
1977
1978 offset = dataoff;
1979
1929 size += sizeof(*elf); 1980 size += sizeof(*elf);
1930 if (size > cprm->limit || !dump_write(cprm->file, elf, sizeof(*elf))) 1981 if (size > cprm->limit || !dump_write(cprm->file, elf, sizeof(*elf)))
1931 goto end_coredump; 1982 goto end_coredump;
@@ -2003,11 +2054,20 @@ static int elf_core_dump(struct coredump_params *cprm)
2003 if (!elf_core_write_extra_data(cprm->file, &size, cprm->limit)) 2054 if (!elf_core_write_extra_data(cprm->file, &size, cprm->limit))
2004 goto end_coredump; 2055 goto end_coredump;
2005 2056
2057 if (e_phnum == PN_XNUM) {
2058 size += sizeof(*shdr4extnum);
2059 if (size > cprm->limit
2060 || !dump_write(cprm->file, shdr4extnum,
2061 sizeof(*shdr4extnum)))
2062 goto end_coredump;
2063 }
2064
2006end_coredump: 2065end_coredump:
2007 set_fs(fs); 2066 set_fs(fs);
2008 2067
2009cleanup: 2068cleanup:
2010 free_note_info(&info); 2069 free_note_info(&info);
2070 kfree(shdr4extnum);
2011 kfree(phdr4note); 2071 kfree(phdr4note);
2012 kfree(elf); 2072 kfree(elf);
2013out: 2073out: