Skip to content

Commit 6a8d389

Browse files
paulburtonralfbaechle
authored andcommitted
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 <[email protected]> Cc: [email protected] Cc: Alexander Viro <[email protected]> Cc: [email protected] Cc: [email protected] Patchwork: https://patchwork.linux-mips.org/patch/7676/ Signed-off-by: Ralf Baechle <[email protected]>
1 parent e292ccd commit 6a8d389

File tree

1 file changed

+56
-43
lines changed

1 file changed

+56
-43
lines changed

fs/binfmt_elf.c

Lines changed: 56 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,59 @@ static unsigned long total_mapping_size(struct elf_phdr *cmds, int nr)
386386
ELF_PAGESTART(cmds[first_idx].p_vaddr);
387387
}
388388

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+
}
389442

390443
/* This is much more generalized than the library routine read function,
391444
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,
403456
unsigned long last_bss = 0, elf_bss = 0;
404457
unsigned long error = ~0UL;
405458
unsigned long total_size;
406-
int retval, i, size;
459+
int i;
407460

408461
/* First of all, some simple consistency checks */
409462
if (interp_elf_ex->e_type != ET_EXEC &&
@@ -414,33 +467,10 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
414467
if (!interpreter->f_op->mmap)
415468
goto out;
416469

417-
/*
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);
470+
elf_phdata = load_elf_phdrs(interp_elf_ex, interpreter);
432471
if (!elf_phdata)
433472
goto out;
434473

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-
444474
total_size = total_mapping_size(elf_phdata, interp_elf_ex->e_phnum);
445475
if (!total_size) {
446476
error = -EINVAL;
@@ -578,7 +608,6 @@ static int load_elf_binary(struct linux_binprm *bprm)
578608
struct elf_phdr *elf_ppnt, *elf_phdata;
579609
unsigned long elf_bss, elf_brk;
580610
int retval, i;
581-
unsigned int size;
582611
unsigned long elf_entry;
583612
unsigned long interp_load_addr = 0;
584613
unsigned long start_code, end_code, start_data, end_data;
@@ -611,26 +640,10 @@ static int load_elf_binary(struct linux_binprm *bprm)
611640
if (!bprm->file->f_op->mmap)
612641
goto out;
613642

614-
/* Now read in all of the header information */
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);
643+
elf_phdata = load_elf_phdrs(&loc->elf_ex, bprm->file);
623644
if (!elf_phdata)
624645
goto out;
625646

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-
634647
elf_ppnt = elf_phdata;
635648
elf_bss = 0;
636649
elf_brk = 0;

0 commit comments

Comments
 (0)