summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/attr.c25
-rw-r--r--fs/internal.h5
2 files changed, 30 insertions, 0 deletions
diff --git a/fs/attr.c b/fs/attr.c
index 666489157978..c8049ae34a2e 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -20,6 +20,31 @@
#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
*
diff --git a/fs/internal.h b/fs/internal.h
index 0fe920d9f393..d5d9fcdae10c 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -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);