Skip to content

Commit 60bfba7

Browse files
Jan KratochvilLinus Torvalds
authored andcommitted
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>
1 parent f057eac commit 60bfba7

File tree

2 files changed

+87
-24
lines changed

2 files changed

+87
-24
lines changed

arch/ia64/ia32/binfmt_elf32.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ elf32_set_personality (void)
261261
}
262262

263263
static unsigned long
264-
elf32_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type)
264+
elf32_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type, unsigned long unused)
265265
{
266266
unsigned long pgoff = (eppnt->p_vaddr) & ~IA32_PAGE_MASK;
267267

fs/binfmt_elf.c

Lines changed: 86 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545

4646
static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs);
4747
static int load_elf_library(struct file *);
48-
static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int);
48+
static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int, unsigned long);
4949

5050
/*
5151
* If we don't support core dumping, then supply a NULL so we
@@ -80,7 +80,7 @@ static struct linux_binfmt elf_format = {
8080
.hasvdso = 1
8181
};
8282

83-
#define BAD_ADDR(x) ((unsigned long)(x) >= TASK_SIZE)
83+
#define BAD_ADDR(x) IS_ERR_VALUE(x)
8484

8585
static int set_brk(unsigned long start, unsigned long end)
8686
{
@@ -285,40 +285,78 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
285285
#ifndef elf_map
286286

287287
static 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)
289290
{
290291
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);
292296

293-
down_write(&current->mm->mmap_sem);
294297
/* mmap() will return -EINVAL if given a zero size, but a
295298
* segment with zero filesize is perfectly valid */
296-
if (eppnt->p_filesz + pageoffset)
297-
map_addr = do_mmap(filep, ELF_PAGESTART(addr),
298-
eppnt->p_filesz + pageoffset, prot, type,
299-
eppnt->p_offset - pageoffset);
300-
else
301-
map_addr = ELF_PAGESTART(addr);
299+
if (!size)
300+
return addr;
301+
302+
down_write(&current->mm->mmap_sem);
303+
/*
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+
302319
up_write(&current->mm->mmap_sem);
303320
return(map_addr);
304321
}
305322

306323
#endif /* !elf_map */
307324

325+
static 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+
308344
/* This is much more generalized than the library routine read function,
309345
so we keep this separate. Technically the library read function
310346
is only provided so that we can read a.out libraries that have
311347
an ELF header */
312348

313349
static 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)
315352
{
316353
struct elf_phdr *elf_phdata;
317354
struct elf_phdr *eppnt;
318355
unsigned long load_addr = 0;
319356
int load_addr_set = 0;
320357
unsigned long last_bss = 0, elf_bss = 0;
321358
unsigned long error = ~0UL;
359+
unsigned long total_size;
322360
int retval, i, size;
323361

324362
/* First of all, some simple consistency checks */
@@ -357,6 +395,12 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
357395
goto out_close;
358396
}
359397

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+
360404
eppnt = elf_phdata;
361405
for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) {
362406
if (eppnt->p_type == PT_LOAD) {
@@ -374,9 +418,14 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
374418
vaddr = eppnt->p_vaddr;
375419
if (interp_elf_ex->e_type == ET_EXEC || load_addr_set)
376420
elf_type |= MAP_FIXED;
421+
else if (no_base && interp_elf_ex->e_type == ET_DYN)
422+
load_addr = -vaddr;
377423

378424
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;
380429
error = map_addr;
381430
if (BAD_ADDR(map_addr))
382431
goto out_close;
@@ -442,8 +491,7 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
442491
goto out_close;
443492
}
444493

445-
*interp_load_addr = load_addr;
446-
error = ((unsigned long)interp_elf_ex->e_entry) + load_addr;
494+
error = load_addr;
447495

448496
out_close:
449497
kfree(elf_phdata);
@@ -540,7 +588,8 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
540588
int elf_exec_fileno;
541589
int retval, i;
542590
unsigned int size;
543-
unsigned long elf_entry, interp_load_addr = 0;
591+
unsigned long elf_entry;
592+
unsigned long interp_load_addr = 0;
544593
unsigned long start_code, end_code, start_data, end_data;
545594
unsigned long reloc_func_desc = 0;
546595
char passed_fileno[6];
@@ -808,9 +857,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
808857
current->mm->start_stack = bprm->p;
809858

810859
/* 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
812-
the image should be loaded at fixed address, not at a variable
813-
address. */
860+
the correct location in memory. */
814861
for(i = 0, elf_ppnt = elf_phdata;
815862
i < loc->elf_ex.e_phnum; i++, elf_ppnt++) {
816863
int elf_prot = 0, elf_flags;
@@ -864,11 +911,15 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
864911
* default mmap base, as well as whatever program they
865912
* might try to exec. This is because the brk will
866913
* follow the loader, and is not movable. */
914+
#ifdef CONFIG_X86
915+
load_bias = 0;
916+
#else
867917
load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr);
918+
#endif
868919
}
869920

870921
error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt,
871-
elf_prot, elf_flags);
922+
elf_prot, elf_flags,0);
872923
if (BAD_ADDR(error)) {
873924
send_sig(SIGKILL, current, 0);
874925
retval = IS_ERR((void *)error) ?
@@ -944,13 +995,25 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
944995
}
945996

946997
if (elf_interpreter) {
947-
if (interpreter_type == INTERPRETER_AOUT)
998+
if (interpreter_type == INTERPRETER_AOUT) {
948999
elf_entry = load_aout_interp(&loc->interp_ex,
9491000
interpreter);
950-
else
1001+
} else {
1002+
unsigned long interp_map_addr; /* unused */
1003+
9511004
elf_entry = load_elf_interp(&loc->interp_elf_ex,
9521005
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+
}
9541017
if (BAD_ADDR(elf_entry)) {
9551018
force_sig(SIGSEGV, current);
9561019
retval = IS_ERR((void *)elf_entry) ?

0 commit comments

Comments
 (0)