Navigation Menu

Skip to content

Commit

Permalink
fs: take i_mutex during prepare_binprm for set[ug]id executables
Browse files Browse the repository at this point in the history
commit 8b01fc86b9f425899f8a3a8fc1c47d73c2c20543 upstream.

This prevents a race between chown() and execve(), where chowning a
setuid-user binary to root would momentarily make the binary setuid
root.

This patch was mostly written by Linus Torvalds.

Change-Id: I6dc376d49378c63dcdccd531312061b51c7ed212
Signed-off-by: Jann Horn <jann@thejh.net>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
[lizf: Backported to 3.4:
- adjust context
- remove task_no_new_priv and user namespace stuff
- open-code file_inode()
- s/READ_ONCE/ACCESS_ONCE]
Signed-off-by: Zefan Li <lizefan@huawei.com>
  • Loading branch information
thejh authored and nardholio committed Aug 19, 2015
1 parent dc54c22 commit af567a3
Showing 1 changed file with 40 additions and 26 deletions.
66 changes: 40 additions & 26 deletions fs/exec.c
Expand Up @@ -1248,6 +1248,45 @@ void install_exec_creds(struct linux_binprm *bprm)
}
EXPORT_SYMBOL(install_exec_creds);

static void bprm_fill_uid(struct linux_binprm *bprm)
{
struct inode *inode;
unsigned int mode;
uid_t uid;
gid_t gid;

/* clear any previous set[ug]id data from a previous binary */
bprm->cred->euid = current_euid();
bprm->cred->egid = current_egid();

if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
return;

inode = bprm->file->f_path.dentry->d_inode;
mode = ACCESS_ONCE(inode->i_mode);
if (!(mode & (S_ISUID|S_ISGID)))
return;

/* Be careful if suid/sgid is set */
mutex_lock(&inode->i_mutex);

/* reload atomically mode/uid/gid now that lock held */
mode = inode->i_mode;
uid = inode->i_uid;
gid = inode->i_gid;
mutex_unlock(&inode->i_mutex);

if (mode & S_ISUID) {
bprm->per_clear |= PER_CLEAR_ON_SETID;
bprm->cred->euid = uid;
}

if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
bprm->per_clear |= PER_CLEAR_ON_SETID;
bprm->cred->egid = gid;
}
}

/*
* determine how safe it is to execute the proposed program
* - the caller must hold ->cred_guard_mutex to protect against
Expand Down Expand Up @@ -1304,37 +1343,12 @@ static int check_unsafe_exec(struct linux_binprm *bprm)
*/
int prepare_binprm(struct linux_binprm *bprm)
{
umode_t mode;
struct inode * inode = bprm->file->f_path.dentry->d_inode;
int retval;

mode = inode->i_mode;
if (bprm->file->f_op == NULL)
return -EACCES;

/* clear any previous set[ug]id data from a previous binary */
bprm->cred->euid = current_euid();
bprm->cred->egid = current_egid();

if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) &&
!task_no_new_privs(current)) {
/* Set-uid? */
if (mode & S_ISUID) {
bprm->per_clear |= PER_CLEAR_ON_SETID;
bprm->cred->euid = inode->i_uid;
}

/* Set-gid? */
/*
* If setgid is set but no group execute bit then this
* is a candidate for mandatory locking, not a setgid
* executable.
*/
if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
bprm->per_clear |= PER_CLEAR_ON_SETID;
bprm->cred->egid = inode->i_gid;
}
}
bprm_fill_uid(bprm);

/* fill in binprm security blob */
retval = security_bprm_set_creds(bprm);
Expand Down

0 comments on commit af567a3

Please sign in to comment.