diff options
Diffstat (limited to 'fs/binfmt_elf.c')
-rw-r--r-- | fs/binfmt_elf.c | 66 |
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 | ||
1841 | static 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 | |||
1857 | static 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 | |||
2006 | end_coredump: | 2065 | end_coredump: |
2007 | set_fs(fs); | 2066 | set_fs(fs); |
2008 | 2067 | ||
2009 | cleanup: | 2068 | cleanup: |
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); |
2013 | out: | 2073 | out: |