Commit 9b2bc421 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] binfmt_elf.c fix for 32-bit apps with large bss

From: Julie DeWandel <jdewand@redhat.com>

A problem exists where a 32-bit application can have a huge bss, one that
is so large that an overflow of the TASK_SIZE happens.  But in this case,
the overflow is not detected in load_elf_binary().  Instead, because
arithmetic is being done using 32-bit containers, a truncation occurs and
the program gets loaded when it shouldn't have been.  Subsequent execution
yields unpredictable results.

The attached patch fixes this problem by checking for the overflow
condition and sending a SIGKILL to the application if the overflow is
detected.  This problem can in theory exist when loading the elf
interpreter as well, so a similar check was added there.
parent a804dbaf
...@@ -359,6 +359,18 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, ...@@ -359,6 +359,18 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
load_addr_set = 1; load_addr_set = 1;
} }
/*
* Check to see if the section's size will overflow the
* allowed task size. Note that p_filesz must always be
* <= p_memsize so it is only necessary to check p_memsz.
*/
k = load_addr + eppnt->p_vaddr;
if (k > TASK_SIZE || eppnt->p_filesz > eppnt->p_memsz ||
eppnt->p_memsz > TASK_SIZE || TASK_SIZE - eppnt->p_memsz < k) {
error = -ENOMEM;
goto out_close;
}
/* /*
* Find the end of the file mapping for this phdr, and keep * Find the end of the file mapping for this phdr, and keep
* track of the largest address we see for this. * track of the largest address we see for this.
...@@ -759,6 +771,19 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) ...@@ -759,6 +771,19 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
if (k < start_code) start_code = k; if (k < start_code) start_code = k;
if (start_data < k) start_data = k; if (start_data < k) start_data = k;
/*
* Check to see if the section's size will overflow the
* allowed task size. Note that p_filesz must always be
* <= p_memsz so it is only necessary to check p_memsz.
*/
if (k > TASK_SIZE || elf_ppnt->p_filesz > elf_ppnt->p_memsz ||
elf_ppnt->p_memsz > TASK_SIZE ||
TASK_SIZE - elf_ppnt->p_memsz < k) {
/* set_brk can never work. Avoid overflows. */
send_sig(SIGKILL, current, 0);
goto out_free_dentry;
}
k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
if (k > elf_bss) if (k > elf_bss)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment