Commit a62c5b1b authored by Alexey Dobriyan's avatar Alexey Dobriyan Committed by Linus Torvalds

fs/binfmt_elf.c: don't copy ELF header around

ELF header is read into bprm->buf[] by generic execve code.

Save a memcpy and allocate just one header for the interpreter instead
of two headers (64 bytes instead of 128 on 64-bit).

Link: http://lkml.kernel.org/r/20191208171242.GA19716@avx2Signed-off-by: default avatarAlexey Dobriyan <adobriyan@gmail.com>
Reviewed-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent f67ef446
...@@ -161,8 +161,9 @@ static int padzero(unsigned long elf_bss) ...@@ -161,8 +161,9 @@ static int padzero(unsigned long elf_bss)
#endif #endif
static int static int
create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, create_elf_tables(struct linux_binprm *bprm, const struct elfhdr *exec,
unsigned long load_addr, unsigned long interp_load_addr) unsigned long load_addr, unsigned long interp_load_addr,
unsigned long e_entry)
{ {
unsigned long p = bprm->p; unsigned long p = bprm->p;
int argc = bprm->argc; int argc = bprm->argc;
...@@ -251,7 +252,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, ...@@ -251,7 +252,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
NEW_AUX_ENT(AT_PHNUM, exec->e_phnum); NEW_AUX_ENT(AT_PHNUM, exec->e_phnum);
NEW_AUX_ENT(AT_BASE, interp_load_addr); NEW_AUX_ENT(AT_BASE, interp_load_addr);
NEW_AUX_ENT(AT_FLAGS, 0); NEW_AUX_ENT(AT_FLAGS, 0);
NEW_AUX_ENT(AT_ENTRY, exec->e_entry); NEW_AUX_ENT(AT_ENTRY, e_entry);
NEW_AUX_ENT(AT_UID, from_kuid_munged(cred->user_ns, cred->uid)); NEW_AUX_ENT(AT_UID, from_kuid_munged(cred->user_ns, cred->uid));
NEW_AUX_ENT(AT_EUID, from_kuid_munged(cred->user_ns, cred->euid)); NEW_AUX_ENT(AT_EUID, from_kuid_munged(cred->user_ns, cred->euid));
NEW_AUX_ENT(AT_GID, from_kgid_munged(cred->user_ns, cred->gid)); NEW_AUX_ENT(AT_GID, from_kgid_munged(cred->user_ns, cred->gid));
...@@ -690,12 +691,13 @@ static int load_elf_binary(struct linux_binprm *bprm) ...@@ -690,12 +691,13 @@ static int load_elf_binary(struct linux_binprm *bprm)
int bss_prot = 0; int bss_prot = 0;
int retval, i; int retval, i;
unsigned long elf_entry; unsigned long elf_entry;
unsigned long e_entry;
unsigned long interp_load_addr = 0; unsigned long interp_load_addr = 0;
unsigned long start_code, end_code, start_data, end_data; unsigned long start_code, end_code, start_data, end_data;
unsigned long reloc_func_desc __maybe_unused = 0; unsigned long reloc_func_desc __maybe_unused = 0;
int executable_stack = EXSTACK_DEFAULT; int executable_stack = EXSTACK_DEFAULT;
struct elfhdr *elf_ex = (struct elfhdr *)bprm->buf;
struct { struct {
struct elfhdr elf_ex;
struct elfhdr interp_elf_ex; struct elfhdr interp_elf_ex;
} *loc; } *loc;
struct arch_elf_state arch_state = INIT_ARCH_ELF_STATE; struct arch_elf_state arch_state = INIT_ARCH_ELF_STATE;
...@@ -707,29 +709,26 @@ static int load_elf_binary(struct linux_binprm *bprm) ...@@ -707,29 +709,26 @@ static int load_elf_binary(struct linux_binprm *bprm)
goto out_ret; goto out_ret;
} }
/* Get the exec-header */
loc->elf_ex = *((struct elfhdr *)bprm->buf);
retval = -ENOEXEC; retval = -ENOEXEC;
/* First of all, some simple consistency checks */ /* First of all, some simple consistency checks */
if (memcmp(loc->elf_ex.e_ident, ELFMAG, SELFMAG) != 0) if (memcmp(elf_ex->e_ident, ELFMAG, SELFMAG) != 0)
goto out; goto out;
if (loc->elf_ex.e_type != ET_EXEC && loc->elf_ex.e_type != ET_DYN) if (elf_ex->e_type != ET_EXEC && elf_ex->e_type != ET_DYN)
goto out; goto out;
if (!elf_check_arch(&loc->elf_ex)) if (!elf_check_arch(elf_ex))
goto out; goto out;
if (elf_check_fdpic(&loc->elf_ex)) if (elf_check_fdpic(elf_ex))
goto out; goto out;
if (!bprm->file->f_op->mmap) if (!bprm->file->f_op->mmap)
goto out; goto out;
elf_phdata = load_elf_phdrs(&loc->elf_ex, bprm->file); elf_phdata = load_elf_phdrs(elf_ex, bprm->file);
if (!elf_phdata) if (!elf_phdata)
goto out; goto out;
elf_ppnt = elf_phdata; elf_ppnt = elf_phdata;
for (i = 0; i < loc->elf_ex.e_phnum; i++, elf_ppnt++) { for (i = 0; i < elf_ex->e_phnum; i++, elf_ppnt++) {
char *elf_interpreter; char *elf_interpreter;
if (elf_ppnt->p_type != PT_INTERP) if (elf_ppnt->p_type != PT_INTERP)
...@@ -783,7 +782,7 @@ static int load_elf_binary(struct linux_binprm *bprm) ...@@ -783,7 +782,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
} }
elf_ppnt = elf_phdata; elf_ppnt = elf_phdata;
for (i = 0; i < loc->elf_ex.e_phnum; i++, elf_ppnt++) for (i = 0; i < elf_ex->e_phnum; i++, elf_ppnt++)
switch (elf_ppnt->p_type) { switch (elf_ppnt->p_type) {
case PT_GNU_STACK: case PT_GNU_STACK:
if (elf_ppnt->p_flags & PF_X) if (elf_ppnt->p_flags & PF_X)
...@@ -793,7 +792,7 @@ static int load_elf_binary(struct linux_binprm *bprm) ...@@ -793,7 +792,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
break; break;
case PT_LOPROC ... PT_HIPROC: case PT_LOPROC ... PT_HIPROC:
retval = arch_elf_pt_proc(&loc->elf_ex, elf_ppnt, retval = arch_elf_pt_proc(elf_ex, elf_ppnt,
bprm->file, false, bprm->file, false,
&arch_state); &arch_state);
if (retval) if (retval)
...@@ -837,7 +836,7 @@ static int load_elf_binary(struct linux_binprm *bprm) ...@@ -837,7 +836,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
* still possible to return an error to the code that invoked * still possible to return an error to the code that invoked
* the exec syscall. * the exec syscall.
*/ */
retval = arch_check_elf(&loc->elf_ex, retval = arch_check_elf(elf_ex,
!!interpreter, &loc->interp_elf_ex, !!interpreter, &loc->interp_elf_ex,
&arch_state); &arch_state);
if (retval) if (retval)
...@@ -850,8 +849,8 @@ static int load_elf_binary(struct linux_binprm *bprm) ...@@ -850,8 +849,8 @@ static int load_elf_binary(struct linux_binprm *bprm)
/* Do this immediately, since STACK_TOP as used in setup_arg_pages /* Do this immediately, since STACK_TOP as used in setup_arg_pages
may depend on the personality. */ may depend on the personality. */
SET_PERSONALITY2(loc->elf_ex, &arch_state); SET_PERSONALITY2(*elf_ex, &arch_state);
if (elf_read_implies_exec(loc->elf_ex, executable_stack)) if (elf_read_implies_exec(*elf_ex, executable_stack))
current->personality |= READ_IMPLIES_EXEC; current->personality |= READ_IMPLIES_EXEC;
if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
...@@ -878,7 +877,7 @@ static int load_elf_binary(struct linux_binprm *bprm) ...@@ -878,7 +877,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
/* Now we do a little grungy work by mmapping the ELF image into /* Now we do a little grungy work by mmapping the ELF image into
the correct location in memory. */ the correct location in memory. */
for(i = 0, elf_ppnt = elf_phdata; for(i = 0, elf_ppnt = elf_phdata;
i < loc->elf_ex.e_phnum; i++, elf_ppnt++) { i < elf_ex->e_phnum; i++, elf_ppnt++) {
int elf_prot, elf_flags; int elf_prot, elf_flags;
unsigned long k, vaddr; unsigned long k, vaddr;
unsigned long total_size = 0; unsigned long total_size = 0;
...@@ -922,9 +921,9 @@ static int load_elf_binary(struct linux_binprm *bprm) ...@@ -922,9 +921,9 @@ static int load_elf_binary(struct linux_binprm *bprm)
* If we are loading ET_EXEC or we have already performed * If we are loading ET_EXEC or we have already performed
* the ET_DYN load_addr calculations, proceed normally. * the ET_DYN load_addr calculations, proceed normally.
*/ */
if (loc->elf_ex.e_type == ET_EXEC || load_addr_set) { if (elf_ex->e_type == ET_EXEC || load_addr_set) {
elf_flags |= MAP_FIXED; elf_flags |= MAP_FIXED;
} else if (loc->elf_ex.e_type == ET_DYN) { } else if (elf_ex->e_type == ET_DYN) {
/* /*
* This logic is run once for the first LOAD Program * This logic is run once for the first LOAD Program
* Header for ET_DYN binaries to calculate the * Header for ET_DYN binaries to calculate the
...@@ -973,7 +972,7 @@ static int load_elf_binary(struct linux_binprm *bprm) ...@@ -973,7 +972,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
load_bias = ELF_PAGESTART(load_bias - vaddr); load_bias = ELF_PAGESTART(load_bias - vaddr);
total_size = total_mapping_size(elf_phdata, total_size = total_mapping_size(elf_phdata,
loc->elf_ex.e_phnum); elf_ex->e_phnum);
if (!total_size) { if (!total_size) {
retval = -EINVAL; retval = -EINVAL;
goto out_free_dentry; goto out_free_dentry;
...@@ -991,7 +990,7 @@ static int load_elf_binary(struct linux_binprm *bprm) ...@@ -991,7 +990,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
if (!load_addr_set) { if (!load_addr_set) {
load_addr_set = 1; load_addr_set = 1;
load_addr = (elf_ppnt->p_vaddr - elf_ppnt->p_offset); load_addr = (elf_ppnt->p_vaddr - elf_ppnt->p_offset);
if (loc->elf_ex.e_type == ET_DYN) { if (elf_ex->e_type == ET_DYN) {
load_bias += error - load_bias += error -
ELF_PAGESTART(load_bias + vaddr); ELF_PAGESTART(load_bias + vaddr);
load_addr += load_bias; load_addr += load_bias;
...@@ -1032,7 +1031,7 @@ static int load_elf_binary(struct linux_binprm *bprm) ...@@ -1032,7 +1031,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
} }
} }
loc->elf_ex.e_entry += load_bias; e_entry = elf_ex->e_entry + load_bias;
elf_bss += load_bias; elf_bss += load_bias;
elf_brk += load_bias; elf_brk += load_bias;
start_code += load_bias; start_code += load_bias;
...@@ -1075,7 +1074,7 @@ static int load_elf_binary(struct linux_binprm *bprm) ...@@ -1075,7 +1074,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
allow_write_access(interpreter); allow_write_access(interpreter);
fput(interpreter); fput(interpreter);
} else { } else {
elf_entry = loc->elf_ex.e_entry; elf_entry = e_entry;
if (BAD_ADDR(elf_entry)) { if (BAD_ADDR(elf_entry)) {
retval = -EINVAL; retval = -EINVAL;
goto out_free_dentry; goto out_free_dentry;
...@@ -1093,8 +1092,8 @@ static int load_elf_binary(struct linux_binprm *bprm) ...@@ -1093,8 +1092,8 @@ static int load_elf_binary(struct linux_binprm *bprm)
goto out; goto out;
#endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */ #endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */
retval = create_elf_tables(bprm, &loc->elf_ex, retval = create_elf_tables(bprm, elf_ex,
load_addr, interp_load_addr); load_addr, interp_load_addr, e_entry);
if (retval < 0) if (retval < 0)
goto out; goto out;
current->mm->end_code = end_code; current->mm->end_code = end_code;
...@@ -1112,7 +1111,7 @@ static int load_elf_binary(struct linux_binprm *bprm) ...@@ -1112,7 +1111,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
* growing down), and into the unused ELF_ET_DYN_BASE region. * growing down), and into the unused ELF_ET_DYN_BASE region.
*/ */
if (IS_ENABLED(CONFIG_ARCH_HAS_ELF_RANDOMIZE) && if (IS_ENABLED(CONFIG_ARCH_HAS_ELF_RANDOMIZE) &&
loc->elf_ex.e_type == ET_DYN && !interpreter) elf_ex->e_type == ET_DYN && !interpreter)
current->mm->brk = current->mm->start_brk = current->mm->brk = current->mm->start_brk =
ELF_ET_DYN_BASE; ELF_ET_DYN_BASE;
......
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