| From 9f0ab4a3f0fdb1ff404d150618ace2fa069bb2e1 Mon Sep 17 00:00:00 2001 |
| From: Roland McGrath <roland@redhat.com> |
| Date: Tue, 8 Sep 2009 19:49:40 -0700 |
| Subject: binfmt_elf: fix PT_INTERP bss handling |
| |
| From: Roland McGrath <roland@redhat.com> |
| |
| commit 9f0ab4a3f0fdb1ff404d150618ace2fa069bb2e1 upstream. |
| |
| In fs/binfmt_elf.c, load_elf_interp() calls padzero() for .bss even if |
| the PT_LOAD has no PROT_WRITE and no .bss. This generates EFAULT. |
| |
| Here is a small test case. (Yes, there are other, useful PT_INTERP |
| which have only .text and no .data/.bss.) |
| |
| ----- ptinterp.S |
| _start: .globl _start |
| nop |
| int3 |
| ----- |
| $ gcc -m32 -nostartfiles -nostdlib -o ptinterp ptinterp.S |
| $ gcc -m32 -Wl,--dynamic-linker=ptinterp -o hello hello.c |
| $ ./hello |
| Segmentation fault # during execve() itself |
| |
| After applying the patch: |
| $ ./hello |
| Trace trap # user-mode execution after execve() finishes |
| |
| If the ELF headers are actually self-inconsistent, then dying is fine. |
| But having no PROT_WRITE segment is perfectly normal and correct if |
| there is no segment with p_memsz > p_filesz (i.e. bss). John Reiser |
| suggested checking for PROT_WRITE in the bss logic. I think it makes |
| most sense to simply apply the bss logic only when there is bss. |
| |
| This patch looks less trivial than it is due to some reindentation. |
| It just moves the "if (last_bss > elf_bss) {" test up to include the |
| partial-page bss logic as well as the more-pages bss logic. |
| |
| Reported-by: John Reiser <jreiser@bitwagon.com> |
| Signed-off-by: Roland McGrath <roland@redhat.com> |
| Signed-off-by: James Morris <jmorris@namei.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| fs/binfmt_elf.c | 28 ++++++++++++++-------------- |
| 1 file changed, 14 insertions(+), 14 deletions(-) |
| |
| --- a/fs/binfmt_elf.c |
| +++ b/fs/binfmt_elf.c |
| @@ -501,22 +501,22 @@ static unsigned long load_elf_interp(str |
| } |
| } |
| |
| - /* |
| - * Now fill out the bss section. First pad the last page up |
| - * to the page boundary, and then perform a mmap to make sure |
| - * that there are zero-mapped pages up to and including the |
| - * last bss page. |
| - */ |
| - if (padzero(elf_bss)) { |
| - error = -EFAULT; |
| - goto out_close; |
| - } |
| + if (last_bss > elf_bss) { |
| + /* |
| + * Now fill out the bss section. First pad the last page up |
| + * to the page boundary, and then perform a mmap to make sure |
| + * that there are zero-mapped pages up to and including the |
| + * last bss page. |
| + */ |
| + if (padzero(elf_bss)) { |
| + error = -EFAULT; |
| + goto out_close; |
| + } |
| |
| - /* What we have mapped so far */ |
| - elf_bss = ELF_PAGESTART(elf_bss + ELF_MIN_ALIGN - 1); |
| + /* What we have mapped so far */ |
| + elf_bss = ELF_PAGESTART(elf_bss + ELF_MIN_ALIGN - 1); |
| |
| - /* Map the last of the bss segment */ |
| - if (last_bss > elf_bss) { |
| + /* Map the last of the bss segment */ |
| down_write(¤t->mm->mmap_sem); |
| error = do_brk(elf_bss, last_bss - elf_bss); |
| up_write(¤t->mm->mmap_sem); |