On Wed, May 23, 2007 at 10:50:24AM +0200, Jiri Kosina wrote: > From: Jan Kratochvil <[EMAIL PROTECTED]> > > This patch is using mmap()'s randomization functionality in such a way > that it maps the main executable of (specially compiled/linked -pie/-fpie) > ET_DYN binaries onto a random address (in cases in which mmap() is allowed > to perform a randomization). > > Origin of this patch is in exec-shield > (http://people.redhat.com/mingo/exec-shield/) > > Signed-off-by: Jan Kratochvil <[EMAIL PROTECTED]> > Signed-off-by: Jiri Kosina <[EMAIL PROTECTED]> > Cc: Ingo Molnar <[EMAIL PROTECTED]> > Cc: Roland McGrath <[EMAIL PROTECTED]> > Cc: Jakub Jelinek <[EMAIL PROTECTED]>
> -#define BAD_ADDR(x) ((unsigned long)(x) >= TASK_SIZE) > +#define BAD_ADDR(x) ((unsigned long)(x) >= PAGE_MASK) ... > @@ -442,8 +491,7 @@ static unsigned long load_elf_interp(str > goto out_close; > } > > - *interp_load_addr = load_addr; > - error = ((unsigned long)interp_elf_ex->e_entry) + load_addr; > + error = load_addr; ... > if (elf_interpreter) { > - if (interpreter_type == INTERPRETER_AOUT) > + if (interpreter_type == INTERPRETER_AOUT) { > elf_entry = load_aout_interp(&loc->interp_ex, > interpreter); > - else > + } else { > + unsigned long interp_map_addr; /* unused */ > + > elf_entry = load_elf_interp(&loc->interp_elf_ex, > interpreter, > - &interp_load_addr); > + &interp_map_addr, > + load_bias); > + if (!BAD_ADDR(elf_entry)) { > + /* > + * load_elf_interp() returns relocation > + * adjustment > + */ > + interp_load_addr = elf_entry; > + elf_entry += loc->interp_elf_ex.e_entry; > + } > + } > if (BAD_ADDR(elf_entry)) { > force_sig(SIGSEGV, current); > retval = IS_ERR((void *)elf_entry) ? The above highlighted changes are the cause of random segfaults of PIE binaries. See https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=246623 The problem is if ld.so is prelinked to some address in the area where the kernel actually maps it, particularly if elf_map in load_elf_interp returns an address one page below its first PT_LOAD segments vaddr. Then load_addr (it is a load bias actually) returned from load_elf_interp is 0xfffff000 (on 32-bit kernels) and BAD_ADDR are all addresses >= 0xfffff000 (on i?86). The fix should be either changing the definition of BAD_ADDR to e.g. IS_ERR_VALUE(x), or at least changing the if (!BAD_ADDR(elf_entry)) { above to if (!IS_ERR_VALUE(elf_entry)) {, the second BAD_ADDR can already stay, because at that place elf_entry is no longer a bias (difference between actual and preferred load address), but an actual address, where very high addresses are of course invalid. Jakub - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/