Patch "fs: take i_mutex during prepare_binprm for set[ug]id executables" has been added to the 3.19-stable tree
Subsystems (3)
This is a note to let you know that I've just added the patch titled
fs: take i_mutex during prepare_binprm for set[ug]id executables
to the 3.19-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
fs-take-i_mutex-during-prepare_binprm-for-setid-executables.patch
and it can be found in the queue-3.19 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
8b01fc86b9f425899f8a3a8fc1c47d73c2c20543Mon Sep 17 00:00:00 2001
From: Jann Horn <[email protected]>
Date: Sun, 19 Apr 2015 02:48:39 +0200
Subject: fs: take i_mutex during prepare_binprm for set[ug]id executables
From: Jann Horn <[email protected]>
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.
--- fs/exec.c | 76 +++++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 48 insertions(+), 28 deletions(-)
fs/exec.c +48 -28
@@ -1259,6 +1259,53 @@ static void check_unsafe_exec(struct linspin_unlock (&p->fs->lock); } +static void bprm_fill_uid (struct linux_binprm *bprm) +{ +struct inode *inode; +unsigned int mode; +kuid_t uid; +kgid_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 ; + +if (task_no_new_privs (current)) +return ; + + inode =file_inode (bprm->file); + mode =READ_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); + +/* We ignore suid/sgid if there are no mappings for them in the ns */ +if (!kuid_has_mapping (bprm->cred->user_ns, uid) || + !kgid_has_mapping (bprm->cred->user_ns, gid)) +return ; + +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; + } +} +/* * Fill the binprm structure from the inode. * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes
@@ -1267,36 +1314,9 @@ static void check_unsafe_exec(struct lin*/ int prepare_binprm (struct linux_binprm *bprm) { -struct inode *inode =file_inode (bprm->file); -umode_t mode = inode->i_mode;int retval; - -/* 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) && -kuid_has_mapping (bprm->cred->user_ns, inode->i_uid) && -kgid_has_mapping (bprm->cred->user_ns, inode->i_gid)) { -/* 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);
Patches currently in stable-queue which might be from [email protected] are
queue-3.19/fs-take-i_mutex-during-prepare_binprm-for-setid-executables.patch