From: Julie DeWandel 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. --- 25-akpm/fs/binfmt_elf.c | 25 +++++++++++++++++++++++++ 1 files changed, 25 insertions(+) diff -puN fs/binfmt_elf.c~load_elf_binary-overflow-detection-fix fs/binfmt_elf.c --- 25/fs/binfmt_elf.c~load_elf_binary-overflow-detection-fix Thu Mar 25 14:24:33 2004 +++ 25-akpm/fs/binfmt_elf.c Thu Mar 25 14:24:33 2004 @@ -360,6 +360,18 @@ static unsigned long load_elf_interp(str } /* + * 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 * track of the largest address we see for this. */ @@ -759,6 +771,19 @@ static int load_elf_binary(struct linux_ if (k < start_code) start_code = 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; if (k > elf_bss) _