The START_THREAD arch hook called in binfmt_elf is modified to return a value which the elf loader returns as the final result. Since no arch has specialised this macro it is being modified to allow any arch specialising this macro to either 1. Abort execution of an elf binary from within start_thread() by returning a negative value or 2. Place a positive value in the first result register for the executing program to access by returning the positive value.
This modified macro also takes in the bprm struct instead of the sp to allow any arch to access more information about the binary contained within. Compatibility is maintained in previous versions by passing the sp from bprm to the default start_thread() implementation.
This required changing kernel_execve() to always return 0 on success instead of the aforementioned positive value. This is because only a return value of 0 would indicate that the init process has started correctly during boot, in which kernel_execve() is called.
Signed-off-by: Sherwin da Cruz sherwin.dacruz@arm.com --- fs/binfmt_elf.c | 3 +-- fs/compat_binfmt_elf.c | 6 +++++- fs/exec.c | 4 ++-- include/linux/elf.h | 7 +++++-- 4 files changed, 13 insertions(+), 7 deletions(-)
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 920e3515080e..7e391025ffe8 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -1442,8 +1442,7 @@ static int load_elf_binary(struct linux_binprm *bprm) #endif
finalize_exec(bprm); - START_THREAD(elf_ex, regs, elf_entry, bprm->p); - retval = 0; + retval = START_THREAD(elf_ex, regs, elf_entry, bprm); out: return retval;
diff --git a/fs/compat_binfmt_elf.c b/fs/compat_binfmt_elf.c index 413922b85be6..247b9ebd8fbb 100644 --- a/fs/compat_binfmt_elf.c +++ b/fs/compat_binfmt_elf.c @@ -127,7 +127,11 @@
#ifdef COMPAT_START_THREAD #undef START_THREAD -#define START_THREAD COMPAT_START_THREAD +#define START_THREAD(elf_ex, regs, elf_entry, bprm) \ +({ \ + COMPAT_START_THREAD(elf_ex, regs, elf_entry, bprm->p); \ + 0; /* binfmt_elf return value */ \ +}) #endif
#ifdef compat_arch_setup_additional_pages diff --git a/fs/exec.c b/fs/exec.c index c177f8cc3e00..3edd9601ae9a 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1793,7 +1793,7 @@ static int exec_binprm(struct linux_binprm *bprm) trace_sched_process_exec(current, old_pid, bprm); ptrace_event(PTRACE_EVENT_EXEC, old_vpid); proc_exec_connector(current); - return 0; + return ret; }
/* @@ -2003,7 +2003,7 @@ int kernel_execve(const char *kernel_filename, free_bprm(bprm); out_ret: putname(filename); - return retval; + return retval < 0 ? retval : 0; }
static int do_execve(struct filename *filename, diff --git a/include/linux/elf.h b/include/linux/elf.h index 50ca9e34763c..039ad1867045 100644 --- a/include/linux/elf.h +++ b/include/linux/elf.h @@ -23,8 +23,11 @@ #endif
#ifndef START_THREAD -#define START_THREAD(elf_ex, regs, elf_entry, start_stack) \ - start_thread(regs, elf_entry, start_stack) +#define START_THREAD(elf_ex, regs, elf_entry, bprm) \ +({ \ + start_thread(regs, elf_entry, bprm->p); \ + 0; /* binfmt_elf return value */ \ +}) #endif
#if defined(ARCH_HAS_SETUP_ADDITIONAL_PAGES) && !defined(ARCH_SETUP_ADDITIONAL_PAGES)