History

exec: Remove recursion from search_binary_handler

Recursion in kernel code is generally a bad idea as it can overflow the kernel stack. Recursion in exec also hides that the code is looping and that the loop changes bprm->file. Instead of recursing in search_binary_handler have the methods that would recurse set bprm->interpreter and return 0. Modify exec_binprm to loop when bprm->interpreter is set. Consolidate all of the reassignments of bprm->file in that loop to make it clear what is going on. The structure of the new loop in exec_binprm is that all errors return immediately, while successful completion (ret == 0 && !bprm->interpreter) just breaks out of the loop and runs what exec_bprm has always run upon successful completion. Fail if the an interpreter is being call after execfd has been set. The code has never properly handled an interpreter being called with execfd being set and with reassignments of bprm->file and the assignment of bprm->executable in generic code it has finally become possible to test and fail when if this problematic condition happens. With the reassignments of bprm->file and the assignment of bprm->executable moved into the generic code add a test to see if bprm->executable is being reassigned. In search_binary_handler remove the test for !bprm->file. With all reassignments of bprm->file moved to exec_binprm bprm->file can never be NULL in search_binary_handler.

Eric W. Biederman committed 6 years ago

Commit bc2bf331 parent b8a61c96 files · +43 −55Browse files

Showing the changes to include/linux (1 of 6 files). Show all

Unified · Split

include/linux/binfmts.h+1−2
@@ -50,8 +50,8 @@ struct linux_binprm { · 49 unmodified lines
5050 #ifdef __alpha__
5151 unsigned int taso:1;
5252 #endif
53− unsigned int recursion_depth; /* only for search_binary_handler() */
5453 struct file * executable; /* Executable to pass to the interpreter */
54+ struct file * interpreter;
5555 struct file * file;
5656 struct cred *cred; /* new credentials */
5757 int unsafe; /* how unsafe this exec is (mask of LSM_UNSAFE_*) */
@@ -117,7 +117,6 @@ static inline void insert_binfmt(struct linux_binfmt *fmt) · 59 unmodified lines
117117 extern void unregister_binfmt(struct linux_binfmt *);
118118
119119 extern int __must_check remove_arg_zero(struct linux_binprm *);
120−extern int search_binary_handler(struct linux_binprm *);
121120 extern int begin_new_exec(struct linux_binprm * bprm);
122121 extern void setup_new_exec(struct linux_binprm * bprm);
123122 extern void finalize_exec(struct linux_binprm *bprm);