[PATCH 4/4] elf: save allocation per exec

From: Alexey Dobriyan
Date: Mon Feb 04 2019 - 15:33:21 EST


2 ELF header aren't that large to allocate them on heap.

However, code is bloated by 1.5 KB (!!!) with gcc 8.2 and stack size
grows by ~340 bytes.

The problem is that 2 elf headers are only 128 bytes.

I'm shocked and the patch should not be applied probably.

Signed-off-by: Alexey Dobriyan <adobriyan@xxxxxxxxx>
---

fs/binfmt_elf.c | 78 ++++++++++++++++++++++++--------------------------------
1 file changed, 34 insertions(+), 44 deletions(-)

--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -699,37 +699,29 @@ static int load_elf_binary(struct linux_binprm *bprm)
unsigned long reloc_func_desc __maybe_unused = 0;
int executable_stack = EXSTACK_DEFAULT;
struct pt_regs *regs = current_pt_regs();
- struct {
- struct elfhdr elf_ex;
- struct elfhdr interp_elf_ex;
- } *loc;
+ struct elfhdr elf_ex;
+ struct elfhdr interp_elf_ex;
struct arch_elf_state arch_state = INIT_ARCH_ELF_STATE;
loff_t pos;

- loc = kmalloc(sizeof(*loc), GFP_KERNEL);
- if (!loc) {
- retval = -ENOMEM;
- goto out_ret;
- }
-
/* Get the exec-header */
- loc->elf_ex = *((struct elfhdr *)bprm->buf);
+ elf_ex = *(struct elfhdr *)bprm->buf;

retval = -ENOEXEC;
/* 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;

- 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;
- if (!elf_check_arch(&loc->elf_ex))
+ if (!elf_check_arch(&elf_ex))
goto out;
- if (elf_check_fdpic(&loc->elf_ex))
+ if (elf_check_fdpic(&elf_ex))
goto out;
if (!bprm->file->f_op->mmap)
goto out;

- elf_phdata = load_elf_phdrs(&loc->elf_ex, bprm->file);
+ elf_phdata = load_elf_phdrs(&elf_ex, bprm->file);
if (!elf_phdata)
goto out;

@@ -742,7 +734,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
start_data = 0;
end_data = 0;

- for (i = 0; i < loc->elf_ex.e_phnum; i++) {
+ for (i = 0; i < elf_ex.e_phnum; i++) {
if (elf_ppnt->p_type == PT_INTERP) {
/* This is the program interpreter used for
* shared libraries - for now assume that this
@@ -786,9 +778,9 @@ static int load_elf_binary(struct linux_binprm *bprm)

/* Get the exec headers */
pos = 0;
- retval = kernel_read(interpreter, &loc->interp_elf_ex,
- sizeof(loc->interp_elf_ex), &pos);
- if (retval != sizeof(loc->interp_elf_ex)) {
+ retval = kernel_read(interpreter, &interp_elf_ex,
+ sizeof(interp_elf_ex), &pos);
+ if (retval != sizeof(interp_elf_ex)) {
if (retval >= 0)
retval = -EIO;
goto out_free_dentry;
@@ -800,7 +792,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
}

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) {
case PT_GNU_STACK:
if (elf_ppnt->p_flags & PF_X)
@@ -810,7 +802,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
break;

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,
&arch_state);
if (retval)
@@ -822,25 +814,25 @@ static int load_elf_binary(struct linux_binprm *bprm)
if (elf_interpreter) {
retval = -ELIBBAD;
/* Not an ELF interpreter */
- if (memcmp(loc->interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
+ if (memcmp(interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
goto out_free_dentry;
/* Verify the interpreter has a valid arch */
- if (!elf_check_arch(&loc->interp_elf_ex) ||
- elf_check_fdpic(&loc->interp_elf_ex))
+ if (!elf_check_arch(&interp_elf_ex) ||
+ elf_check_fdpic(&interp_elf_ex))
goto out_free_dentry;

/* Load the interpreter program headers */
- interp_elf_phdata = load_elf_phdrs(&loc->interp_elf_ex,
+ interp_elf_phdata = load_elf_phdrs(&interp_elf_ex,
interpreter);
if (!interp_elf_phdata)
goto out_free_dentry;

/* Pass PT_LOPROC..PT_HIPROC headers to arch code */
elf_ppnt = interp_elf_phdata;
- for (i = 0; i < loc->interp_elf_ex.e_phnum; i++, elf_ppnt++)
+ for (i = 0; i < interp_elf_ex.e_phnum; i++, elf_ppnt++)
switch (elf_ppnt->p_type) {
case PT_LOPROC ... PT_HIPROC:
- retval = arch_elf_pt_proc(&loc->interp_elf_ex,
+ retval = arch_elf_pt_proc(&interp_elf_ex,
elf_ppnt, interpreter,
true, &arch_state);
if (retval)
@@ -854,8 +846,8 @@ static int load_elf_binary(struct linux_binprm *bprm)
* still possible to return an error to the code that invoked
* the exec syscall.
*/
- retval = arch_check_elf(&loc->elf_ex,
- !!interpreter, &loc->interp_elf_ex,
+ retval = arch_check_elf(&elf_ex,
+ !!interpreter, &interp_elf_ex,
&arch_state);
if (retval)
goto out_free_dentry;
@@ -867,8 +859,8 @@ static int load_elf_binary(struct linux_binprm *bprm)

/* Do this immediately, since STACK_TOP as used in setup_arg_pages
may depend on the personality. */
- SET_PERSONALITY2(loc->elf_ex, &arch_state);
- if (elf_read_implies_exec(loc->elf_ex, executable_stack))
+ SET_PERSONALITY2(elf_ex, &arch_state);
+ if (elf_read_implies_exec(elf_ex, executable_stack))
current->personality |= READ_IMPLIES_EXEC;

if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
@@ -889,7 +881,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
/* Now we do a little grungy work by mmapping the ELF image into
the correct location in memory. */
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 = 0, elf_flags, elf_fixed = MAP_FIXED_NOREPLACE;
unsigned long k, vaddr;
unsigned long total_size = 0;
@@ -945,9 +937,9 @@ static int load_elf_binary(struct linux_binprm *bprm)
* If we are loading ET_EXEC or we have already performed
* 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 |= elf_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
* Header for ET_DYN binaries to calculate the
@@ -996,7 +988,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
load_bias = ELF_PAGESTART(load_bias - vaddr);

total_size = total_mapping_size(elf_phdata,
- loc->elf_ex.e_phnum);
+ elf_ex.e_phnum);
if (!total_size) {
retval = -EINVAL;
goto out_free_dentry;
@@ -1014,7 +1006,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
if (!load_addr_set) {
load_addr_set = 1;
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 -
ELF_PAGESTART(load_bias + vaddr);
load_addr += load_bias;
@@ -1055,7 +1047,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
}
}

- loc->elf_ex.e_entry += load_bias;
+ elf_ex.e_entry += load_bias;
elf_bss += load_bias;
elf_brk += load_bias;
start_code += load_bias;
@@ -1079,7 +1071,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
if (elf_interpreter) {
unsigned long interp_map_addr = 0;

- elf_entry = load_elf_interp(&loc->interp_elf_ex,
+ elf_entry = load_elf_interp(&interp_elf_ex,
interpreter,
&interp_map_addr,
load_bias, interp_elf_phdata);
@@ -1089,7 +1081,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
* adjustment
*/
interp_load_addr = elf_entry;
- elf_entry += loc->interp_elf_ex.e_entry;
+ elf_entry += interp_elf_ex.e_entry;
}
if (BAD_ADDR(elf_entry)) {
retval = IS_ERR((void *)elf_entry) ?
@@ -1102,7 +1094,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
fput(interpreter);
kfree(elf_interpreter);
} else {
- elf_entry = loc->elf_ex.e_entry;
+ elf_entry = elf_ex.e_entry;
if (BAD_ADDR(elf_entry)) {
retval = -EINVAL;
goto out_free_dentry;
@@ -1120,7 +1112,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
goto out;
#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);
if (retval < 0)
goto out;
@@ -1166,8 +1158,6 @@ static int load_elf_binary(struct linux_binprm *bprm)
start_thread(regs, elf_entry, bprm->p);
retval = 0;
out:
- kfree(loc);
-out_ret:
return retval;

/* error cleanup */