Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1449507 > unrolled thread
| Started by | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| First post | 2016-07-25 16:10 +0200 |
| Last post | 2016-07-25 16:20 +0200 |
| Articles | 3 on this page of 23 — 1 participant |
Back to article view | Back to linux.kernel
[PATCH v24 00/22] Richacls (Core and Ext4) Andreas Gruenbacher <agruenba@redhat.com> - 2016-07-25 16:10 +0200
[PATCH v24 03/22] vfs: Add MAY_DELETE_SELF and MAY_DELETE_CHILD permission flags Andreas Gruenbacher <agruenba@redhat.com> - 2016-07-25 16:20 +0200
[PATCH v24 21/22] ext4: Add richacl support Andreas Gruenbacher <agruenba@redhat.com> - 2016-07-25 16:20 +0200
[PATCH v24 22/22] ext4: Add richacl feature flag Andreas Gruenbacher <agruenba@redhat.com> - 2016-07-25 16:20 +0200
[PATCH v24 13/22] richacl: Update the file masks in chmod() Andreas Gruenbacher <agruenba@redhat.com> - 2016-07-25 16:20 +0200
[PATCH v24 18/22] richacl: Add richacl xattr handler Andreas Gruenbacher <agruenba@redhat.com> - 2016-07-25 16:20 +0200
[PATCH v24 19/22] vfs: Add richacl permission checking Andreas Gruenbacher <agruenba@redhat.com> - 2016-07-25 16:20 +0200
[PATCH v24 09/22] richacl: Compute maximum file masks from an acl Andreas Gruenbacher <agruenba@redhat.com> - 2016-07-25 16:20 +0200
[PATCH v24 01/22] vfs: Add IS_ACL() and IS_RICHACL() tests Andreas Gruenbacher <agruenba@redhat.com> - 2016-07-25 16:20 +0200
[PATCH v24 20/22] vfs: Move check_posix_acl and check_richacl out of fs/namei.c Andreas Gruenbacher <agruenba@redhat.com> - 2016-07-25 16:20 +0200
[PATCH v24 04/22] vfs: Make the inode passed to inode_change_ok non-const Andreas Gruenbacher <agruenba@redhat.com> - 2016-07-25 16:20 +0200
[PATCH v24 06/22] richacl: In-memory representation and helper functions Andreas Gruenbacher <agruenba@redhat.com> - 2016-07-25 16:20 +0200
[PATCH v24 02/22] vfs: Add MAY_CREATE_FILE and MAY_CREATE_DIR permission flags Andreas Gruenbacher <agruenba@redhat.com> - 2016-07-25 16:20 +0200
[PATCH v24 15/22] richacl: Create-time inheritance Andreas Gruenbacher <agruenba@redhat.com> - 2016-07-25 16:20 +0200
[PATCH v24 17/22] richacl: xattr mapping functions Andreas Gruenbacher <agruenba@redhat.com> - 2016-07-25 16:20 +0200
[PATCH v24 11/22] vfs: Add get_richacl and set_richacl inode operations Andreas Gruenbacher <agruenba@redhat.com> - 2016-07-25 16:20 +0200
[PATCH v24 12/22] vfs: Cache richacl in struct inode Andreas Gruenbacher <agruenba@redhat.com> - 2016-07-25 16:20 +0200
[PATCH v24 05/22] vfs: Add permission flags for setting file attributes Andreas Gruenbacher <agruenba@redhat.com> - 2016-07-25 16:20 +0200
[PATCH v24 08/22] richacl: Permission check algorithm Andreas Gruenbacher <agruenba@redhat.com> - 2016-07-25 16:20 +0200
[PATCH v24 14/22] richacl: Check if an acl is equivalent to a file mode Andreas Gruenbacher <agruenba@redhat.com> - 2016-07-25 16:20 +0200
[PATCH v24 07/22] richacl: Permission mapping functions Andreas Gruenbacher <agruenba@redhat.com> - 2016-07-25 16:20 +0200
[PATCH v24 10/22] vfs: Cache base_acl objects in inodes Andreas Gruenbacher <agruenba@redhat.com> - 2016-07-25 16:20 +0200
[PATCH v24 16/22] richacl: Automatic Inheritance Andreas Gruenbacher <agruenba@redhat.com> - 2016-07-25 16:20 +0200
Page 2 of 2 — ← Prev page 1 [2]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2016-07-25 16:20 +0200 |
| Subject | [PATCH v24 07/22] richacl: Permission mapping functions |
| Message-ID | <rYOTF-5Bn-51@gated-at.bofh.it> |
| In reply to | #1449507 |
We need to map from POSIX permissions to NFSv4 permissions when a
chmod() is done, from NFSv4 permissions to POSIX permissions when an acl
is set (which implicitly sets the file permission bits), and from the
MAY_READ/MAY_WRITE/MAY_EXEC/MAY_APPEND flags to NFSv4 permissions when
doing an access check in a richacl.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Reviewed-by: J. Bruce Fields <bfields@redhat.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
---
fs/richacl.c | 112 +++++++++++++++++++++++++++++++++++++++++++
include/linux/richacl.h | 2 +
include/uapi/linux/richacl.h | 44 +++++++++++++++++
3 files changed, 158 insertions(+)
diff --git a/fs/richacl.c b/fs/richacl.c
index bcc6591..2072cf4 100644
--- a/fs/richacl.c
+++ b/fs/richacl.c
@@ -63,3 +63,115 @@ richace_copy(struct richace *to, const struct richace *from)
{
memcpy(to, from, sizeof(struct richace));
}
+
+/*
+ * richacl_mask_to_mode - compute the file permission bits from mask
+ * @mask: %RICHACE_* permission mask
+ *
+ * Compute the file permission bits corresponding to a particular set of
+ * richacl permissions.
+ *
+ * See richacl_masks_to_mode().
+ */
+static int
+richacl_mask_to_mode(unsigned int mask)
+{
+ int mode = 0;
+
+ if (mask & RICHACE_POSIX_MODE_READ)
+ mode |= S_IROTH;
+ if (mask & RICHACE_POSIX_MODE_WRITE)
+ mode |= S_IWOTH;
+ if (mask & RICHACE_POSIX_MODE_EXEC)
+ mode |= S_IXOTH;
+
+ return mode;
+}
+
+/**
+ * richacl_masks_to_mode - compute file permission bits from file masks
+ *
+ * When setting a richacl, we set the file permission bits to indicate maximum
+ * permissions: for example, we set the Write permission when a mask contains
+ * RICHACE_APPEND_DATA even if it does not also contain RICHACE_WRITE_DATA.
+ *
+ * Permissions which are not in RICHACE_POSIX_MODE_READ,
+ * RICHACE_POSIX_MODE_WRITE, or RICHACE_POSIX_MODE_EXEC cannot be represented
+ * in the file permission bits. Such permissions can still be effective, but
+ * not for new files or after a chmod(); they must be explicitly enabled in the
+ * richacl.
+ */
+int
+richacl_masks_to_mode(const struct richacl *acl)
+{
+ return richacl_mask_to_mode(acl->a_owner_mask) << 6 |
+ richacl_mask_to_mode(acl->a_group_mask) << 3 |
+ richacl_mask_to_mode(acl->a_other_mask);
+}
+EXPORT_SYMBOL_GPL(richacl_masks_to_mode);
+
+/**
+ * richacl_mode_to_mask - compute a file mask from the lowest three mode bits
+ * @mode: mode to convert to richacl permissions
+ *
+ * When the file permission bits of a file are set with chmod(), this specifies
+ * the maximum permissions that processes will get. All permissions beyond
+ * that will be removed from the file masks, and become ineffective.
+ */
+unsigned int
+richacl_mode_to_mask(umode_t mode)
+{
+ unsigned int mask = 0;
+
+ if (mode & S_IROTH)
+ mask |= RICHACE_POSIX_MODE_READ;
+ if (mode & S_IWOTH)
+ mask |= RICHACE_POSIX_MODE_WRITE;
+ if (mode & S_IXOTH)
+ mask |= RICHACE_POSIX_MODE_EXEC;
+
+ return mask;
+}
+
+/**
+ * richacl_want_to_mask - convert the iop->permission want argument to a mask
+ * @want: @want argument of the permission inode operation
+ *
+ * When checking for append, create file, create dir, or delete child access,
+ * MAY_WRITE is also set in @want.
+ */
+static unsigned int
+richacl_want_to_mask(unsigned int want)
+{
+ unsigned int mask = 0;
+
+ if (want & MAY_READ)
+ mask |= RICHACE_READ_DATA;
+ if (want & MAY_DELETE_SELF)
+ mask |= RICHACE_DELETE;
+ if (want & MAY_TAKE_OWNERSHIP)
+ mask |= RICHACE_WRITE_OWNER;
+ if (want & MAY_CHMOD)
+ mask |= RICHACE_WRITE_ACL;
+ if (want & MAY_SET_TIMES)
+ mask |= RICHACE_WRITE_ATTRIBUTES;
+ if (want & MAY_EXEC)
+ mask |= RICHACE_EXECUTE;
+ /*
+ * differentiate MAY_WRITE from these request
+ */
+ if (want & (MAY_APPEND |
+ MAY_CREATE_FILE | MAY_CREATE_DIR |
+ MAY_DELETE_CHILD)) {
+ if (want & MAY_APPEND)
+ mask |= RICHACE_APPEND_DATA;
+ if (want & MAY_CREATE_FILE)
+ mask |= RICHACE_ADD_FILE;
+ if (want & MAY_CREATE_DIR)
+ mask |= RICHACE_ADD_SUBDIRECTORY;
+ if (want & MAY_DELETE_CHILD)
+ mask |= RICHACE_DELETE_CHILD;
+ } else if (want & MAY_WRITE)
+ mask |= RICHACE_WRITE_DATA;
+ return mask;
+}
diff --git a/include/linux/richacl.h b/include/linux/richacl.h
index edb8480..70923f8 100644
--- a/include/linux/richacl.h
+++ b/include/linux/richacl.h
@@ -175,5 +175,7 @@ richace_is_same_identifier(const struct richace *a, const struct richace *b)
extern struct richacl *richacl_alloc(int, gfp_t);
extern struct richacl *richacl_clone(const struct richacl *, gfp_t);
extern void richace_copy(struct richace *, const struct richace *);
+extern int richacl_masks_to_mode(const struct richacl *);
+extern unsigned int richacl_mode_to_mask(umode_t);
#endif /* __RICHACL_H */
diff --git a/include/uapi/linux/richacl.h b/include/uapi/linux/richacl.h
index 08856f8..1ed48ac 100644
--- a/include/uapi/linux/richacl.h
+++ b/include/uapi/linux/richacl.h
@@ -96,4 +96,48 @@
RICHACE_WRITE_OWNER | \
RICHACE_SYNCHRONIZE )
+/*
+ * The POSIX permissions are supersets of the following richacl permissions:
+ *
+ * - MAY_READ maps to READ_DATA or LIST_DIRECTORY, depending on the type
+ * of the file system object.
+ *
+ * - MAY_WRITE maps to WRITE_DATA or RICHACE_APPEND_DATA for files, and to
+ * ADD_FILE, RICHACE_ADD_SUBDIRECTORY, or RICHACE_DELETE_CHILD for directories.
+ *
+ * - MAY_EXECUTE maps to RICHACE_EXECUTE.
+ *
+ * (Some of these richacl permissions have the same bit values.)
+ */
+#define RICHACE_POSIX_MODE_READ ( \
+ RICHACE_READ_DATA | \
+ RICHACE_LIST_DIRECTORY)
+#define RICHACE_POSIX_MODE_WRITE ( \
+ RICHACE_WRITE_DATA | \
+ RICHACE_ADD_FILE | \
+ RICHACE_APPEND_DATA | \
+ RICHACE_ADD_SUBDIRECTORY | \
+ RICHACE_DELETE_CHILD)
+#define RICHACE_POSIX_MODE_EXEC RICHACE_EXECUTE
+#define RICHACE_POSIX_MODE_ALL ( \
+ RICHACE_POSIX_MODE_READ | \
+ RICHACE_POSIX_MODE_WRITE | \
+ RICHACE_POSIX_MODE_EXEC)
+
+/*
+ * These permissions are always allowed no matter what the acl says.
+ */
+#define RICHACE_POSIX_ALWAYS_ALLOWED ( \
+ RICHACE_SYNCHRONIZE | \
+ RICHACE_READ_ATTRIBUTES | \
+ RICHACE_READ_ACL)
+
+/*
+ * The owner is implicitly granted these permissions under POSIX.
+ */
+#define RICHACE_POSIX_OWNER_ALLOWED ( \
+ RICHACE_WRITE_ATTRIBUTES | \
+ RICHACE_WRITE_OWNER | \
+ RICHACE_WRITE_ACL)
+
#endif /* __UAPI_RICHACL_H */
--
2.5.5
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2016-07-25 16:20 +0200 |
| Subject | [PATCH v24 10/22] vfs: Cache base_acl objects in inodes |
| Message-ID | <rYOTF-5Bn-57@gated-at.bofh.it> |
| In reply to | #1449507 |
POSIX ACLs and richacls are both objects allocated by kmalloc() with a
reference count which are freed by kfree_rcu(). An inode can either
cache an access and a default POSIX ACL, or a richacl (richacls do not
have default acls). To allow an inode to cache either of the two kinds
of acls, introduce a new base_acl type and convert i_acl and
i_default_acl to that type. In most cases, the vfs then doesn't care which
kind of acl an inode caches (if any).
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Cc: Andreas Dilger <adilger@dilger.ca>
---
drivers/staging/lustre/lustre/llite/llite_lib.c | 2 +-
fs/9p/acl.c | 8 +--
fs/f2fs/acl.c | 4 +-
fs/inode.c | 32 +++++++++++-
fs/jffs2/acl.c | 6 ++-
fs/namei.c | 33 ++++++------
fs/nfs/nfs3acl.c | 14 ++---
fs/posix_acl.c | 69 +++++++------------------
fs/richacl.c | 4 +-
include/linux/fs.h | 39 ++++++++++++--
include/linux/posix_acl.h | 19 ++++---
include/linux/richacl.h | 9 ++--
12 files changed, 137 insertions(+), 102 deletions(-)
diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c
index 96c7e9f..7819a7c 100644
--- a/drivers/staging/lustre/lustre/llite/llite_lib.c
+++ b/drivers/staging/lustre/lustre/llite/llite_lib.c
@@ -1087,7 +1087,7 @@ void ll_clear_inode(struct inode *inode)
}
#ifdef CONFIG_FS_POSIX_ACL
else if (lli->lli_posix_acl) {
- LASSERT(atomic_read(&lli->lli_posix_acl->a_refcount) == 1);
+ LASSERT(base_acl_refcount(&lli->lli_posix_acl->a_base) == 1);
LASSERT(!lli->lli_remote_perms);
posix_acl_release(lli->lli_posix_acl);
lli->lli_posix_acl = NULL;
diff --git a/fs/9p/acl.c b/fs/9p/acl.c
index 0576eae..1ce572f 100644
--- a/fs/9p/acl.c
+++ b/fs/9p/acl.c
@@ -87,14 +87,14 @@ int v9fs_get_acl(struct inode *inode, struct p9_fid *fid)
static struct posix_acl *v9fs_get_cached_acl(struct inode *inode, int type)
{
- struct posix_acl *acl;
+ struct base_acl *base_acl;
/*
* 9p Always cache the acl value when
* instantiating the inode (v9fs_inode_from_fid)
*/
- acl = get_cached_acl(inode, type);
- BUG_ON(is_uncached_acl(acl));
- return acl;
+ base_acl = get_cached_acl(inode, type);
+ BUG_ON(is_uncached_acl(base_acl));
+ return posix_acl(base_acl);
}
struct posix_acl *v9fs_iop_get_acl(struct inode *inode, int type)
diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c
index a31c7e8..6079017 100644
--- a/fs/f2fs/acl.c
+++ b/fs/f2fs/acl.c
@@ -267,7 +267,7 @@ static struct posix_acl *f2fs_acl_clone(const struct posix_acl *acl,
sizeof(struct posix_acl_entry);
clone = kmemdup(acl, size, flags);
if (clone)
- atomic_set(&clone->a_refcount, 1);
+ base_acl_init(&clone->a_base);
}
return clone;
}
@@ -279,7 +279,7 @@ static int f2fs_acl_create_masq(struct posix_acl *acl, umode_t *mode_p)
umode_t mode = *mode_p;
int not_equiv = 0;
- /* assert(atomic_read(acl->a_refcount) == 1); */
+ /* assert(base_acl_refcount(&acl->a_base) == 1); */
FOREACH_ACL_ENTRY(pa, acl, pe) {
switch(pa->e_tag) {
diff --git a/fs/inode.c b/fs/inode.c
index 4ccbc21..40c03a7 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -240,14 +240,42 @@ void __destroy_inode(struct inode *inode)
#ifdef CONFIG_FS_POSIX_ACL
if (inode->i_acl && !is_uncached_acl(inode->i_acl))
- posix_acl_release(inode->i_acl);
+ base_acl_put(inode->i_acl);
if (inode->i_default_acl && !is_uncached_acl(inode->i_default_acl))
- posix_acl_release(inode->i_default_acl);
+ base_acl_put(inode->i_default_acl);
#endif
this_cpu_dec(nr_inodes);
}
EXPORT_SYMBOL(__destroy_inode);
+#ifdef CONFIG_FS_POSIX_ACL
+struct base_acl *__get_cached_acl(struct base_acl **p)
+{
+ struct base_acl *base_acl;
+
+ for (;;) {
+ rcu_read_lock();
+ base_acl = rcu_dereference(*p);
+ if (!base_acl || is_uncached_acl(base_acl) ||
+ atomic_inc_not_zero(&base_acl->ba_refcount))
+ break;
+ rcu_read_unlock();
+ cpu_relax();
+ }
+ rcu_read_unlock();
+ return base_acl;
+}
+
+void __forget_cached_acl(struct base_acl **p)
+{
+ struct base_acl *old;
+
+ old = xchg(p, ACL_NOT_CACHED);
+ if (!is_uncached_acl(old))
+ base_acl_put(old);
+}
+#endif
+
static void i_callback(struct rcu_head *head)
{
struct inode *inode = container_of(head, struct inode, i_rcu);
diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c
index bc2693d..6c11909 100644
--- a/fs/jffs2/acl.c
+++ b/fs/jffs2/acl.c
@@ -292,13 +292,15 @@ int jffs2_init_acl_post(struct inode *inode)
int rc;
if (inode->i_default_acl) {
- rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_DEFAULT, inode->i_default_acl);
+ rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_DEFAULT,
+ posix_acl(inode->i_default_acl));
if (rc)
return rc;
}
if (inode->i_acl) {
- rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_ACCESS, inode->i_acl);
+ rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_ACCESS,
+ posix_acl(inode->i_acl));
if (rc)
return rc;
}
diff --git a/fs/namei.c b/fs/namei.c
index 663933e..7a822d0 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -259,25 +259,28 @@ void putname(struct filename *name)
static int check_acl(struct inode *inode, int mask)
{
#ifdef CONFIG_FS_POSIX_ACL
- struct posix_acl *acl;
-
if (mask & MAY_NOT_BLOCK) {
- acl = get_cached_acl_rcu(inode, ACL_TYPE_ACCESS);
- if (!acl)
+ struct base_acl *base_acl;
+
+ base_acl = rcu_dereference(inode->i_acl);
+ if (!base_acl)
return -EAGAIN;
/* no ->get_acl() calls in RCU mode... */
- if (is_uncached_acl(acl))
+ if (is_uncached_acl(base_acl))
return -ECHILD;
- return posix_acl_permission(inode, acl, mask & ~MAY_NOT_BLOCK);
- }
-
- acl = get_acl(inode, ACL_TYPE_ACCESS);
- if (IS_ERR(acl))
- return PTR_ERR(acl);
- if (acl) {
- int error = posix_acl_permission(inode, acl, mask);
- posix_acl_release(acl);
- return error;
+ return posix_acl_permission(inode, posix_acl(base_acl),
+ mask & ~MAY_NOT_BLOCK);
+ } else {
+ struct posix_acl *acl;
+
+ acl = get_acl(inode, ACL_TYPE_ACCESS);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+ if (acl) {
+ int error = posix_acl_permission(inode, acl, mask);
+ posix_acl_release(acl);
+ return error;
+ }
}
#endif
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c
index 720d92f5..2b70944 100644
--- a/fs/nfs/nfs3acl.c
+++ b/fs/nfs/nfs3acl.c
@@ -16,28 +16,28 @@
* caching get_acl results in a race-free way. See fs/posix_acl.c:get_acl()
* for explanations.
*/
-static void nfs3_prepare_get_acl(struct posix_acl **p)
+static void nfs3_prepare_get_acl(struct base_acl **p)
{
- struct posix_acl *sentinel = uncached_acl_sentinel(current);
+ struct base_acl *sentinel = uncached_acl_sentinel(current);
if (cmpxchg(p, ACL_NOT_CACHED, sentinel) != ACL_NOT_CACHED) {
/* Not the first reader or sentinel already in place. */
}
}
-static void nfs3_complete_get_acl(struct posix_acl **p, struct posix_acl *acl)
+static void nfs3_complete_get_acl(struct base_acl **p, struct posix_acl *acl)
{
- struct posix_acl *sentinel = uncached_acl_sentinel(current);
+ struct base_acl *sentinel = uncached_acl_sentinel(current);
/* Only cache the ACL if our sentinel is still in place. */
posix_acl_dup(acl);
- if (cmpxchg(p, sentinel, acl) != sentinel)
+ if (cmpxchg(p, sentinel, &acl->a_base) != sentinel)
posix_acl_release(acl);
}
-static void nfs3_abort_get_acl(struct posix_acl **p)
+static void nfs3_abort_get_acl(struct base_acl **p)
{
- struct posix_acl *sentinel = uncached_acl_sentinel(current);
+ struct base_acl *sentinel = uncached_acl_sentinel(current);
/* Remove our sentinel upon failure. */
cmpxchg(p, sentinel, ACL_NOT_CACHED);
diff --git a/fs/posix_acl.c b/fs/posix_acl.c
index edc452c..1b685a1 100644
--- a/fs/posix_acl.c
+++ b/fs/posix_acl.c
@@ -21,7 +21,7 @@
#include <linux/export.h>
#include <linux/user_namespace.h>
-static struct posix_acl **acl_by_type(struct inode *inode, int type)
+static inline struct base_acl **acl_by_type(struct inode *inode, int type)
{
switch (type) {
case ACL_TYPE_ACCESS:
@@ -33,51 +33,23 @@ static struct posix_acl **acl_by_type(struct inode *inode, int type)
}
}
-struct posix_acl *get_cached_acl(struct inode *inode, int type)
+struct base_acl *get_cached_acl(struct inode *inode, int type)
{
- struct posix_acl **p = acl_by_type(inode, type);
- struct posix_acl *acl;
-
- for (;;) {
- rcu_read_lock();
- acl = rcu_dereference(*p);
- if (!acl || is_uncached_acl(acl) ||
- atomic_inc_not_zero(&acl->a_refcount))
- break;
- rcu_read_unlock();
- cpu_relax();
- }
- rcu_read_unlock();
- return acl;
+ return __get_cached_acl(acl_by_type(inode, type));
}
EXPORT_SYMBOL(get_cached_acl);
-struct posix_acl *get_cached_acl_rcu(struct inode *inode, int type)
-{
- return rcu_dereference(*acl_by_type(inode, type));
-}
-EXPORT_SYMBOL(get_cached_acl_rcu);
-
void set_cached_acl(struct inode *inode, int type, struct posix_acl *acl)
{
- struct posix_acl **p = acl_by_type(inode, type);
- struct posix_acl *old;
+ struct base_acl **p = acl_by_type(inode, type);
+ struct base_acl *old;
- old = xchg(p, posix_acl_dup(acl));
+ old = xchg(p, &posix_acl_dup(acl)->a_base);
if (!is_uncached_acl(old))
- posix_acl_release(old);
+ base_acl_put(old);
}
EXPORT_SYMBOL(set_cached_acl);
-static void __forget_cached_acl(struct posix_acl **p)
-{
- struct posix_acl *old;
-
- old = xchg(p, ACL_NOT_CACHED);
- if (!is_uncached_acl(old))
- posix_acl_release(old);
-}
-
void forget_cached_acl(struct inode *inode, int type)
{
__forget_cached_acl(acl_by_type(inode, type));
@@ -93,25 +65,24 @@ EXPORT_SYMBOL(forget_all_cached_acls);
struct posix_acl *get_acl(struct inode *inode, int type)
{
- void *sentinel;
- struct posix_acl **p;
+ struct base_acl **p = acl_by_type(inode, type);
+ struct base_acl *sentinel, *base_acl;
struct posix_acl *acl;
+ if (!IS_POSIXACL(inode))
+ return NULL;
+
/*
* The sentinel is used to detect when another operation like
* set_cached_acl() or forget_cached_acl() races with get_acl().
* It is guaranteed that is_uncached_acl(sentinel) is true.
*/
- acl = get_cached_acl(inode, type);
- if (!is_uncached_acl(acl))
- return acl;
-
- if (!IS_POSIXACL(inode))
- return NULL;
+ base_acl = __get_cached_acl(p);
+ if (!is_uncached_acl(base_acl))
+ return posix_acl(base_acl);
sentinel = uncached_acl_sentinel(current);
- p = acl_by_type(inode, type);
/*
* If the ACL isn't being read yet, set our sentinel. Otherwise, the
@@ -151,7 +122,7 @@ struct posix_acl *get_acl(struct inode *inode, int type)
* Cache the result, but only if our sentinel is still in place.
*/
posix_acl_dup(acl);
- if (unlikely(cmpxchg(p, sentinel, acl) != sentinel))
+ if (unlikely(cmpxchg(p, sentinel, &acl->a_base) != sentinel))
posix_acl_release(acl);
return acl;
}
@@ -163,7 +134,7 @@ EXPORT_SYMBOL(get_acl);
void
posix_acl_init(struct posix_acl *acl, int count)
{
- atomic_set(&acl->a_refcount, 1);
+ base_acl_init(&acl->a_base);
acl->a_count = count;
}
EXPORT_SYMBOL(posix_acl_init);
@@ -196,7 +167,7 @@ posix_acl_clone(const struct posix_acl *acl, gfp_t flags)
sizeof(struct posix_acl_entry);
clone = kmemdup(acl, size, flags);
if (clone)
- atomic_set(&clone->a_refcount, 1);
+ base_acl_init(&clone->a_base);
}
return clone;
}
@@ -418,7 +389,7 @@ static int posix_acl_create_masq(struct posix_acl *acl, umode_t *mode_p)
umode_t mode = *mode_p;
int not_equiv = 0;
- /* assert(atomic_read(acl->a_refcount) == 1); */
+ /* assert(base_acl_refcount(&acl->a_base) == 1); */
FOREACH_ACL_ENTRY(pa, acl, pe) {
switch(pa->e_tag) {
@@ -473,7 +444,7 @@ static int __posix_acl_chmod_masq(struct posix_acl *acl, umode_t mode)
struct posix_acl_entry *group_obj = NULL, *mask_obj = NULL;
struct posix_acl_entry *pa, *pe;
- /* assert(atomic_read(acl->a_refcount) == 1); */
+ /* assert(base_acl_refcount(&acl->a_base) == 1); */
FOREACH_ACL_ENTRY(pa, acl, pe) {
switch(pa->e_tag) {
diff --git a/fs/richacl.c b/fs/richacl.c
index 0443090..57a4048 100644
--- a/fs/richacl.c
+++ b/fs/richacl.c
@@ -31,7 +31,7 @@ richacl_alloc(int count, gfp_t gfp)
struct richacl *acl = kzalloc(size, gfp);
if (acl) {
- atomic_set(&acl->a_refcount, 1);
+ base_acl_init(&acl->a_base);
acl->a_count = count;
}
return acl;
@@ -50,7 +50,7 @@ richacl_clone(const struct richacl *acl, gfp_t gfp)
if (dup) {
memcpy(dup, acl, size);
- atomic_set(&dup->a_refcount, 1);
+ base_acl_init(&dup->a_base);
}
return dup;
}
diff --git a/include/linux/fs.h b/include/linux/fs.h
index bb36561..917dadb 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -582,17 +582,21 @@ static inline void mapping_allow_writable(struct address_space *mapping)
#define i_size_ordered_init(inode) do { } while (0)
#endif
+struct base_acl {
+ atomic_t ba_refcount;
+ struct rcu_head ba_rcu;
+};
struct posix_acl;
#define ACL_NOT_CACHED ((void *)(-1))
-static inline struct posix_acl *
+static inline struct base_acl *
uncached_acl_sentinel(struct task_struct *task)
{
return (void *)task + 1;
}
static inline bool
-is_uncached_acl(struct posix_acl *acl)
+is_uncached_acl(struct base_acl *acl)
{
return (long)acl & 1;
}
@@ -613,9 +617,9 @@ struct inode {
kgid_t i_gid;
unsigned int i_flags;
-#ifdef CONFIG_FS_POSIX_ACL
- struct posix_acl *i_acl;
- struct posix_acl *i_default_acl;
+#if defined(CONFIG_FS_POSIX_ACL)
+ struct base_acl *i_acl;
+ struct base_acl *i_default_acl;
#endif
const struct inode_operations *i_op;
@@ -3193,4 +3197,29 @@ static inline bool dir_relax_shared(struct inode *inode)
extern bool path_noexec(const struct path *path);
extern void inode_nohighmem(struct inode *inode);
+static inline void base_acl_get(struct base_acl *acl)
+{
+ if (acl)
+ atomic_inc(&acl->ba_refcount);
+}
+
+static inline void base_acl_put(struct base_acl *acl)
+{
+ if (acl && atomic_dec_and_test(&acl->ba_refcount))
+ kfree_rcu(acl, ba_rcu);
+}
+
+static inline void base_acl_init(struct base_acl *acl)
+{
+ atomic_set(&acl->ba_refcount, 1);
+}
+
+static inline int base_acl_refcount(struct base_acl *acl)
+{
+ return atomic_read(&acl->ba_refcount);
+}
+
+extern struct base_acl *__get_cached_acl(struct base_acl **);
+extern void __forget_cached_acl(struct base_acl **);
+
#endif /* _LINUX_FS_H */
diff --git a/include/linux/posix_acl.h b/include/linux/posix_acl.h
index c818772..daf84fa 100644
--- a/include/linux/posix_acl.h
+++ b/include/linux/posix_acl.h
@@ -43,8 +43,7 @@ struct posix_acl_entry {
};
struct posix_acl {
- atomic_t a_refcount;
- struct rcu_head a_rcu;
+ struct base_acl a_base; /* must be first, see posix_acl_release() */
unsigned int a_count;
struct posix_acl_entry a_entries[0];
};
@@ -59,8 +58,7 @@ struct posix_acl {
static inline struct posix_acl *
posix_acl_dup(struct posix_acl *acl)
{
- if (acl)
- atomic_inc(&acl->a_refcount);
+ base_acl_get(&acl->a_base);
return acl;
}
@@ -70,10 +68,16 @@ posix_acl_dup(struct posix_acl *acl)
static inline void
posix_acl_release(struct posix_acl *acl)
{
- if (acl && atomic_dec_and_test(&acl->a_refcount))
- kfree_rcu(acl, a_rcu);
+ BUILD_BUG_ON(offsetof(struct posix_acl, a_base) != 0);
+ base_acl_put(&acl->a_base);
}
+static inline struct posix_acl *
+posix_acl(struct base_acl *base_acl)
+{
+ BUILD_BUG_ON(offsetof(struct posix_acl, a_base) != 0);
+ return container_of(base_acl, struct posix_acl, a_base);
+}
/* posix_acl.c */
@@ -97,8 +101,7 @@ extern int posix_acl_create(struct inode *, umode_t *, struct posix_acl **,
extern int simple_set_acl(struct inode *, struct posix_acl *, int);
extern int simple_acl_create(struct inode *, struct inode *);
-struct posix_acl *get_cached_acl(struct inode *inode, int type);
-struct posix_acl *get_cached_acl_rcu(struct inode *inode, int type);
+struct base_acl *get_cached_acl(struct inode *inode, int type);
void set_cached_acl(struct inode *inode, int type, struct posix_acl *acl);
void forget_cached_acl(struct inode *inode, int type);
void forget_all_cached_acls(struct inode *inode);
diff --git a/include/linux/richacl.h b/include/linux/richacl.h
index 700888b..d535206 100644
--- a/include/linux/richacl.h
+++ b/include/linux/richacl.h
@@ -31,7 +31,7 @@ struct richace {
};
struct richacl {
- atomic_t a_refcount;
+ struct base_acl a_base; /* must be first, see richacl_put() */
unsigned int a_owner_mask;
unsigned int a_group_mask;
unsigned int a_other_mask;
@@ -56,8 +56,7 @@ struct richacl {
static inline struct richacl *
richacl_get(struct richacl *acl)
{
- if (acl)
- atomic_inc(&acl->a_refcount);
+ base_acl_get(&acl->a_base);
return acl;
}
@@ -67,8 +66,8 @@ richacl_get(struct richacl *acl)
static inline void
richacl_put(struct richacl *acl)
{
- if (acl && atomic_dec_and_test(&acl->a_refcount))
- kfree(acl);
+ BUILD_BUG_ON(offsetof(struct richacl, a_base) != 0);
+ base_acl_put(&acl->a_base);
}
/**
--
2.5.5
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2016-07-25 16:20 +0200 |
| Subject | [PATCH v24 16/22] richacl: Automatic Inheritance |
| Message-ID | <rYOTF-5Bn-53@gated-at.bofh.it> |
| In reply to | #1449507 |
Automatic Inheritance (AI) allows changes to the acl of a directory to
propagate down to children.
This is mostly implemented in user space: when a process changes the
permissions of a directory and Automatic Inheritance is enabled for that
directory, the process must propagate those changes to all children,
recursively.
The kernel enables this by keeping track of which permissions have been
inherited at create time. In addition, it makes sure that permission
propagation is turned off when the permissions are set explicitly (for
example, upon create or chmod).
Automatic Inheritance works as follows:
- When the RICHACL_AUTO_INHERIT flag in the acl of a file or directory
is not set, the file or directory is not affected by AI.
- When the RICHACL_AUTO_INHERIT flag in the acl of a directory is set
and a file or subdirectory is created in that directory, the
inherited acl will have the RICHACL_AUTO_INHERIT flag set, and all
inherited aces will have the RICHACE_INHERITED_ACE flag set. This
allows user space to distinguish between aces which have been
inherited and aces which have been explicitly added.
- When the RICHACL_PROTECTED acl flag in the acl of a file or directory
is set, AI will not modify the acl. This does not affect propagation
of permissions from the file to its children (if the file is a
directory).
Linux does not have a way of creating files or directories without setting the
file permission bits, so all files created inside a directory with
RICHACL_AUTO_INHERIT set will have the RICHACL_PROTECTED flag set. This
effectively disables Automatic Inheritance.
Protocols which support creating files without specifying permissions can
explicitly clear the RICHACL_PROTECTED flag after creating a file and reset the
file masks to "undo" applying the create mode; see richacl_compute_max_masks().
They should set the RICHACL_DEFAULTED flag. (A mechanism that would allow to
indicate to the kernel to ignore the create mode in the first place when there
are inherited permissions would be nice to have.)
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
---
fs/richacl.c | 20 +++++++++++++++++++-
include/linux/richacl.h | 12 ++++++++++++
include/uapi/linux/richacl.h | 11 ++++++++++-
3 files changed, 41 insertions(+), 2 deletions(-)
diff --git a/fs/richacl.c b/fs/richacl.c
index 8051181..4edce8b 100644
--- a/fs/richacl.c
+++ b/fs/richacl.c
@@ -567,7 +567,8 @@ __richacl_chmod(struct richacl *acl, umode_t mode)
acl->a_group_mask == group_mask &&
acl->a_other_mask == other_mask &&
(acl->a_flags & RICHACL_MASKED) &&
- (acl->a_flags & RICHACL_WRITE_THROUGH))
+ (acl->a_flags & RICHACL_WRITE_THROUGH) &&
+ (!richacl_is_auto_inherit(acl) || richacl_is_protected(acl)))
return acl;
clone = richacl_clone(acl, GFP_KERNEL);
@@ -579,6 +580,8 @@ __richacl_chmod(struct richacl *acl, umode_t mode)
clone->a_owner_mask = owner_mask;
clone->a_group_mask = group_mask;
clone->a_other_mask = other_mask;
+ if (richacl_is_auto_inherit(clone))
+ clone->a_flags |= RICHACL_PROTECTED;
return clone;
}
@@ -794,6 +797,14 @@ richacl_inherit(const struct richacl *dir_acl, int isdir)
ace++;
}
}
+ if (richacl_is_auto_inherit(dir_acl)) {
+ acl->a_flags = RICHACL_AUTO_INHERIT;
+ richacl_for_each_entry(ace, acl)
+ ace->e_flags |= RICHACE_INHERITED_ACE;
+ } else {
+ richacl_for_each_entry(ace, acl)
+ ace->e_flags &= ~RICHACE_INHERITED_ACE;
+ }
return acl;
}
@@ -822,6 +833,13 @@ richacl_inherit_inode(const struct richacl *dir_acl, umode_t *mode_p)
richacl_put(acl);
acl = NULL;
} else {
+ /*
+ * We need to set RICHACL_PROTECTED because we are
+ * doing an implicit chmod
+ */
+ if (richacl_is_auto_inherit(acl))
+ acl->a_flags |= RICHACL_PROTECTED;
+
richacl_compute_max_masks(acl);
/*
* Ensure that the acl will not grant any permissions
diff --git a/include/linux/richacl.h b/include/linux/richacl.h
index 6354ef0..737513b 100644
--- a/include/linux/richacl.h
+++ b/include/linux/richacl.h
@@ -81,6 +81,18 @@ extern void set_cached_richacl(struct inode *, struct richacl *);
extern void forget_cached_richacl(struct inode *);
extern struct richacl *get_richacl(struct inode *);
+static inline int
+richacl_is_auto_inherit(const struct richacl *acl)
+{
+ return acl->a_flags & RICHACL_AUTO_INHERIT;
+}
+
+static inline int
+richacl_is_protected(const struct richacl *acl)
+{
+ return acl->a_flags & RICHACL_PROTECTED;
+}
+
/**
* richace_is_owner - check if @ace is an OWNER@ entry
*/
diff --git a/include/uapi/linux/richacl.h b/include/uapi/linux/richacl.h
index 1ed48ac..8849a53 100644
--- a/include/uapi/linux/richacl.h
+++ b/include/uapi/linux/richacl.h
@@ -18,6 +18,9 @@
#define __UAPI_RICHACL_H
/* a_flags values */
+#define RICHACL_AUTO_INHERIT 0x01
+#define RICHACL_PROTECTED 0x02
+#define RICHACL_DEFAULTED 0x04
#define RICHACL_WRITE_THROUGH 0x40
#define RICHACL_MASKED 0x80
@@ -31,6 +34,7 @@
#define RICHACE_NO_PROPAGATE_INHERIT_ACE 0x0004
#define RICHACE_INHERIT_ONLY_ACE 0x0008
#define RICHACE_IDENTIFIER_GROUP 0x0040
+#define RICHACE_INHERITED_ACE 0x0080
#define RICHACE_SPECIAL_WHO 0x4000
/* e_mask bitflags */
@@ -60,6 +64,9 @@
#define RICHACE_EVERYONE_SPECIAL_ID 2
#define RICHACL_VALID_FLAGS ( \
+ RICHACL_AUTO_INHERIT | \
+ RICHACL_PROTECTED | \
+ RICHACL_DEFAULTED | \
RICHACL_WRITE_THROUGH | \
RICHACL_MASKED )
@@ -69,13 +76,15 @@
RICHACE_NO_PROPAGATE_INHERIT_ACE | \
RICHACE_INHERIT_ONLY_ACE | \
RICHACE_IDENTIFIER_GROUP | \
+ RICHACE_INHERITED_ACE | \
RICHACE_SPECIAL_WHO )
#define RICHACE_INHERITANCE_FLAGS ( \
RICHACE_FILE_INHERIT_ACE | \
RICHACE_DIRECTORY_INHERIT_ACE | \
RICHACE_NO_PROPAGATE_INHERIT_ACE | \
- RICHACE_INHERIT_ONLY_ACE )
+ RICHACE_INHERIT_ONLY_ACE | \
+ RICHACE_INHERITED_ACE )
/* Valid RICHACE_* flags for directories and non-directories */
#define RICHACE_VALID_MASK ( \
--
2.5.5
[toc] | [prev] | [standalone]
Page 2 of 2 — ← Prev page 1 [2]
Back to top | Article view | linux.kernel
csiph-web