diff options
Diffstat (limited to 'fs/binfmt_elf.c')
-rw-r--r-- | fs/binfmt_elf.c | 178 |
1 files changed, 92 insertions, 86 deletions
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index edd90c49003c..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> |
@@ -662,27 +663,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
662 | if (elf_interpreter[elf_ppnt->p_filesz - 1] != '\0') | 663 | if (elf_interpreter[elf_ppnt->p_filesz - 1] != '\0') |
663 | goto out_free_interp; | 664 | goto out_free_interp; |
664 | 665 | ||
665 | /* | ||
666 | * The early SET_PERSONALITY here is so that the lookup | ||
667 | * for the interpreter happens in the namespace of the | ||
668 | * to-be-execed image. SET_PERSONALITY can select an | ||
669 | * alternate root. | ||
670 | * | ||
671 | * However, SET_PERSONALITY is NOT allowed to switch | ||
672 | * this task into the new images's memory mapping | ||
673 | * policy - that is, TASK_SIZE must still evaluate to | ||
674 | * that which is appropriate to the execing application. | ||
675 | * This is because exit_mmap() needs to have TASK_SIZE | ||
676 | * evaluate to the size of the old image. | ||
677 | * | ||
678 | * So if (say) a 64-bit application is execing a 32-bit | ||
679 | * application it is the architecture's responsibility | ||
680 | * to defer changing the value of TASK_SIZE until the | ||
681 | * switch really is going to happen - do this in | ||
682 | * flush_thread(). - akpm | ||
683 | */ | ||
684 | SET_PERSONALITY(loc->elf_ex); | ||
685 | |||
686 | interpreter = open_exec(elf_interpreter); | 666 | interpreter = open_exec(elf_interpreter); |
687 | retval = PTR_ERR(interpreter); | 667 | retval = PTR_ERR(interpreter); |
688 | if (IS_ERR(interpreter)) | 668 | if (IS_ERR(interpreter)) |
@@ -730,9 +710,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
730 | /* Verify the interpreter has a valid arch */ | 710 | /* Verify the interpreter has a valid arch */ |
731 | if (!elf_check_arch(&loc->interp_elf_ex)) | 711 | if (!elf_check_arch(&loc->interp_elf_ex)) |
732 | goto out_free_dentry; | 712 | goto out_free_dentry; |
733 | } else { | ||
734 | /* Executables without an interpreter also need a personality */ | ||
735 | SET_PERSONALITY(loc->elf_ex); | ||
736 | } | 713 | } |
737 | 714 | ||
738 | /* Flush all traces of the currently running executable */ | 715 | /* Flush all traces of the currently running executable */ |
@@ -752,7 +729,8 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
752 | 729 | ||
753 | if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) | 730 | if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) |
754 | current->flags |= PF_RANDOMIZE; | 731 | current->flags |= PF_RANDOMIZE; |
755 | arch_pick_mmap_layout(current->mm); | 732 | |
733 | setup_new_exec(bprm); | ||
756 | 734 | ||
757 | /* Do this so that we can load the interpreter, if need be. We will | 735 | /* Do this so that we can load the interpreter, if need be. We will |
758 | change some of these later */ | 736 | change some of these later */ |
@@ -1108,36 +1086,6 @@ out: | |||
1108 | * Modelled on fs/exec.c:aout_core_dump() | 1086 | * Modelled on fs/exec.c:aout_core_dump() |
1109 | * Jeremy Fitzhardinge <jeremy@sw.oz.au> | 1087 | * Jeremy Fitzhardinge <jeremy@sw.oz.au> |
1110 | */ | 1088 | */ |
1111 | /* | ||
1112 | * These are the only things you should do on a core-file: use only these | ||
1113 | * functions to write out all the necessary info. | ||
1114 | */ | ||
1115 | static int dump_write(struct file *file, const void *addr, int nr) | ||
1116 | { | ||
1117 | return file->f_op->write(file, addr, nr, &file->f_pos) == nr; | ||
1118 | } | ||
1119 | |||
1120 | static int dump_seek(struct file *file, loff_t off) | ||
1121 | { | ||
1122 | if (file->f_op->llseek && file->f_op->llseek != no_llseek) { | ||
1123 | if (file->f_op->llseek(file, off, SEEK_CUR) < 0) | ||
1124 | return 0; | ||
1125 | } else { | ||
1126 | char *buf = (char *)get_zeroed_page(GFP_KERNEL); | ||
1127 | if (!buf) | ||
1128 | return 0; | ||
1129 | while (off > 0) { | ||
1130 | unsigned long n = off; | ||
1131 | if (n > PAGE_SIZE) | ||
1132 | n = PAGE_SIZE; | ||
1133 | if (!dump_write(file, buf, n)) | ||
1134 | return 0; | ||
1135 | off -= n; | ||
1136 | } | ||
1137 | free_page((unsigned long)buf); | ||
1138 | } | ||
1139 | return 1; | ||
1140 | } | ||
1141 | 1089 | ||
1142 | /* | 1090 | /* |
1143 | * Decide what to dump of a segment, part, all or none. | 1091 | * Decide what to dump of a segment, part, all or none. |
@@ -1272,11 +1220,6 @@ static int writenote(struct memelfnote *men, struct file *file, | |||
1272 | } | 1220 | } |
1273 | #undef DUMP_WRITE | 1221 | #undef DUMP_WRITE |
1274 | 1222 | ||
1275 | #define DUMP_WRITE(addr, nr) \ | ||
1276 | if ((size += (nr)) > cprm->limit || \ | ||
1277 | !dump_write(cprm->file, (addr), (nr))) \ | ||
1278 | goto end_coredump; | ||
1279 | |||
1280 | static void fill_elf_header(struct elfhdr *elf, int segs, | 1223 | static void fill_elf_header(struct elfhdr *elf, int segs, |
1281 | u16 machine, u32 flags, u8 osabi) | 1224 | u16 machine, u32 flags, u8 osabi) |
1282 | { | 1225 | { |
@@ -1895,6 +1838,34 @@ static struct vm_area_struct *next_vma(struct vm_area_struct *this_vma, | |||
1895 | return gate_vma; | 1838 | return gate_vma; |
1896 | } | 1839 | } |
1897 | 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 | |||
1898 | /* | 1869 | /* |
1899 | * Actual dumper | 1870 | * Actual dumper |
1900 | * | 1871 | * |
@@ -1911,8 +1882,11 @@ static int elf_core_dump(struct coredump_params *cprm) | |||
1911 | struct vm_area_struct *vma, *gate_vma; | 1882 | struct vm_area_struct *vma, *gate_vma; |
1912 | struct elfhdr *elf = NULL; | 1883 | struct elfhdr *elf = NULL; |
1913 | loff_t offset = 0, dataoff, foffset; | 1884 | loff_t offset = 0, dataoff, foffset; |
1914 | unsigned long mm_flags; | ||
1915 | 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; | ||
1916 | 1890 | ||
1917 | /* | 1891 | /* |
1918 | * We no longer stop all VM operations. | 1892 | * We no longer stop all VM operations. |
@@ -1935,20 +1909,25 @@ static int elf_core_dump(struct coredump_params *cprm) | |||
1935 | * Please check DEFAULT_MAX_MAP_COUNT definition when you modify here. | 1909 | * Please check DEFAULT_MAX_MAP_COUNT definition when you modify here. |
1936 | */ | 1910 | */ |
1937 | segs = current->mm->map_count; | 1911 | segs = current->mm->map_count; |
1938 | #ifdef ELF_CORE_EXTRA_PHDRS | 1912 | segs += elf_core_extra_phdrs(); |
1939 | segs += ELF_CORE_EXTRA_PHDRS; | ||
1940 | #endif | ||
1941 | 1913 | ||
1942 | gate_vma = get_gate_vma(current); | 1914 | gate_vma = get_gate_vma(current); |
1943 | if (gate_vma != NULL) | 1915 | if (gate_vma != NULL) |
1944 | segs++; | 1916 | segs++; |
1945 | 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 | |||
1946 | /* | 1926 | /* |
1947 | * Collect all the non-memory information about the process for the | 1927 | * Collect all the non-memory information about the process for the |
1948 | * notes. This also sets up the file header. | 1928 | * notes. This also sets up the file header. |
1949 | */ | 1929 | */ |
1950 | if (!fill_note_info(elf, segs + 1, /* including notes section */ | 1930 | if (!fill_note_info(elf, e_phnum, &info, cprm->signr, cprm->regs)) |
1951 | &info, cprm->signr, cprm->regs)) | ||
1952 | goto cleanup; | 1931 | goto cleanup; |
1953 | 1932 | ||
1954 | has_dumped = 1; | 1933 | has_dumped = 1; |
@@ -1957,31 +1936,47 @@ static int elf_core_dump(struct coredump_params *cprm) | |||
1957 | fs = get_fs(); | 1936 | fs = get_fs(); |
1958 | set_fs(KERNEL_DS); | 1937 | set_fs(KERNEL_DS); |
1959 | 1938 | ||
1960 | DUMP_WRITE(elf, sizeof(*elf)); | ||
1961 | offset += sizeof(*elf); /* Elf header */ | 1939 | offset += sizeof(*elf); /* Elf header */ |
1962 | offset += (segs + 1) * sizeof(struct elf_phdr); /* Program headers */ | 1940 | offset += segs * sizeof(struct elf_phdr); /* Program headers */ |
1963 | foffset = offset; | 1941 | foffset = offset; |
1964 | 1942 | ||
1965 | /* Write notes phdr entry */ | 1943 | /* Write notes phdr entry */ |
1966 | { | 1944 | { |
1967 | struct elf_phdr phdr; | ||
1968 | size_t sz = get_note_info_size(&info); | 1945 | size_t sz = get_note_info_size(&info); |
1969 | 1946 | ||
1970 | sz += elf_coredump_extra_notes_size(); | 1947 | sz += elf_coredump_extra_notes_size(); |
1971 | 1948 | ||
1972 | 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); | ||
1973 | offset += sz; | 1954 | offset += sz; |
1974 | DUMP_WRITE(&phdr, sizeof(phdr)); | ||
1975 | } | 1955 | } |
1976 | 1956 | ||
1977 | dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); | 1957 | dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); |
1978 | 1958 | ||
1979 | /* | 1959 | offset += elf_core_vma_data_size(gate_vma, cprm->mm_flags); |
1980 | * We must use the same mm->flags while dumping core to avoid | 1960 | offset += elf_core_extra_data_size(); |
1981 | * inconsistency between the program headers and bodies, otherwise an | 1961 | e_shoff = offset; |
1982 | * unusable core file can be generated. | 1962 | |
1983 | */ | 1963 | if (e_phnum == PN_XNUM) { |
1984 | 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; | ||
1985 | 1980 | ||
1986 | /* Write program headers for segments dump */ | 1981 | /* Write program headers for segments dump */ |
1987 | for (vma = first_vma(current, gate_vma); vma != NULL; | 1982 | for (vma = first_vma(current, gate_vma); vma != NULL; |
@@ -1992,7 +1987,7 @@ static int elf_core_dump(struct coredump_params *cprm) | |||
1992 | phdr.p_offset = offset; | 1987 | phdr.p_offset = offset; |
1993 | phdr.p_vaddr = vma->vm_start; | 1988 | phdr.p_vaddr = vma->vm_start; |
1994 | phdr.p_paddr = 0; | 1989 | phdr.p_paddr = 0; |
1995 | phdr.p_filesz = vma_dump_size(vma, mm_flags); | 1990 | phdr.p_filesz = vma_dump_size(vma, cprm->mm_flags); |
1996 | phdr.p_memsz = vma->vm_end - vma->vm_start; | 1991 | phdr.p_memsz = vma->vm_end - vma->vm_start; |
1997 | offset += phdr.p_filesz; | 1992 | offset += phdr.p_filesz; |
1998 | phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; | 1993 | phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; |
@@ -2002,12 +1997,14 @@ static int elf_core_dump(struct coredump_params *cprm) | |||
2002 | phdr.p_flags |= PF_X; | 1997 | phdr.p_flags |= PF_X; |
2003 | phdr.p_align = ELF_EXEC_PAGESIZE; | 1998 | phdr.p_align = ELF_EXEC_PAGESIZE; |
2004 | 1999 | ||
2005 | 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; | ||
2006 | } | 2004 | } |
2007 | 2005 | ||
2008 | #ifdef ELF_CORE_WRITE_EXTRA_PHDRS | 2006 | if (!elf_core_write_extra_phdrs(cprm->file, offset, &size, cprm->limit)) |
2009 | ELF_CORE_WRITE_EXTRA_PHDRS; | 2007 | goto end_coredump; |
2010 | #endif | ||
2011 | 2008 | ||
2012 | /* write out the notes section */ | 2009 | /* write out the notes section */ |
2013 | if (!write_note_info(&info, cprm->file, &foffset)) | 2010 | if (!write_note_info(&info, cprm->file, &foffset)) |
@@ -2025,7 +2022,7 @@ static int elf_core_dump(struct coredump_params *cprm) | |||
2025 | unsigned long addr; | 2022 | unsigned long addr; |
2026 | unsigned long end; | 2023 | unsigned long end; |
2027 | 2024 | ||
2028 | end = vma->vm_start + vma_dump_size(vma, mm_flags); | 2025 | end = vma->vm_start + vma_dump_size(vma, cprm->mm_flags); |
2029 | 2026 | ||
2030 | for (addr = vma->vm_start; addr < end; addr += PAGE_SIZE) { | 2027 | for (addr = vma->vm_start; addr < end; addr += PAGE_SIZE) { |
2031 | struct page *page; | 2028 | struct page *page; |
@@ -2046,15 +2043,24 @@ static int elf_core_dump(struct coredump_params *cprm) | |||
2046 | } | 2043 | } |
2047 | } | 2044 | } |
2048 | 2045 | ||
2049 | #ifdef ELF_CORE_WRITE_EXTRA_DATA | 2046 | if (!elf_core_write_extra_data(cprm->file, &size, cprm->limit)) |
2050 | ELF_CORE_WRITE_EXTRA_DATA; | 2047 | goto end_coredump; |
2051 | #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 | } | ||
2052 | 2056 | ||
2053 | end_coredump: | 2057 | end_coredump: |
2054 | set_fs(fs); | 2058 | set_fs(fs); |
2055 | 2059 | ||
2056 | cleanup: | 2060 | cleanup: |
2057 | free_note_info(&info); | 2061 | free_note_info(&info); |
2062 | kfree(shdr4extnum); | ||
2063 | kfree(phdr4note); | ||
2058 | kfree(elf); | 2064 | kfree(elf); |
2059 | out: | 2065 | out: |
2060 | return has_dumped; | 2066 | return has_dumped; |