[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1318951981-5508-24-git-send-email-aneesh.kumar@linux.vnet.ibm.com>
Date: Tue, 18 Oct 2011 21:02:58 +0530
From: "Aneesh Kumar K.V" <aneesh.kumar@...ux.vnet.ibm.com>
To: agruen@...nel.org, bfields@...ldses.org, akpm@...ux-foundation.org,
viro@...iv.linux.org.uk, dhowells@...hat.com
Cc: aneesh.kumar@...ux.vnet.ibm.com, linux-fsdevel@...r.kernel.org,
linux-nfs@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: [PATCH -V7 23/26] vfs: Add richacl permission check
From: "Aneesh Kumar K.V" <aneesh.kumar@...ux.vnet.ibm.com>
Acked-by: David Howells <dhowells@...hat.com>
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@...ux.vnet.ibm.com>
---
fs/attr.c | 6 +++-
fs/namei.c | 13 ++++++++++-
fs/richacl_base.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++
include/linux/fs.h | 2 +-
include/linux/richacl.h | 2 +
5 files changed, 73 insertions(+), 4 deletions(-)
diff --git a/fs/attr.c b/fs/attr.c
index 00578b9..2b445ba 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -13,6 +13,7 @@
#include <linux/fsnotify.h>
#include <linux/fcntl.h>
#include <linux/security.h>
+#include <linux/richacl.h>
static int richacl_change_ok(struct inode *inode, int mask)
{
@@ -21,8 +22,9 @@ static int richacl_change_ok(struct inode *inode, int mask)
if (inode->i_op->permission)
return inode->i_op->permission(inode, mask);
-
- return check_acl(inode, mask);
+ if (inode->i_op->get_richacl)
+ return check_richacl(inode, mask);
+ return -EPERM;
}
static bool inode_uid_change_ok(struct inode *inode, uid_t ia_uid)
diff --git a/fs/namei.c b/fs/namei.c
index 0c28f95..5d8f21e 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -33,6 +33,7 @@
#include <linux/device_cgroup.h>
#include <linux/fs_struct.h>
#include <linux/posix_acl.h>
+#include <linux/richacl.h>
#include <asm/uaccess.h>
#include "internal.h"
@@ -174,7 +175,7 @@ void putname(const char *name)
EXPORT_SYMBOL(putname);
#endif
-int check_acl(struct inode *inode, int mask)
+static int check_posix_acl(struct inode *inode, int mask)
{
#ifdef CONFIG_FS_POSIX_ACL
struct posix_acl *acl;
@@ -220,6 +221,16 @@ int check_acl(struct inode *inode, int mask)
return -EAGAIN;
}
+static int check_acl(struct inode *inode, int mask)
+{
+ if (IS_POSIXACL(inode))
+ return check_posix_acl(inode, mask);
+ else if (IS_RICHACL(inode))
+ return check_richacl(inode, mask);
+ else
+ return -EAGAIN;
+}
+
/*
* This does the basic permission checking
*/
diff --git a/fs/richacl_base.c b/fs/richacl_base.c
index bde2eea..9a57039 100644
--- a/fs/richacl_base.c
+++ b/fs/richacl_base.c
@@ -622,3 +622,57 @@ richacl_equiv_mode(const struct richacl *acl, mode_t *mode_p)
return 0;
}
EXPORT_SYMBOL_GPL(richacl_equiv_mode);
+
+int check_richacl(struct inode *inode, int want)
+{
+#ifdef CONFIG_FS_RICHACL
+ struct richacl *acl;
+ int richacl_mask = richacl_want_to_mask(want);
+
+ if (want & MAY_NOT_BLOCK) {
+ acl = rcu_dereference(inode->i_richacl);
+ if (!acl)
+ return -EAGAIN;
+ /* no ->get_acl() calls in RCU mode... */
+ if (acl == ACL_NOT_CACHED)
+ return -ECHILD;
+ return richacl_permission(inode, acl, richacl_mask);
+ }
+ return richacl_check_acl(inode, richacl_mask);
+#endif
+ return -EAGAIN;
+}
+
+int richacl_check_acl(struct inode *inode, int richacl_mask)
+{
+
+#ifdef CONFIG_FS_RICHACL
+ struct richacl *acl;
+ acl = get_cached_richacl(inode);
+ /*
+ * A filesystem can force a ACL callback by just never filling the
+ * ACL cache. But normally you'd fill the cache either at inode
+ * instantiation time, or on the first ->get_acl call.
+ *
+ * If the filesystem doesn't have a get_acl() function at all, we'll
+ * just create the negative cache entry.
+ */
+ if (acl == ACL_NOT_CACHED) {
+ if (inode->i_op->get_acl) {
+ acl = inode->i_op->get_richacl(inode);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+ } else {
+ set_cached_richacl(inode, NULL);
+ return -EAGAIN;
+ }
+ }
+ if (acl) {
+ int error = richacl_permission(inode, acl, richacl_mask);
+ richacl_put(acl);
+ return error;
+ }
+#endif
+ return -EAGAIN;
+}
+EXPORT_SYMBOL_GPL(richacl_check_acl);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 771955c..e01bad7 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1624,6 +1624,7 @@ struct inode_operations {
void * (*follow_link) (struct dentry *, struct nameidata *);
int (*permission) (struct inode *, int);
struct posix_acl * (*get_acl)(struct inode *, int);
+ struct richacl * (*get_richacl)(struct inode *);
int (*readlink) (struct dentry *, char __user *,int);
void (*put_link) (struct dentry *, struct nameidata *, void *);
@@ -2243,7 +2244,6 @@ extern sector_t bmap(struct inode *, sector_t);
extern int notify_change(struct dentry *, struct iattr *);
extern int inode_permission(struct inode *, int);
extern int generic_permission(struct inode *, int);
-extern int check_acl(struct inode *, int);
static inline bool execute_ok(struct inode *inode)
{
diff --git a/include/linux/richacl.h b/include/linux/richacl.h
index 694b7dc..4af6d22 100644
--- a/include/linux/richacl.h
+++ b/include/linux/richacl.h
@@ -367,6 +367,8 @@ extern int richacl_permission(struct inode *, const struct richacl *,
unsigned int);
extern struct richacl *richacl_inherit(const struct richacl *, int);
extern int richacl_equiv_mode(const struct richacl *, mode_t *);
+extern int check_richacl(struct inode *, int);
+extern int richacl_check_acl(struct inode *, int);
/* richacl_inode.c */
extern struct richacl *richacl_inherit_inode(const struct richacl *,
--
1.7.5.4
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists