aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Kratochvil <honza@jikos.cz>2007-07-16 02:40:06 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-16 12:05:42 -0400
commit60bfba7e85f88fe834e623ead799cf580de20971 (patch)
treed27468bc99bfbe8dcfa6fa0e8b8599d2a6e6c7de
parentf057eac0d7ad967138390a9dd7fd8267e1e39d19 (diff)
PIE randomization
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/) [jkosina@suse.cz: pie randomization: fix BAD_ADDR macro] Signed-off-by: Jan Kratochvil <honza@jikos.cz> Signed-off-by: Jiri Kosina <jkosina@suse.cz> Cc: Ingo Molnar <mingo@elte.hu> Cc: Roland McGrath <roland@redhat.com> Cc: Jakub Jelinek <jakub@redhat.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--arch/ia64/ia32/binfmt_elf32.c2
-rw-r--r--fs/binfmt_elf.c109
2 files changed, 87 insertions, 24 deletions
diff --git a/arch/ia64/ia32/binfmt_elf32.c b/arch/ia64/ia32/binfmt_elf32.c
index c05bda662364..6f4d3d06f0ed 100644
--- a/arch/ia64/ia32/binfmt_elf32.c
+++ b/arch/ia64/ia32/binfmt_elf32.c
@@ -261,7 +261,7 @@ elf32_set_personality (void)
261} 261}
262 262
263static unsigned long 263static unsigned long
264elf32_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type) 264elf32_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type, unsigned long unused)
265{ 265{
266 unsigned long pgoff = (eppnt->p_vaddr) & ~IA32_PAGE_MASK; 266 unsigned long pgoff = (eppnt->p_vaddr) & ~IA32_PAGE_MASK;
267 267
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 08e4414b8374..5cfa735639ae 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -45,7 +45,7 @@
45 45
46static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs); 46static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs);
47static int load_elf_library(struct file *); 47static int load_elf_library(struct file *);
48static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int); 48static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int, unsigned long);
49 49
50/* 50/*
51 * If we don't support core dumping, then supply a NULL so we 51 * If we don't support core dumping, then supply a NULL so we
@@ -80,7 +80,7 @@ static struct linux_binfmt elf_format = {
80 .hasvdso = 1 80 .hasvdso = 1
81}; 81};
82 82
83#define BAD_ADDR(x) ((unsigned long)(x) >= TASK_SIZE) 83#define BAD_ADDR(x) IS_ERR_VALUE(x)
84 84
85static int set_brk(unsigned long start, unsigned long end) 85static int set_brk(unsigned long start, unsigned long end)
86{ 86{
@@ -285,33 +285,70 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
285#ifndef elf_map 285#ifndef elf_map
286 286
287static unsigned long elf_map(struct file *filep, unsigned long addr, 287static unsigned long elf_map(struct file *filep, unsigned long addr,
288 struct elf_phdr *eppnt, int prot, int type) 288 struct elf_phdr *eppnt, int prot, int type,
289 unsigned long total_size)
289{ 290{
290 unsigned long map_addr; 291 unsigned long map_addr;
291 unsigned long pageoffset = ELF_PAGEOFFSET(eppnt->p_vaddr); 292 unsigned long size = eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr);
293 unsigned long off = eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr);
294 addr = ELF_PAGESTART(addr);
295 size = ELF_PAGEALIGN(size);
292 296
293 down_write(&current->mm->mmap_sem);
294 /* mmap() will return -EINVAL if given a zero size, but a 297 /* mmap() will return -EINVAL if given a zero size, but a
295 * segment with zero filesize is perfectly valid */ 298 * segment with zero filesize is perfectly valid */
296 if (eppnt->p_filesz + pageoffset) 299 if (!size)
297 map_addr = do_mmap(filep, ELF_PAGESTART(addr), 300 return addr;
298 eppnt->p_filesz + pageoffset, prot, type, 301
299 eppnt->p_offset - pageoffset); 302 down_write(&current->mm->mmap_sem);
300 else 303 /*
301 map_addr = ELF_PAGESTART(addr); 304 * total_size is the size of the ELF (interpreter) image.
305 * The _first_ mmap needs to know the full size, otherwise
306 * randomization might put this image into an overlapping
307 * position with the ELF binary image. (since size < total_size)
308 * So we first map the 'big' image - and unmap the remainder at
309 * the end. (which unmap is needed for ELF images with holes.)
310 */
311 if (total_size) {
312 total_size = ELF_PAGEALIGN(total_size);
313 map_addr = do_mmap(filep, addr, total_size, prot, type, off);
314 if (!BAD_ADDR(map_addr))
315 do_munmap(current->mm, map_addr+size, total_size-size);
316 } else
317 map_addr = do_mmap(filep, addr, size, prot, type, off);
318
302 up_write(&current->mm->mmap_sem); 319 up_write(&current->mm->mmap_sem);
303 return(map_addr); 320 return(map_addr);
304} 321}
305 322
306#endif /* !elf_map */ 323#endif /* !elf_map */
307 324
325static unsigned long total_mapping_size(struct elf_phdr *cmds, int nr)
326{
327 int i, first_idx = -1, last_idx = -1;
328
329 for (i = 0; i < nr; i++) {
330 if (cmds[i].p_type == PT_LOAD) {
331 last_idx = i;
332 if (first_idx == -1)
333 first_idx = i;
334 }
335 }
336 if (first_idx == -1)
337 return 0;
338
339 return cmds[last_idx].p_vaddr + cmds[last_idx].p_memsz -
340 ELF_PAGESTART(cmds[first_idx].p_vaddr);
341}
342
343
308/* This is much more generalized than the library routine read function, 344/* This is much more generalized than the library routine read function,
309 so we keep this separate. Technically the library read function 345 so we keep this separate. Technically the library read function
310 is only provided so that we can read a.out libraries that have 346 is only provided so that we can read a.out libraries that have
311 an ELF header */ 347 an ELF header */
312 348
313static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, 349static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
314 struct file *interpreter, unsigned long *interp_load_addr) 350 struct file *interpreter, unsigned long *interp_map_addr,
351 unsigned long no_base)
315{ 352{
316 struct elf_phdr *elf_phdata; 353 struct elf_phdr *elf_phdata;
317 struct elf_phdr *eppnt; 354 struct elf_phdr *eppnt;
@@ -319,6 +356,7 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
319 int load_addr_set = 0; 356 int load_addr_set = 0;
320 unsigned long last_bss = 0, elf_bss = 0; 357 unsigned long last_bss = 0, elf_bss = 0;
321 unsigned long error = ~0UL; 358 unsigned long error = ~0UL;
359 unsigned long total_size;
322 int retval, i, size; 360 int retval, i, size;
323 361
324 /* First of all, some simple consistency checks */ 362 /* First of all, some simple consistency checks */
@@ -357,6 +395,12 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
357 goto out_close; 395 goto out_close;
358 } 396 }
359 397
398 total_size = total_mapping_size(elf_phdata, interp_elf_ex->e_phnum);
399 if (!total_size) {
400 error = -EINVAL;
401 goto out_close;
402 }
403
360 eppnt = elf_phdata; 404 eppnt = elf_phdata;
361 for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) { 405 for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) {
362 if (eppnt->p_type == PT_LOAD) { 406 if (eppnt->p_type == PT_LOAD) {
@@ -374,9 +418,14 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
374 vaddr = eppnt->p_vaddr; 418 vaddr = eppnt->p_vaddr;
375 if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) 419 if (interp_elf_ex->e_type == ET_EXEC || load_addr_set)
376 elf_type |= MAP_FIXED; 420 elf_type |= MAP_FIXED;
421 else if (no_base && interp_elf_ex->e_type == ET_DYN)
422 load_addr = -vaddr;
377 423
378 map_addr = elf_map(interpreter, load_addr + vaddr, 424 map_addr = elf_map(interpreter, load_addr + vaddr,
379 eppnt, elf_prot, elf_type); 425 eppnt, elf_prot, elf_type, total_size);
426 total_size = 0;
427 if (!*interp_map_addr)
428 *interp_map_addr = map_addr;
380 error = map_addr; 429 error = map_addr;
381 if (BAD_ADDR(map_addr)) 430 if (BAD_ADDR(map_addr))
382 goto out_close; 431 goto out_close;
@@ -442,8 +491,7 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
442 goto out_close; 491 goto out_close;
443 } 492 }
444 493
445 *interp_load_addr = load_addr; 494 error = load_addr;
446 error = ((unsigned long)interp_elf_ex->e_entry) + load_addr;
447 495
448out_close: 496out_close:
449 kfree(elf_phdata); 497 kfree(elf_phdata);
@@ -540,7 +588,8 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
540 int elf_exec_fileno; 588 int elf_exec_fileno;
541 int retval, i; 589 int retval, i;
542 unsigned int size; 590 unsigned int size;
543 unsigned long elf_entry, interp_load_addr = 0; 591 unsigned long elf_entry;
592 unsigned long interp_load_addr = 0;
544 unsigned long start_code, end_code, start_data, end_data; 593 unsigned long start_code, end_code, start_data, end_data;
545 unsigned long reloc_func_desc = 0; 594 unsigned long reloc_func_desc = 0;
546 char passed_fileno[6]; 595 char passed_fileno[6];
@@ -808,9 +857,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
808 current->mm->start_stack = bprm->p; 857 current->mm->start_stack = bprm->p;
809 858
810 /* Now we do a little grungy work by mmaping the ELF image into 859 /* Now we do a little grungy work by mmaping the ELF image into
811 the correct location in memory. At this point, we assume that 860 the correct location in memory. */
812 the image should be loaded at fixed address, not at a variable
813 address. */
814 for(i = 0, elf_ppnt = elf_phdata; 861 for(i = 0, elf_ppnt = elf_phdata;
815 i < loc->elf_ex.e_phnum; i++, elf_ppnt++) { 862 i < loc->elf_ex.e_phnum; i++, elf_ppnt++) {
816 int elf_prot = 0, elf_flags; 863 int elf_prot = 0, elf_flags;
@@ -864,11 +911,15 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
864 * default mmap base, as well as whatever program they 911 * default mmap base, as well as whatever program they
865 * might try to exec. This is because the brk will 912 * might try to exec. This is because the brk will
866 * follow the loader, and is not movable. */ 913 * follow the loader, and is not movable. */
914#ifdef CONFIG_X86
915 load_bias = 0;
916#else
867 load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr); 917 load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr);
918#endif
868 } 919 }
869 920
870 error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, 921 error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt,
871 elf_prot, elf_flags); 922 elf_prot, elf_flags,0);
872 if (BAD_ADDR(error)) { 923 if (BAD_ADDR(error)) {
873 send_sig(SIGKILL, current, 0); 924 send_sig(SIGKILL, current, 0);
874 retval = IS_ERR((void *)error) ? 925 retval = IS_ERR((void *)error) ?
@@ -944,13 +995,25 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
944 } 995 }
945 996
946 if (elf_interpreter) { 997 if (elf_interpreter) {
947 if (interpreter_type == INTERPRETER_AOUT) 998 if (interpreter_type == INTERPRETER_AOUT) {
948 elf_entry = load_aout_interp(&loc->interp_ex, 999 elf_entry = load_aout_interp(&loc->interp_ex,
949 interpreter); 1000 interpreter);
950 else 1001 } else {
1002 unsigned long interp_map_addr; /* unused */
1003
951 elf_entry = load_elf_interp(&loc->interp_elf_ex, 1004 elf_entry = load_elf_interp(&loc->interp_elf_ex,
952 interpreter, 1005 interpreter,
953 &interp_load_addr); 1006 &interp_map_addr,
1007 load_bias);
1008 if (!BAD_ADDR(elf_entry)) {
1009 /*
1010 * load_elf_interp() returns relocation
1011 * adjustment
1012 */
1013 interp_load_addr = elf_entry;
1014 elf_entry += loc->interp_elf_ex.e_entry;
1015 }
1016 }
954 if (BAD_ADDR(elf_entry)) { 1017 if (BAD_ADDR(elf_entry)) {
955 force_sig(SIGSEGV, current); 1018 force_sig(SIGSEGV, current);
956 retval = IS_ERR((void *)elf_entry) ? 1019 retval = IS_ERR((void *)elf_entry) ?