]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 14 Aug 2024 18:08:03 +0000 (20:08 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 14 Aug 2024 18:08:03 +0000 (20:08 +0200)
added patches:
exec-fix-toctou-between-perm-check-and-set-uid-gid-usage.patch

queue-5.4/exec-fix-toctou-between-perm-check-and-set-uid-gid-usage.patch [new file with mode: 0644]
queue-5.4/series

diff --git a/queue-5.4/exec-fix-toctou-between-perm-check-and-set-uid-gid-usage.patch b/queue-5.4/exec-fix-toctou-between-perm-check-and-set-uid-gid-usage.patch
new file mode 100644 (file)
index 0000000..d9ca405
--- /dev/null
@@ -0,0 +1,95 @@
+From f50733b45d865f91db90919f8311e2127ce5a0cb Mon Sep 17 00:00:00 2001
+From: Kees Cook <kees@kernel.org>
+Date: Thu, 8 Aug 2024 11:39:08 -0700
+Subject: exec: Fix ToCToU between perm check and set-uid/gid usage
+
+From: Kees Cook <kees@kernel.org>
+
+commit f50733b45d865f91db90919f8311e2127ce5a0cb upstream.
+
+When opening a file for exec via do_filp_open(), permission checking is
+done against the file's metadata at that moment, and on success, a file
+pointer is passed back. Much later in the execve() code path, the file
+metadata (specifically mode, uid, and gid) is used to determine if/how
+to set the uid and gid. However, those values may have changed since the
+permissions check, meaning the execution may gain unintended privileges.
+
+For example, if a file could change permissions from executable and not
+set-id:
+
+---------x 1 root root 16048 Aug  7 13:16 target
+
+to set-id and non-executable:
+
+---S------ 1 root root 16048 Aug  7 13:16 target
+
+it is possible to gain root privileges when execution should have been
+disallowed.
+
+While this race condition is rare in real-world scenarios, it has been
+observed (and proven exploitable) when package managers are updating
+the setuid bits of installed programs. Such files start with being
+world-executable but then are adjusted to be group-exec with a set-uid
+bit. For example, "chmod o-x,u+s target" makes "target" executable only
+by uid "root" and gid "cdrom", while also becoming setuid-root:
+
+-rwxr-xr-x 1 root cdrom 16048 Aug  7 13:16 target
+
+becomes:
+
+-rwsr-xr-- 1 root cdrom 16048 Aug  7 13:16 target
+
+But racing the chmod means users without group "cdrom" membership can
+get the permission to execute "target" just before the chmod, and when
+the chmod finishes, the exec reaches brpm_fill_uid(), and performs the
+setuid to root, violating the expressed authorization of "only cdrom
+group members can setuid to root".
+
+Re-check that we still have execute permissions in case the metadata
+has changed. It would be better to keep a copy from the perm-check time,
+but until we can do that refactoring, the least-bad option is to do a
+full inode_permission() call (under inode lock). It is understood that
+this is safe against dead-locks, but hardly optimal.
+
+Reported-by: Marco Vanotti <mvanotti@google.com>
+Tested-by: Marco Vanotti <mvanotti@google.com>
+Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: stable@vger.kernel.org
+Cc: Eric Biederman <ebiederm@xmission.com>
+Cc: Alexander Viro <viro@zeniv.linux.org.uk>
+Cc: Christian Brauner <brauner@kernel.org>
+Signed-off-by: Kees Cook <kees@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/exec.c |    8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/fs/exec.c
++++ b/fs/exec.c
+@@ -1558,6 +1558,7 @@ static void bprm_fill_uid(struct linux_b
+       unsigned int mode;
+       kuid_t uid;
+       kgid_t gid;
++      int err;
+       /*
+        * Since this can be called multiple times (via prepare_binprm),
+@@ -1582,12 +1583,17 @@ static void bprm_fill_uid(struct linux_b
+       /* 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))
index a1a20eb6a9db6eb1673e10fbd9bf3805d2c2ab05..e07bf2d2e02f73b69a7b318da0e9a01fc9671f6d 100644 (file)
@@ -254,3 +254,4 @@ netfilter-nf_tables-prefer-nft_chain_validate.patch
 drm-i915-gem-fix-virtual-memory-mapping-boundaries-calculation.patch
 arm64-cpufeature-fix-the-visibility-of-compat-hwcaps.patch
 media-uvcvideo-use-entity-get_cur-in-uvc_ctrl_set.patch
+exec-fix-toctou-between-perm-check-and-set-uid-gid-usage.patch