diff options
| author | 2020-06-04 14:07:08 -0700 | |
|---|---|---|
| committer | 2020-06-04 14:07:08 -0700 | |
| commit | 15a2bc4dbb9cfed1c661a657fcb10798150b7598 (patch) | |
| tree | f9ca834dbdd2e6cf1d5a2cef5008f82c72b00261 /fs/binfmt_script.c | |
| parent | Merge branch 'proc-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace (diff) | |
| parent | exec: Remove the recomputation of bprm->cred (diff) | |
| download | wireguard-linux-15a2bc4dbb9cfed1c661a657fcb10798150b7598.tar.xz wireguard-linux-15a2bc4dbb9cfed1c661a657fcb10798150b7598.zip | |
Merge branch 'exec-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace
Pull execve updates from Eric Biederman:
 "Last cycle for the Nth time I ran into bugs and quality of
  implementation issues related to exec that could not be easily be
  fixed because of the way exec is implemented. So I have been digging
  into exec and cleanup up what I can.
  I don't think I have exec sorted out enough to fix the issues I
  started with but I have made some headway this cycle with 4 sets of
  changes.
   - promised cleanups after introducing exec_update_mutex
   - trivial cleanups for exec
   - control flow simplifications
   - remove the recomputation of bprm->cred
  The net result is code that is a bit easier to understand and work
  with and a decrease in the number of lines of code (if you don't count
  the added tests)"
* 'exec-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace: (24 commits)
  exec: Compute file based creds only once
  exec: Add a per bprm->file version of per_clear
  binfmt_elf_fdpic: fix execfd build regression
  selftests/exec: Add binfmt_script regression test
  exec: Remove recursion from search_binary_handler
  exec: Generic execfd support
  exec/binfmt_script: Don't modify bprm->buf and then return -ENOEXEC
  exec: Move the call of prepare_binprm into search_binary_handler
  exec: Allow load_misc_binary to call prepare_binprm unconditionally
  exec: Convert security_bprm_set_creds into security_bprm_repopulate_creds
  exec: Factor security_bprm_creds_for_exec out of security_bprm_set_creds
  exec: Teach prepare_exec_creds how exec treats uids & gids
  exec: Set the point of no return sooner
  exec: Move handling of the point of no return to the top level
  exec: Run sync_mm_rss before taking exec_update_mutex
  exec: Fix spelling of search_binary_handler in a comment
  exec: Move the comment from above de_thread to above unshare_sighand
  exec: Rename flush_old_exec begin_new_exec
  exec: Move most of setup_new_exec into flush_old_exec
  exec: In setup_new_exec cache current in the local variable me
  ...
Diffstat (limited to 'fs/binfmt_script.c')
| -rw-r--r-- | fs/binfmt_script.c | 82 | 
1 files changed, 35 insertions, 47 deletions
| diff --git a/fs/binfmt_script.c b/fs/binfmt_script.c index e9e6a6f4a35f..0e8b953d12cf 100644 --- a/fs/binfmt_script.c +++ b/fs/binfmt_script.c @@ -16,14 +16,14 @@  #include <linux/fs.h>  static inline bool spacetab(char c) { return c == ' ' || c == '\t'; } -static inline char *next_non_spacetab(char *first, const char *last) +static inline const char *next_non_spacetab(const char *first, const char *last)  {  	for (; first <= last; first++)  		if (!spacetab(*first))  			return first;  	return NULL;  } -static inline char *next_terminator(char *first, const char *last) +static inline const char *next_terminator(const char *first, const char *last)  {  	for (; first <= last; first++)  		if (spacetab(*first) || !*first) @@ -33,8 +33,7 @@ static inline char *next_terminator(char *first, const char *last)  static int load_script(struct linux_binprm *bprm)  { -	const char *i_arg, *i_name; -	char *cp, *buf_end; +	const char *i_name, *i_sep, *i_arg, *i_end, *buf_end;  	struct file *file;  	int retval; @@ -43,20 +42,6 @@ static int load_script(struct linux_binprm *bprm)  		return -ENOEXEC;  	/* -	 * If the script filename will be inaccessible after exec, typically -	 * because it is a "/dev/fd/<fd>/.." path against an O_CLOEXEC fd, give -	 * up now (on the assumption that the interpreter will want to load -	 * this file). -	 */ -	if (bprm->interp_flags & BINPRM_FLAGS_PATH_INACCESSIBLE) -		return -ENOENT; - -	/* Release since we are not mapping a binary into memory. */ -	allow_write_access(bprm->file); -	fput(bprm->file); -	bprm->file = NULL; - -	/*  	 * This section handles parsing the #! line into separate  	 * interpreter path and argument strings. We must be careful  	 * because bprm->buf is not yet guaranteed to be NUL-terminated @@ -71,39 +56,43 @@ static int load_script(struct linux_binprm *bprm)  	 * parse them on its own.  	 */  	buf_end = bprm->buf + sizeof(bprm->buf) - 1; -	cp = strnchr(bprm->buf, sizeof(bprm->buf), '\n'); -	if (!cp) { -		cp = next_non_spacetab(bprm->buf + 2, buf_end); -		if (!cp) +	i_end = strnchr(bprm->buf, sizeof(bprm->buf), '\n'); +	if (!i_end) { +		i_end = next_non_spacetab(bprm->buf + 2, buf_end); +		if (!i_end)  			return -ENOEXEC; /* Entire buf is spaces/tabs */  		/*  		 * If there is no later space/tab/NUL we must assume the  		 * interpreter path is truncated.  		 */ -		if (!next_terminator(cp, buf_end)) +		if (!next_terminator(i_end, buf_end))  			return -ENOEXEC; -		cp = buf_end; +		i_end = buf_end;  	} -	/* NUL-terminate the buffer and any trailing spaces/tabs. */ -	*cp = '\0'; -	while (cp > bprm->buf) { -		cp--; -		if ((*cp == ' ') || (*cp == '\t')) -			*cp = '\0'; -		else -			break; -	} -	for (cp = bprm->buf+2; (*cp == ' ') || (*cp == '\t'); cp++); -	if (*cp == '\0') +	/* Trim any trailing spaces/tabs from i_end */ +	while (spacetab(i_end[-1])) +		i_end--; + +	/* Skip over leading spaces/tabs */ +	i_name = next_non_spacetab(bprm->buf+2, i_end); +	if (!i_name || (i_name == i_end))  		return -ENOEXEC; /* No interpreter name found */ -	i_name = cp; + +	/* Is there an optional argument? */  	i_arg = NULL; -	for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) -		/* nothing */ ; -	while ((*cp == ' ') || (*cp == '\t')) -		*cp++ = '\0'; -	if (*cp) -		i_arg = cp; +	i_sep = next_terminator(i_name, i_end); +	if (i_sep && (*i_sep != '\0')) +		i_arg = next_non_spacetab(i_sep, i_end); + +	/* +	 * If the script filename will be inaccessible after exec, typically +	 * because it is a "/dev/fd/<fd>/.." path against an O_CLOEXEC fd, give +	 * up now (on the assumption that the interpreter will want to load +	 * this file). +	 */ +	if (bprm->interp_flags & BINPRM_FLAGS_PATH_INACCESSIBLE) +		return -ENOENT; +  	/*  	 * OK, we've parsed out the interpreter name and  	 * (optional) argument. @@ -121,7 +110,9 @@ static int load_script(struct linux_binprm *bprm)  	if (retval < 0)  		return retval;  	bprm->argc++; +	*((char *)i_end) = '\0';  	if (i_arg) { +		*((char *)i_sep) = '\0';  		retval = copy_strings_kernel(1, &i_arg, bprm);  		if (retval < 0)  			return retval; @@ -142,11 +133,8 @@ static int load_script(struct linux_binprm *bprm)  	if (IS_ERR(file))  		return PTR_ERR(file); -	bprm->file = file; -	retval = prepare_binprm(bprm); -	if (retval < 0) -		return retval; -	return search_binary_handler(bprm); +	bprm->interpreter = file; +	return 0;  }  static struct linux_binfmt script_format = { | 
