]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
attr: add setattr_should_drop_sgid()
authorAmir Goldstein <amir73il@gmail.com>
Sat, 18 Mar 2023 10:15:26 +0000 (12:15 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 22 Mar 2023 12:30:07 +0000 (13:30 +0100)
commit 72ae017c5451860443a16fb2a8c243bff3e396b8 upstream.

[backported to 5.10.y, prior to idmapped mounts]

The current setgid stripping logic during write and ownership change
operations is inconsistent and strewn over multiple places. In order to
consolidate it and make more consistent we'll add a new helper
setattr_should_drop_sgid(). The function retains the old behavior where
we remove the S_ISGID bit unconditionally when S_IXGRP is set but also
when it isn't set and the caller is neither in the group of the inode
nor privileged over the inode.

We will use this helper both in write operation permission removal such
as file_remove_privs() as well as in ownership change operations.

Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Christian Brauner (Microsoft) <brauner@kernel.org>
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/attr.c
fs/internal.h

index 6664891579785e5174a0d8cd756a787a3d6f7eac..c8049ae34a2e0f75ac9f8106c7e3f4140c03e58e 100644 (file)
--- a/fs/attr.c
+++ b/fs/attr.c
 
 #include "internal.h"
 
+/**
+ * setattr_should_drop_sgid - determine whether the setgid bit needs to be
+ *                            removed
+ * @inode:     inode to check
+ *
+ * This function determines whether the setgid bit needs to be removed.
+ * We retain backwards compatibility and require setgid bit to be removed
+ * unconditionally if S_IXGRP is set. Otherwise we have the exact same
+ * requirements as setattr_prepare() and setattr_copy().
+ *
+ * Return: ATTR_KILL_SGID if setgid bit needs to be removed, 0 otherwise.
+ */
+int setattr_should_drop_sgid(const struct inode *inode)
+{
+       umode_t mode = inode->i_mode;
+
+       if (!(mode & S_ISGID))
+               return 0;
+       if (mode & S_IXGRP)
+               return ATTR_KILL_SGID;
+       if (!in_group_or_capable(inode, inode->i_gid))
+               return ATTR_KILL_SGID;
+       return 0;
+}
+
 /*
  * The logic we want is
  *
index 0fe920d9f393859a12b469d91721690da147040c..d5d9fcdae10c4578be446ba291a17419c6b03bb3 100644 (file)
@@ -197,3 +197,8 @@ int sb_init_dio_done_wq(struct super_block *sb);
  */
 int do_statx(int dfd, const char __user *filename, unsigned flags,
             unsigned int mask, struct statx __user *buffer);
+
+/*
+ * fs/attr.c
+ */
+int setattr_should_drop_sgid(const struct inode *inode);