mirror of
https://github.com/Divested-Mobile/DivestOS-Build.git
synced 2024-10-01 01:35:54 -04:00
117 lines
3.2 KiB
Diff
117 lines
3.2 KiB
Diff
From 470e517be17dd6ef8670bec7bd7831ea0d3ad8a6 Mon Sep 17 00:00:00 2001
|
|
From: Jann Horn <jann@thejh.net>
|
|
Date: Sun, 19 Apr 2015 02:48:39 +0200
|
|
Subject: fs: take i_mutex during prepare_binprm for set[ug]id executables
|
|
|
|
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.
|
|
|
|
Signed-off-by: Jann Horn <jann@thejh.net>
|
|
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
|
|
[bwh: Backported to 3.2:
|
|
- Drop the task_no_new_privs() and user namespace checks
|
|
- Open-code file_inode()
|
|
- s/READ_ONCE/ACCESS_ONCE/
|
|
- Adjust context]
|
|
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
|
|
---
|
|
fs/exec.c | 65 +++++++++++++++++++++++++++++++++++++++------------------------
|
|
1 file changed, 40 insertions(+), 25 deletions(-)
|
|
|
|
diff --git a/fs/exec.c b/fs/exec.c
|
|
index 78199eb..7adb43f 100644
|
|
--- a/fs/exec.c
|
|
+++ b/fs/exec.c
|
|
@@ -1282,6 +1282,45 @@ int check_unsafe_exec(struct linux_binprm *bprm)
|
|
return res;
|
|
}
|
|
|
|
+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;
|
|
+ }
|
|
+}
|
|
+
|
|
/*
|
|
* Fill the binprm structure from the inode.
|
|
* Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes
|
|
@@ -1290,36 +1329,12 @@ 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)) {
|
|
- /* 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);
|
|
--
|
|
cgit v1.1
|
|
|