xfs
[Top] [All Lists]

[PATCH 3/5] fs: Provide function telling whether file_remove_privs() wil

To: Al Viro <viro@xxxxxxxxxxxxxxxxxx>
Subject: [PATCH 3/5] fs: Provide function telling whether file_remove_privs() will do anything
From: Jan Kara <jack@xxxxxxx>
Date: Thu, 18 Dec 2014 13:49:04 +0100
Cc: linux-fsdevel@xxxxxxxxxxxxxxx, xfs@xxxxxxxxxxx, linux-security-module@xxxxxxxxxxxxxxx, Jan Kara <jack@xxxxxxx>
Delivered-to: xfs@xxxxxxxxxxx
In-reply-to: <1418906946-30695-1-git-send-email-jack@xxxxxxx>
References: <1418906946-30695-1-git-send-email-jack@xxxxxxx>
Provide function telling whether file_remove_privs() will do anything.
Currently we only have should_remove_suid() and that does something
slightly different.

Signed-off-by: Jan Kara <jack@xxxxxxx>
---
 fs/inode.c         | 44 ++++++++++++++++++++++++++++++++------------
 include/linux/fs.h |  1 +
 2 files changed, 33 insertions(+), 12 deletions(-)

diff --git a/fs/inode.c b/fs/inode.c
index fcc0886c5824..77942fac4121 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -1598,7 +1598,32 @@ int should_remove_suid(struct dentry *dentry)
 }
 EXPORT_SYMBOL(should_remove_suid);
 
-static int __remove_suid(struct dentry *dentry, int kill)
+/*
+ * Return mask of changes for notify_change() that need to be done as a
+ * response to write or truncate. Return 0 if nothing has to be changed.
+ * Negative value on error (change should be denied).
+ */
+int file_needs_remove_privs(struct file *file)
+{
+       struct dentry *dentry = file->f_path.dentry;
+       struct inode *inode = dentry->d_inode;
+       int mask = 0;
+       int ret;
+
+       if (IS_NOSEC(inode))
+               return 0;
+
+       mask = should_remove_suid(dentry);
+       ret = security_inode_need_killpriv(dentry);
+       if (ret < 0)
+               return ret;
+       if (ret)
+               mask |= ATTR_KILL_PRIV;
+       return mask;
+}
+EXPORT_SYMBOL(file_needs_remove_privs);
+
+static int __remove_privs(struct dentry *dentry, int kill)
 {
        struct iattr newattrs;
 
@@ -1618,23 +1643,18 @@ int file_remove_privs(struct file *file)
 {
        struct dentry *dentry = file->f_path.dentry;
        struct inode *inode = dentry->d_inode;
-       int killsuid;
-       int killpriv;
+       int kill;
        int error = 0;
 
        /* Fast path for nothing security related */
        if (IS_NOSEC(inode))
                return 0;
 
-       killsuid = should_remove_suid(dentry);
-       killpriv = security_inode_need_killpriv(dentry);
-
-       if (killpriv < 0)
-               return killpriv;
-       if (killpriv)
-               error = security_inode_killpriv(dentry);
-       if (!error && killsuid)
-               error = __remove_suid(dentry, killsuid);
+       kill = file_needs_remove_privs(file);
+       if (kill < 0)
+               return kill;
+       if (kill)
+               error = __remove_privs(dentry, kill);
        if (!error && (inode->i_sb->s_flags & MS_NOSEC) &&
            !is_sxid(inode->i_mode))
                inode->i_flags |= S_NOSEC;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 96b2d6a9a6cb..aac707cced66 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2429,6 +2429,7 @@ extern struct inode *new_inode(struct super_block *sb);
 extern void free_inode_nonrcu(struct inode *inode);
 extern int should_remove_suid(struct dentry *);
 extern int file_remove_privs(struct file *);
+extern int file_needs_remove_privs(struct file *file);
 
 extern void __insert_inode_hash(struct inode *, unsigned long hashval);
 static inline void insert_inode_hash(struct inode *inode)
-- 
1.8.4.5

<Prev in Thread] Current Thread [Next in Thread>