Messages in this thread | | | Subject | Re: serious performance regression due to NX patch | From | Daniel McNeil <> | Date | Tue, 13 Jul 2004 09:49:43 -0700 |
| |
On Tue, 2004-07-13 at 09:05, Mark Haverkamp wrote: > I think that there is a problem with this piece of code in > binfmt_elf.c: > > if (i == elf_ex.e_phnum) > def_flags |= VM_EXEC | VM_MAYEXEC; > > I've seen that if this code is executed that a mmap with PROT_NONE will > have the x flag set on the page. because of code in mmap.c for > do_mmp_pgoff: > > vm_flags = calc_vm_prot_bits(prot) | calc_vm_flag_bits(flags) | > mm->def_flags | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC; > > or possibly here in do_brk: > > flags = VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT | mm->def_flags; > > > the mm->def_flags have VM_EXEC and VM_MAYEXEC which means they are set all the time. > > Mark.
This was my email to Andrew yesterday that did not seem to make it to LKML (probably because I attached some elf binaries -- I made them links now). The below program shows the old binaries without the PT_GNU_STACK do not get PROT_NONE mmaps. See info below.
Daniel
On Fri, 2004-07-09 at 23:45, Andrew Morton wrote:
> #include <unistd.h> > #include <errno.h> > #include <sys/mman.h> > > > main() > { > char *p0 = 0; > char *p1 = (char *)-1; > char *p2; > int err; > > p2 = mmap(0, 4096, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); > > printf("p2=%p\n", p2); > printf("pid=%d\n", getpid()); > > getchar(); > > errno = 0; > err = access(p0, R_OK); > printf("access 0 ptr %p return code %d errno %d\n", p0, err, errno); > perror("access result:"); > errno = 0; > err = access(p1, R_OK); > printf("access 1 ptr %p return code %d errno %d\n", p1, err, errno); > perror("access result:"); > errno = 0; > err = access(p2, R_OK); > printf("access 2 ptr %p return code %d errno %d\n", p2, err, errno); > perror("access result:"); > } > > vmm:/home/akpm> ./x > p2=0x40000000 > pid=2038 > > access 0 ptr (nil) return code -1 errno 14 > access result:: Bad address > access 1 ptr 0xffffffff return code -1 errno 14 > access result:: Bad address > access 2 ptr 0x40000000 return code -1 errno 14 > access result:: Bad address > > I get this result on both p4 xeon and p3 xeon.
It is the elf file that makes the difference. I was using gcc 3.2.2 and ld (GNU ld version 2.13.90.0.18 20030206). This produces elf binary without the PT_GNU_STACK program section (from objdump -p x.gcc322)
Program Header: PHDR off 0x00000034 vaddr 0x08048034 paddr 0x08048034 align 2**2 filesz 0x000000c0 memsz 0x000000c0 flags r-x INTERP off 0x000000f4 vaddr 0x080480f4 paddr 0x080480f4 align 2**0 filesz 0x00000013 memsz 0x00000013 flags r-- LOAD off 0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12 filesz 0x00000750 memsz 0x00000750 flags r-x LOAD off 0x00000750 vaddr 0x08049750 paddr 0x08049750 align 2**12 filesz 0x00000118 memsz 0x0000011c flags rw- DYNAMIC off 0x0000075c vaddr 0x0804975c paddr 0x0804975c align 2**2 filesz 0x000000c8 memsz 0x000000c8 flags rw- NOTE off 0x00000108 vaddr 0x08048108 paddr 0x08048108 align 2**2 filesz 0x00000020 memsz 0x00000020 flags r--
With gcc 3.4.1 and GNU ld version 2.14.90.0.6 20030820 and compile with cc -o x.rw -z noexecstack x.c produces a elf binary without execute permission on the stack. (from objdump -p x.rw)
Program Header: PHDR off 0x00000034 vaddr 0x08048034 paddr 0x08048034 align 2**2 filesz 0x000000e0 memsz 0x000000e0 flags r-x INTERP off 0x00000114 vaddr 0x08048114 paddr 0x08048114 align 2**0 filesz 0x00000013 memsz 0x00000013 flags r-- LOAD off 0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12 filesz 0x00000735 memsz 0x00000735 flags r-x LOAD off 0x00000738 vaddr 0x08049738 paddr 0x08049738 align 2**12 filesz 0x0000011c memsz 0x00000120 flags rw- DYNAMIC off 0x00000748 vaddr 0x08049748 paddr 0x08049748 align 2**2 filesz 0x000000c8 memsz 0x000000c8 flags rw- NOTE off 0x00000128 vaddr 0x08048128 paddr 0x08048128 align 2**2 filesz 0x00000020 memsz 0x00000020 flags r-- STACK off 0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**2 filesz 0x00000000 memsz 0x00000000 flags rw-
With gcc 3.4.1 and GNU ld version 2.14.90.0.6 20030820 and compiled with cc -o x.rwx -z execstack x.c. This produces the same binary as with out the "-z execstack".
Program Header: PHDR off 0x00000034 vaddr 0x08048034 paddr 0x08048034 align 2**2 filesz 0x000000e0 memsz 0x000000e0 flags r-x INTERP off 0x00000114 vaddr 0x08048114 paddr 0x08048114 align 2**0 filesz 0x00000013 memsz 0x00000013 flags r-- LOAD off 0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12 filesz 0x00000735 memsz 0x00000735 flags r-x LOAD off 0x00000738 vaddr 0x08049738 paddr 0x08049738 align 2**12 filesz 0x0000011c memsz 0x00000120 flags rw- DYNAMIC off 0x00000748 vaddr 0x08049748 paddr 0x08049748 align 2**2 filesz 0x000000c8 memsz 0x000000c8 flags rw- NOTE off 0x00000128 vaddr 0x08048128 paddr 0x08048128 align 2**2 filesz 0x00000020 memsz 0x00000020 flags r-- 0x6474e551 off 0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**2 filesz 0x00000000 memsz 0x00000000 flags rwx
Here's the corresponding /proc/pid/maps output from the 3 different binaries:
x.gcc322: 40013000-40014000 --xp 40013000 00:00 0 x.rw: 40013000-40014000 ---p 40013000 00:00 0 x.rwx: 40013000-40014000 ---p 40013000 00:00 0
So binaries compiled with an old compiler are not being handled correctly with the nx-update.patch changes.
In load_elf_binary()
for (i = 0; i < elf_ex.e_phnum; i++, elf_ppnt++) if (elf_ppnt->p_type == PT_GNU_STACK) { if (elf_ppnt->p_flags & PF_X) executable_stack = EXSTACK_ENABLE_X; else executable_stack = EXSTACK_DISABLE_X; break; } if (i == elf_ex.e_phnum) def_flags |= VM_EXEC | VM_MAYEXEC;
This setting of def_flags if the PT_GNU_STACK is NOT found is causing the old binaries to get exec on PROT_NONE mmaps.
The 3 elf binaries can be found here: http://developer.osdl.org/daniel/mmap.PROT_NONE.bug/
Daniel
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |