All of lore.kernel.org
 help / color / mirror / Atom feed
From: Randy Dunlap <rdunlap@xenotime.net>
To: halfdog <me@halfdog.net>
Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>,
	Alexander Viro <viro@zeniv.linux.org.uk>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH] Fix kernel stack data disclosure in binfmt_script during execve
Date: Fri, 21 Sep 2012 12:15:37 -0700	[thread overview]
Message-ID: <505CBCD9.7060908@xenotime.net> (raw)
In-Reply-To: <505B3EDB.8020009@halfdog.net>

On 09/20/2012 09:05 AM, halfdog wrote:

> halfdog wrote:
> 
> Now this is the updated and also tested patch (vs. linux-3.5.4 kernel) to fix
> https://bugzilla.kernel.org/show_bug.cgi?id=46841 . See also
> http://www.halfdog.net/Security/2012/LinuxKernelBinfmtScriptStackDataDisclosure/
> This patch adresses the stack data disclosure but does not deal with the
> excessive recursion (to be handled in separate patch if needed).
> 
> --- fs/binfmt_script.c	2012-09-14 22:28:08.000000000 +0000
> +++ fs/binfmt_script.c	2012-09-20 16:01:58.951942355 +0000


Incorrect diff/patch format for kernel patches.
It should be apply-able by using 'patch -p1'.

Oh, the patch is not signed off.
And Documentation/SubmittingPatches says signoffs are:

"using your real name (sorry, no pseudonyms or anonymous contributions.)"

There are also some kernel coding style issues that should be
fixed if this patch is to be merged.

> @@ -14,12 +14,24 @@
>  #include <linux/err.h>
>  #include <linux/fs.h>
> 
> +/** Check if this handler is suitable to load the "binary" identified


/** means kernel-doc notation in the kernel, but this comment
block is not kernel-doc, so don't start it with /**

> + *  by first BINPRM_BUF_SIZE bytes in bprm->buf.
> + *  @returns -ENOEXEC if this handler is not suitable for that type


We don't use "@returns", just returns: <text>.

> + *  of binary. In that case, the handler must not modify any of the
> + *  data associated with bprm.
> + *  Any error if the binary should have been handled by this loader
> + *  but handling failed. In that case. FIXME: be defensive? also
> + *  kill bprm->mm or bprm->file also to make it impossible, that
> + *  upper search_binary_handler can continue handling?
> + *  0 (OK) otherwise, the new executable is ready in bprm->mm.
> + */
>  static int load_script(struct linux_binprm *bprm,struct pt_regs *regs)
>  {
>  	const char *i_arg, *i_name;
>  	char *cp;
>  	struct file *file;
> -	char interp[BINPRM_BUF_SIZE];
> +	char bprm_buf_copy[BINPRM_BUF_SIZE];
> +	const char *bprm_old_interp_name;
>  	int retval;
> 
>  	if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!') ||
> @@ -30,25 +42,29 @@ static int load_script(struct linux_binp
>  	 * Sorta complicated, but hopefully it will work.  -TYT
>  	 */
> 
> -	bprm->recursion_depth++;
> -	allow_write_access(bprm->file);
> -	fput(bprm->file);
> -	bprm->file = NULL;
> +	/* Keep bprm unchanged until we known, that this is a script
> +	 * to be handled by this loader. Copy bprm->buf for sure,
> +	 * otherwise returning -ENOEXEC will make other handlers see
> +	 * modified data. (hd)
> +	 */


Kernel multi-line comment style is
	/*
	 * line 1
	 * line 2
	 */

> +	memcpy(bprm_buf_copy, bprm->buf, BINPRM_BUF_SIZE);
> 
> -	bprm->buf[BINPRM_BUF_SIZE - 1] = '\0';
> -	if ((cp = strchr(bprm->buf, '\n')) == NULL)
> -		cp = bprm->buf+BINPRM_BUF_SIZE-1;
> +	bprm_buf_copy[BINPRM_BUF_SIZE - 1]='\0';
> +	if ((cp = strchr(bprm_buf_copy, '\n')) == NULL)
> +		cp = bprm_buf_copy+BINPRM_BUF_SIZE-1;
>  	*cp = '\0';
> -	while (cp > bprm->buf) {
> +	while (cp > bprm_buf_copy) {
>  		cp--;
>  		if ((*cp == ' ') || (*cp == '\t'))
>  			*cp = '\0';
>  		else
>  			break;
>  	}
> -	for (cp = bprm->buf+2; (*cp == ' ') || (*cp == '\t'); cp++);
> +	for (cp = bprm_buf_copy+2; (*cp == ' ') || (*cp == '\t'); cp++);
>  	if (*cp == '\0')
> -		return -ENOEXEC; /* No interpreter name found */
> +	/* No interpreter name found. No problem to let other handlers
> +	 * retry, we did not change anything. */


multi-line comment style.

> +		return -ENOEXEC;
>  	i_name = cp;
>  	i_arg = NULL;
>  	for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++)
> @@ -57,45 +73,84 @@ static int load_script(struct linux_binp
>  		*cp++ = '\0';
>  	if (*cp)
>  		i_arg = cp;
> -	strcpy (interp, i_name);
> +
> +	/* So this is our point-of-no-return: modification of bprm
> +	 * will be irreversible, so if we fail to setup execution
> +	 * using the new interpreter name (i_name), we have to make
> +	 * sure, that no other handler tries again. (hd)
> +	 */


ditto.

> +
>  	/*
>  	 * OK, we've parsed out the interpreter name and
>  	 * (optional) argument.
>  	 * Splice in (1) the interpreter's name for argv[0]
> -	 *           (2) (optional) argument to interpreter
> -	 *           (3) filename of shell script (replace argv[0])
> +	 *	   (2) (optional) argument to interpreter
> +	 *	   (3) filename of shell script (replace argv[0])
>  	 *
>  	 * This is done in reverse order, because of how the
>  	 * user environment and arguments are stored.
>  	 */
> +
> +	/* Ugly: we store pointer to local stack frame in bprm,
> +	 * so make sure to clear this up before returning.
> +	 */


ditto.

> +	bprm_old_interp_name = bprm->interp;
> +	bprm->interp = i_name;
> +
>  	retval = remove_arg_zero(bprm);
> -	if (retval)
> -		return retval;
> -	retval = copy_strings_kernel(1, &bprm->interp, bprm);
> -	if (retval < 0) return retval;
> +	if (retval) goto out;


Really should be
	if (retval)
		goto out;

> +	/* copy_strings_kernel is ok here, even when racy: since no
> +	 * user can be attached to new mm, there is nobody to race
> +	 * with and call is safe for now. The return code of
> +	 * copy_strings_kernel cannot be -ENOEXEC in any case,
> +	 * so no special checks needed. (hd)
> +	 */


style.

> +	retval = copy_strings_kernel(1, &bprm_old_interp_name, bprm);
> +	if (retval < 0) goto out;
>  	bprm->argc++;
>  	if (i_arg) {
>  		retval = copy_strings_kernel(1, &i_arg, bprm);
> -		if (retval < 0) return retval;
> +		if (retval < 0) goto out;


style.

>  		bprm->argc++;
>  	}
> -	retval = copy_strings_kernel(1, &i_name, bprm);
> -	if (retval) return retval;
> +	retval = copy_strings_kernel(1, &bprm->interp, bprm);
> +	if (retval) goto out;


style.  (but Al can override these if he wants to)

>  	bprm->argc++;
> -	bprm->interp = interp;
> 
>  	/*
>  	 * OK, now restart the process with the interpreter's dentry.
> +         * Release old file first


indentation mucked up.

>  	 */
> -	file = open_exec(interp);
> -	if (IS_ERR(file))
> -		return PTR_ERR(file);
> -
> +	allow_write_access(bprm->file);
> +	fput(bprm->file);
> +	bprm->file = NULL;
> +	file = open_exec(bprm->interp);
> +	if (IS_ERR(file)) {
> +		retval=PTR_ERR(file);
> +		goto out;
> +        }
>  	bprm->file = file;
> +	/* Caveat: This also updates the credentials of the next exec. */
>  	retval = prepare_binprm(bprm);
>  	if (retval < 0)
> -		return retval;
> -	return search_binary_handler(bprm,regs);
> +		goto out;
> +	bprm->recursion_depth++;
> +	retval=search_binary_handler(bprm,regs);
> +
> +out:	/* Make sure, we do not return local stack frame data. If
> +	 * it would be needed after returning, we would have needed
> +	 * to allocate memory or use copy from new bprm->mm anyway. (hd)
> +         */


Comment block probably should come before the label.
and the indentation is mucked up.

> +	bprm->interp = bprm_old_interp_name;
> +	if(!retval) {
> +		/* The handlers for starting of interpreter failed.
> +		 * bprm is already modified, hence we are dead here.
> +		 * Make sure, that we do not return -ENOEXEC, that would
> +		 * allow searching for handlers to continue. (hd).
> +		 */

style

> +		if(retval==-ENOEXEC) retval=-EINVAL;


missing space before '('.
etc.

> +	}
> +	return(retval);
>  }
> 
>  static struct linux_binfmt script_format = {
> 



-- 
~Randy

  reply	other threads:[~2012-09-21 19:16 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-08-18 14:00 Search for patch for kernel stack disclosure in binfmt_script during execve halfdog
2012-08-19  8:39 ` Search for patch for kernel stack data " halfdog
2012-08-22 21:49   ` halfdog
2012-08-23  8:56     ` Kirill A. Shutemov
2012-08-24 10:10       ` halfdog
2012-09-20 16:05         ` [PATCH] Fix " halfdog
2012-09-21 19:15           ` Randy Dunlap [this message]
2012-09-23  4:54             ` [PATCH v2] " halfdog

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=505CBCD9.7060908@xenotime.net \
    --to=rdunlap@xenotime.net \
    --cc=kirill.shutemov@linux.intel.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=me@halfdog.net \
    --cc=viro@zeniv.linux.org.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.