Skip to content

Commit

Permalink
exec: load_script: kill the onstack interp[BINPRM_BUF_SIZE] array
Browse files Browse the repository at this point in the history
Patch series "exec: binfmt_misc: fix use-after-free, kill
iname[BINPRM_BUF_SIZE]".

It looks like this code was always wrong, then commit 948b701
("binfmt_misc: add persistent opened binary handler for containers")
added more problems.

This patch (of 6):

load_script() can simply use i_name instead, it points into bprm->buf[]
and nobody can change this memory until we call prepare_binprm().

The only complication is that we need to also change the signature of
bprm_change_interp() but this change looks good too.

While at it, do whitespace/style cleanups.

NOTE: the real motivation for this change is that people want to
increase BINPRM_BUF_SIZE, we need to change load_misc_binary() too but
this looks more complicated because afaics it is very buggy.

Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Oleg Nesterov <[email protected]>
Acked-by: Kees Cook <[email protected]>
Cc: Travis Gummels <[email protected]>
Cc: Ben Woodard <[email protected]>
Cc: Jim Foraker <[email protected]>
Cc: <[email protected]>
Cc: Al Viro <[email protected]>
Cc: James Bottomley <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
oleg-nesterov authored and torvalds committed Oct 4, 2017
1 parent 384632e commit c2315c1
Show file tree
Hide file tree
Showing 3 changed files with 11 additions and 10 deletions.
17 changes: 9 additions & 8 deletions fs/binfmt_script.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ static int load_script(struct linux_binprm *bprm)
const char *i_arg, *i_name;
char *cp;
struct file *file;
char interp[BINPRM_BUF_SIZE];
int retval;

if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!'))
Expand Down Expand Up @@ -55,7 +54,7 @@ static int load_script(struct linux_binprm *bprm)
break;
}
for (cp = bprm->buf+2; (*cp == ' ') || (*cp == '\t'); cp++);
if (*cp == '\0')
if (*cp == '\0')
return -ENOEXEC; /* No interpreter name found */
i_name = cp;
i_arg = NULL;
Expand All @@ -65,7 +64,6 @@ static int load_script(struct linux_binprm *bprm)
*cp++ = '\0';
if (*cp)
i_arg = cp;
strcpy (interp, i_name);
/*
* OK, we've parsed out the interpreter name and
* (optional) argument.
Expand All @@ -80,24 +78,27 @@ static int load_script(struct linux_binprm *bprm)
if (retval)
return retval;
retval = copy_strings_kernel(1, &bprm->interp, bprm);
if (retval < 0) return retval;
if (retval < 0)
return retval;
bprm->argc++;
if (i_arg) {
retval = copy_strings_kernel(1, &i_arg, bprm);
if (retval < 0) return retval;
if (retval < 0)
return retval;
bprm->argc++;
}
retval = copy_strings_kernel(1, &i_name, bprm);
if (retval) return retval;
if (retval)
return retval;
bprm->argc++;
retval = bprm_change_interp(interp, bprm);
retval = bprm_change_interp(i_name, bprm);
if (retval < 0)
return retval;

/*
* OK, now restart the process with the interpreter's dentry.
*/
file = open_exec(interp);
file = open_exec(i_name);
if (IS_ERR(file))
return PTR_ERR(file);

Expand Down
2 changes: 1 addition & 1 deletion fs/exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -1410,7 +1410,7 @@ static void free_bprm(struct linux_binprm *bprm)
kfree(bprm);
}

int bprm_change_interp(char *interp, struct linux_binprm *bprm)
int bprm_change_interp(const char *interp, struct linux_binprm *bprm)
{
/* If a binfmt changed the interp, free it first. */
if (bprm->interp != bprm->filename)
Expand Down
2 changes: 1 addition & 1 deletion include/linux/binfmts.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ extern int setup_arg_pages(struct linux_binprm * bprm,
int executable_stack);
extern int transfer_args_to_stack(struct linux_binprm *bprm,
unsigned long *sp_location);
extern int bprm_change_interp(char *interp, struct linux_binprm *bprm);
extern int bprm_change_interp(const char *interp, struct linux_binprm *bprm);
extern int copy_strings_kernel(int argc, const char *const *argv,
struct linux_binprm *bprm);
extern int prepare_bprm_creds(struct linux_binprm *bprm);
Expand Down

0 comments on commit c2315c1

Please sign in to comment.