diff --git a/fs/exec.c b/fs/exec.c index add4a298a49a2d828397ef1e0527694b1665fb80..81f8df151d6a2bf461120e482cb2ba36dc79cde8 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1567,6 +1567,7 @@ static void bprm_fill_uid(struct linux_binprm *bprm, struct file *file) unsigned int mode; kuid_t uid; kgid_t gid; + int err; if (!mnt_may_suid(file->f_path.mnt)) return; @@ -1582,12 +1583,17 @@ static void bprm_fill_uid(struct linux_binprm *bprm, struct file *file) /* Be careful if suid/sgid is set */ inode_lock(inode); - /* reload atomically mode/uid/gid now that lock held */ + /* Atomically reload and check mode/uid/gid now that lock held. */ mode = inode->i_mode; uid = inode->i_uid; gid = inode->i_gid; + err = inode_permission(inode, MAY_EXEC); inode_unlock(inode); + /* Did the exec bit vanish out from under us? Give up. */ + if (err) + return; + /* 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))