diff options
-rw-r--r-- | fs/binfmt_elf.c | 99 |
1 files changed, 56 insertions, 43 deletions
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index d8fc0605b9d2..2b02d41f78e2 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
@@ -386,6 +386,59 @@ static unsigned long total_mapping_size(struct elf_phdr *cmds, int nr) | |||
386 | ELF_PAGESTART(cmds[first_idx].p_vaddr); | 386 | ELF_PAGESTART(cmds[first_idx].p_vaddr); |
387 | } | 387 | } |
388 | 388 | ||
389 | /** | ||
390 | * load_elf_phdrs() - load ELF program headers | ||
391 | * @elf_ex: ELF header of the binary whose program headers should be loaded | ||
392 | * @elf_file: the opened ELF binary file | ||
393 | * | ||
394 | * Loads ELF program headers from the binary file elf_file, which has the ELF | ||
395 | * header pointed to by elf_ex, into a newly allocated array. The caller is | ||
396 | * responsible for freeing the allocated data. Returns an ERR_PTR upon failure. | ||
397 | */ | ||
398 | static struct elf_phdr *load_elf_phdrs(struct elfhdr *elf_ex, | ||
399 | struct file *elf_file) | ||
400 | { | ||
401 | struct elf_phdr *elf_phdata = NULL; | ||
402 | int retval, size, err = -1; | ||
403 | |||
404 | /* | ||
405 | * If the size of this structure has changed, then punt, since | ||
406 | * we will be doing the wrong thing. | ||
407 | */ | ||
408 | if (elf_ex->e_phentsize != sizeof(struct elf_phdr)) | ||
409 | goto out; | ||
410 | |||
411 | /* Sanity check the number of program headers... */ | ||
412 | if (elf_ex->e_phnum < 1 || | ||
413 | elf_ex->e_phnum > 65536U / sizeof(struct elf_phdr)) | ||
414 | goto out; | ||
415 | |||
416 | /* ...and their total size. */ | ||
417 | size = sizeof(struct elf_phdr) * elf_ex->e_phnum; | ||
418 | if (size > ELF_MIN_ALIGN) | ||
419 | goto out; | ||
420 | |||
421 | elf_phdata = kmalloc(size, GFP_KERNEL); | ||
422 | if (!elf_phdata) | ||
423 | goto out; | ||
424 | |||
425 | /* Read in the program headers */ | ||
426 | retval = kernel_read(elf_file, elf_ex->e_phoff, | ||
427 | (char *)elf_phdata, size); | ||
428 | if (retval != size) { | ||
429 | err = (retval < 0) ? retval : -EIO; | ||
430 | goto out; | ||
431 | } | ||
432 | |||
433 | /* Success! */ | ||
434 | err = 0; | ||
435 | out: | ||
436 | if (err) { | ||
437 | kfree(elf_phdata); | ||
438 | elf_phdata = NULL; | ||
439 | } | ||
440 | return elf_phdata; | ||
441 | } | ||
389 | 442 | ||
390 | /* This is much more generalized than the library routine read function, | 443 | /* This is much more generalized than the library routine read function, |
391 | so we keep this separate. Technically the library read function | 444 | so we keep this separate. Technically the library read function |
@@ -403,7 +456,7 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, | |||
403 | unsigned long last_bss = 0, elf_bss = 0; | 456 | unsigned long last_bss = 0, elf_bss = 0; |
404 | unsigned long error = ~0UL; | 457 | unsigned long error = ~0UL; |
405 | unsigned long total_size; | 458 | unsigned long total_size; |
406 | int retval, i, size; | 459 | int i; |
407 | 460 | ||
408 | /* First of all, some simple consistency checks */ | 461 | /* First of all, some simple consistency checks */ |
409 | if (interp_elf_ex->e_type != ET_EXEC && | 462 | if (interp_elf_ex->e_type != ET_EXEC && |
@@ -414,33 +467,10 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, | |||
414 | if (!interpreter->f_op->mmap) | 467 | if (!interpreter->f_op->mmap) |
415 | goto out; | 468 | goto out; |
416 | 469 | ||
417 | /* | 470 | elf_phdata = load_elf_phdrs(interp_elf_ex, interpreter); |
418 | * If the size of this structure has changed, then punt, since | ||
419 | * we will be doing the wrong thing. | ||
420 | */ | ||
421 | if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) | ||
422 | goto out; | ||
423 | if (interp_elf_ex->e_phnum < 1 || | ||
424 | interp_elf_ex->e_phnum > 65536U / sizeof(struct elf_phdr)) | ||
425 | goto out; | ||
426 | |||
427 | /* Now read in all of the header information */ | ||
428 | size = sizeof(struct elf_phdr) * interp_elf_ex->e_phnum; | ||
429 | if (size > ELF_MIN_ALIGN) | ||
430 | goto out; | ||
431 | elf_phdata = kmalloc(size, GFP_KERNEL); | ||
432 | if (!elf_phdata) | 471 | if (!elf_phdata) |
433 | goto out; | 472 | goto out; |
434 | 473 | ||
435 | retval = kernel_read(interpreter, interp_elf_ex->e_phoff, | ||
436 | (char *)elf_phdata, size); | ||
437 | error = -EIO; | ||
438 | if (retval != size) { | ||
439 | if (retval < 0) | ||
440 | error = retval; | ||
441 | goto out_close; | ||
442 | } | ||
443 | |||
444 | total_size = total_mapping_size(elf_phdata, interp_elf_ex->e_phnum); | 474 | total_size = total_mapping_size(elf_phdata, interp_elf_ex->e_phnum); |
445 | if (!total_size) { | 475 | if (!total_size) { |
446 | error = -EINVAL; | 476 | error = -EINVAL; |
@@ -578,7 +608,6 @@ static int load_elf_binary(struct linux_binprm *bprm) | |||
578 | struct elf_phdr *elf_ppnt, *elf_phdata; | 608 | struct elf_phdr *elf_ppnt, *elf_phdata; |
579 | unsigned long elf_bss, elf_brk; | 609 | unsigned long elf_bss, elf_brk; |
580 | int retval, i; | 610 | int retval, i; |
581 | unsigned int size; | ||
582 | unsigned long elf_entry; | 611 | unsigned long elf_entry; |
583 | unsigned long interp_load_addr = 0; | 612 | unsigned long interp_load_addr = 0; |
584 | unsigned long start_code, end_code, start_data, end_data; | 613 | unsigned long start_code, end_code, start_data, end_data; |
@@ -611,26 +640,10 @@ static int load_elf_binary(struct linux_binprm *bprm) | |||
611 | if (!bprm->file->f_op->mmap) | 640 | if (!bprm->file->f_op->mmap) |
612 | goto out; | 641 | goto out; |
613 | 642 | ||
614 | /* Now read in all of the header information */ | 643 | elf_phdata = load_elf_phdrs(&loc->elf_ex, bprm->file); |
615 | if (loc->elf_ex.e_phentsize != sizeof(struct elf_phdr)) | ||
616 | goto out; | ||
617 | if (loc->elf_ex.e_phnum < 1 || | ||
618 | loc->elf_ex.e_phnum > 65536U / sizeof(struct elf_phdr)) | ||
619 | goto out; | ||
620 | size = loc->elf_ex.e_phnum * sizeof(struct elf_phdr); | ||
621 | retval = -ENOMEM; | ||
622 | elf_phdata = kmalloc(size, GFP_KERNEL); | ||
623 | if (!elf_phdata) | 644 | if (!elf_phdata) |
624 | goto out; | 645 | goto out; |
625 | 646 | ||
626 | retval = kernel_read(bprm->file, loc->elf_ex.e_phoff, | ||
627 | (char *)elf_phdata, size); | ||
628 | if (retval != size) { | ||
629 | if (retval >= 0) | ||
630 | retval = -EIO; | ||
631 | goto out_free_ph; | ||
632 | } | ||
633 | |||
634 | elf_ppnt = elf_phdata; | 647 | elf_ppnt = elf_phdata; |
635 | elf_bss = 0; | 648 | elf_bss = 0; |
636 | elf_brk = 0; | 649 | elf_brk = 0; |