aboutsummaryrefslogtreecommitdiffstats
path: root/fs/binfmt_elf.c
diff options
context:
space:
mode:
authorPaul Burton <paul.burton@imgtec.com>2014-09-11 03:30:14 -0400
committerRalf Baechle <ralf@linux-mips.org>2014-11-24 01:45:02 -0500
commit6a8d38945cf4e6e819d6b550250615db763065a0 (patch)
treec5e0bef527d102ca506e09685467e1577a2bacab /fs/binfmt_elf.c
parente292ccde216e571faad475e4331c188f22a28182 (diff)
binfmt_elf: Hoist ELF program header loading to a function
load_elf_binary & load_elf_interp both load program headers from an ELF executable in the same way, duplicating the code. This patch introduces a helper function (load_elf_phdrs) which performs this common task & calls it from both load_elf_binary & load_elf_interp. In addition to reducing code duplication, this is part of preparing to load the ELF interpreter headers earlier such that they can be examined before it's too late to return an error from an exec syscall. Signed-off-by: Paul Burton <paul.burton@imgtec.com> Cc: linux-mips@linux-mips.org Cc: Alexander Viro <viro@zeniv.linux.org.uk> Cc: linux-fsdevel@vger.kernel.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/7676/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'fs/binfmt_elf.c')
-rw-r--r--fs/binfmt_elf.c99
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 */
398static 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;
435out:
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;