Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1434569 > unrolled thread
| Started by | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| First post | 2016-06-30 16:00 +0200 |
| Last post | 2016-06-30 17:00 +0200 |
| Articles | 20 on this page of 44 — 6 participants |
Back to article view | Back to linux.kernel
[PATCH v23 00/22] Richacls (Core and Ext4) Andreas Gruenbacher <agruenba@redhat.com> - 2016-06-30 16:00 +0200
[PATCH v23 14/22] richacl: Update the file masks in chmod() Andreas Gruenbacher <agruenba@redhat.com> - 2016-06-30 16:00 +0200
Re: [PATCH v23 14/22] richacl: Update the file masks in chmod() Jeff Layton <jlayton@redhat.com> - 2016-07-12 13:40 +0200
[PATCH v23 15/22] richacl: Check if an acl is equivalent to a file mode Andreas Gruenbacher <agruenba@redhat.com> - 2016-06-30 16:00 +0200
Re: [PATCH v23 15/22] richacl: Check if an acl is equivalent to a file mode Jeff Layton <jlayton@redhat.com> - 2016-07-12 13:40 +0200
[PATCH v23 08/22] richacl: Compute maximum file masks from an acl Andreas Gruenbacher <agruenba@redhat.com> - 2016-06-30 16:00 +0200
RE: [PATCH v23 08/22] richacl: Compute maximum file masks from an acl "Frank Filz" <ffilzlnx@mindspring.com> - 2016-07-05 19:10 +0200
Re: [PATCH v23 08/22] richacl: Compute maximum file masks from an acl Andreas Gruenbacher <agruenba@redhat.com> - 2016-07-13 14:40 +0200
RE: [PATCH v23 08/22] richacl: Compute maximum file masks from an acl "Frank Filz" <ffilzlnx@mindspring.com> - 2016-07-13 21:50 +0200
[PATCH v23 16/22] richacl: Create-time inheritance Andreas Gruenbacher <agruenba@redhat.com> - 2016-06-30 16:00 +0200
Re: [PATCH v23 16/22] richacl: Create-time inheritance Jeff Layton <jlayton@redhat.com> - 2016-07-12 13:50 +0200
[PATCH v23 06/22] richacl: In-memory representation and helper functions Andreas Gruenbacher <agruenba@redhat.com> - 2016-06-30 16:00 +0200
Re: [PATCH v23 06/22] richacl: In-memory representation and helper functions Jeff Layton <jlayton@redhat.com> - 2016-07-05 13:40 +0200
Re: [PATCH v23 06/22] richacl: In-memory representation and helper functions Andreas Gruenbacher <agruenba@redhat.com> - 2016-07-11 12:20 +0200
[PATCH v23 22/22] ext4: Add richacl feature flag Andreas Gruenbacher <agruenba@redhat.com> - 2016-06-30 16:00 +0200
[PATCH v23 21/22] ext4: Add richacl support Andreas Gruenbacher <agruenba@redhat.com> - 2016-06-30 16:00 +0200
[PATCH v23 19/22] richacl: Add richacl xattr handler Andreas Gruenbacher <agruenba@redhat.com> - 2016-06-30 16:00 +0200
Re: [PATCH v23 19/22] richacl: Add richacl xattr handler Jeff Layton <jlayton@redhat.com> - 2016-07-12 14:20 +0200
[PATCH v23 12/22] vfs: Add get_richacl and set_richacl inode operations Andreas Gruenbacher <agruenba@redhat.com> - 2016-06-30 16:00 +0200
Re: [PATCH v23 12/22] vfs: Add get_richacl and set_richacl inode operations Jeff Layton <jlayton@redhat.com> - 2016-07-06 20:40 +0200
[PATCH v23 09/22] richacl: Permission check algorithm Andreas Gruenbacher <agruenba@redhat.com> - 2016-06-30 16:00 +0200
Re: [PATCH v23 09/22] richacl: Permission check algorithm Jeff Layton <jlayton@redhat.com> - 2016-07-05 17:00 +0200
Re: [PATCH v23 09/22] richacl: Permission check algorithm Andreas Gruenbacher <agruenba@redhat.com> - 2016-07-11 15:30 +0200
[PATCH v23 17/22] richacl: Automatic Inheritance Andreas Gruenbacher <agruenba@redhat.com> - 2016-06-30 16:00 +0200
Re: [PATCH v23 17/22] richacl: Automatic Inheritance Jeff Layton <jlayton@redhat.com> - 2016-07-12 14:00 +0200
Re: [PATCH v23 17/22] richacl: Automatic Inheritance "J. Bruce Fields" <bfields@fieldses.org> - 2016-07-12 21:20 +0200
Re: [PATCH v23 17/22] richacl: Automatic Inheritance Andreas Gruenbacher <agruenba@redhat.com> - 2016-07-12 22:30 +0200
[PATCH v23 20/22] vfs: Add richacl permission checking Andreas Gruenbacher <agruenba@redhat.com> - 2016-06-30 16:00 +0200
Re: [PATCH v23 20/22] vfs: Add richacl permission checking Jeff Layton <jlayton@redhat.com> - 2016-07-12 14:20 +0200
Re: [PATCH v23 20/22] vfs: Add richacl permission checking Andreas Gruenbacher <agruenba@redhat.com> - 2016-07-14 23:00 +0200
[PATCH v23 13/22] vfs: Cache richacl in struct inode Andreas Gruenbacher <agruenba@redhat.com> - 2016-06-30 16:00 +0200
Re: [PATCH v23 13/22] vfs: Cache richacl in struct inode Jeff Layton <jlayton@redhat.com> - 2016-07-06 21:00 +0200
Re: [PATCH v23 13/22] vfs: Cache richacl in struct inode David Howells <dhowells@redhat.com> - 2016-07-07 16:20 +0200
Re: [PATCH v23 13/22] vfs: Cache richacl in struct inode Andreas Gruenbacher <agruenba@redhat.com> - 2016-07-14 22:10 +0200
[PATCH v23 03/22] vfs: Add MAY_DELETE_SELF and MAY_DELETE_CHILD permission flags Andreas Gruenbacher <agruenba@redhat.com> - 2016-06-30 16:00 +0200
Re: [PATCH v23 03/22] vfs: Add MAY_DELETE_SELF and MAY_DELETE_CHILD permission flags Jeff Layton <jlayton@redhat.com> - 2016-07-05 13:10 +0200
[PATCH v23 18/22] richacl: xattr mapping functions Andreas Gruenbacher <agruenba@redhat.com> - 2016-06-30 16:00 +0200
Re: [PATCH v23 18/22] richacl: xattr mapping functions Jeff Layton <jlayton@redhat.com> - 2016-07-12 14:10 +0200
Re: [PATCH v23 18/22] richacl: xattr mapping functions Andreas Gruenbacher <agruenba@redhat.com> - 2016-07-14 22:40 +0200
[PATCH v23 11/22] vfs: Cache base_acl objects in inodes Andreas Gruenbacher <agruenba@redhat.com> - 2016-06-30 16:00 +0200
Re: [PATCH v23 11/22] vfs: Cache base_acl objects in inodes Jeff Layton <jlayton@redhat.com> - 2016-07-05 18:00 +0200
[PATCH v23 02/22] vfs: Add MAY_CREATE_FILE and MAY_CREATE_DIR permission flags Andreas Gruenbacher <agruenba@redhat.com> - 2016-06-30 16:10 +0200
Re: [PATCH v23 02/22] vfs: Add MAY_CREATE_FILE and MAY_CREATE_DIR permission flags Jeff Layton <jlayton@redhat.com> - 2016-07-05 13:20 +0200
Re: [PATCH v23 00/22] Richacls (Core and Ext4) Volker Lendecke <Volker.Lendecke@SerNet.DE> - 2016-06-30 17:00 +0200
Page 1 of 3 [1] 2 3 Next page →
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2016-06-30 16:00 +0200 |
| Subject | [PATCH v23 00/22] Richacls (Core and Ext4) |
| Message-ID | <rPKFz-1Pr-3@gated-at.bofh.it> |
Here is another update of the richacl patches. Changes since the last posting (https://lwn.net/Articles/689151/): * Rebase on top of 4.7-rc5+ because of commit 999653786d "nfsd: check permissions when setting ACLs". * Introduce set_richacl() similar to set_posix_acl() and use it in nfsd to avoid going through the richacl xattr representation. The complete patch queue is available here: git://git.kernel.org/pub/scm/linux/kernel/git/agruen/linux-richacl.git \ richacl-2016-06-30 The richacl user-space utilitites, man pages, and test suite are available here: https://github.com/andreas-gruenbacher/richacl Changes to other user-space packages for richacl: https://github.com/andreas-gruenbacher/coreutils https://github.com/andreas-gruenbacher/e2fsprogs https://github.com/andreas-gruenbacher/samba https://github.com/andreas-gruenbacher/xfsprogs-dev https://github.com/andreas-gruenbacher/nfs-utils Please see the richacl homepage for more information: http://www.bestbits.at/richacl/ What more needs to be done to get this initial set of patches merged? Thanks, Andreas Andreas Gruenbacher (20): vfs: Add IS_ACL() and IS_RICHACL() tests vfs: Add MAY_CREATE_FILE and MAY_CREATE_DIR permission flags vfs: Add MAY_DELETE_SELF and MAY_DELETE_CHILD permission flags vfs: Make the inode passed to inode_change_ok non-const vfs: Add permission flags for setting file attributes richacl: In-memory representation and helper functions richacl: Permission mapping functions richacl: Compute maximum file masks from an acl richacl: Permission check algorithm posix_acl: Improve xattr fixup code vfs: Cache base_acl objects in inodes vfs: Add get_richacl and set_richacl inode operations vfs: Cache richacl in struct inode richacl: Update the file masks in chmod() richacl: Check if an acl is equivalent to a file mode richacl: Create-time inheritance richacl: Automatic Inheritance richacl: xattr mapping functions richacl: Add richacl xattr handler vfs: Add richacl permission checking Aneesh Kumar K.V (2): ext4: Add richacl support ext4: Add richacl feature flag drivers/staging/lustre/lustre/llite/llite_lib.c | 2 +- fs/9p/acl.c | 8 +- fs/Kconfig | 3 + fs/Makefile | 1 + fs/attr.c | 81 ++- fs/ext4/Kconfig | 11 + fs/ext4/Makefile | 1 + fs/ext4/ext4.h | 6 +- fs/ext4/file.c | 3 + fs/ext4/ialloc.c | 11 +- fs/ext4/inode.c | 5 +- fs/ext4/namei.c | 5 + fs/ext4/richacl.c | 134 ++++ fs/ext4/richacl.h | 40 ++ fs/ext4/super.c | 49 +- fs/ext4/xattr.c | 7 + fs/f2fs/acl.c | 4 +- fs/inode.c | 43 +- fs/jffs2/acl.c | 6 +- fs/namei.c | 152 +++- fs/nfs/nfs3acl.c | 14 +- fs/posix_acl.c | 69 +- fs/richacl.c | 915 ++++++++++++++++++++++++ fs/richacl_xattr.c | 222 ++++++ fs/xattr.c | 29 +- include/linux/acl.h | 15 + include/linux/fs.h | 67 +- include/linux/posix_acl.h | 21 +- include/linux/richacl.h | 211 ++++++ include/linux/richacl_xattr.h | 31 + include/uapi/linux/Kbuild | 2 + include/uapi/linux/fs.h | 3 +- include/uapi/linux/richacl.h | 152 ++++ include/uapi/linux/richacl_xattr.h | 44 ++ include/uapi/linux/xattr.h | 2 + 35 files changed, 2209 insertions(+), 160 deletions(-) create mode 100644 fs/ext4/richacl.c create mode 100644 fs/ext4/richacl.h create mode 100644 fs/richacl.c create mode 100644 fs/richacl_xattr.c create mode 100644 include/linux/acl.h create mode 100644 include/linux/richacl.h create mode 100644 include/linux/richacl_xattr.h create mode 100644 include/uapi/linux/richacl.h create mode 100644 include/uapi/linux/richacl_xattr.h -- 2.5.5
[toc] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2016-06-30 16:00 +0200 |
| Subject | [PATCH v23 14/22] richacl: Update the file masks in chmod() |
| Message-ID | <rPKFA-1Pr-21@gated-at.bofh.it> |
| In reply to | #1434569 |
Doing a chmod() sets the file mode, which includes the file permission
bits. When a file has a richacl, the permissions that the richacl
grants need to be limited to what the new file permission bits allow.
This is done by setting the file masks in the richacl to what the file
permission bits map to. The richacl access check algorithm takes the
file masks into account, which ensures that the richacl cannot grant too
many permissions.
It is possible to explicitly add permissions to the file masks which go
beyond what the file permission bits can grant (like the
RICHACE_WRITE_ACL permission). The POSIX.1 standard calls this an
alternate file access control mechanism. A subsequent chmod() would
ensure that those permissions are disabled again.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Reviewed-by: J. Bruce Fields <bfields@redhat.com>
---
fs/richacl.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/richacl.h | 1 +
2 files changed, 72 insertions(+)
diff --git a/fs/richacl.c b/fs/richacl.c
index b2a03c1..ba110a6 100644
--- a/fs/richacl.c
+++ b/fs/richacl.c
@@ -547,3 +547,74 @@ out:
return denied ? -EACCES : 0;
}
EXPORT_SYMBOL_GPL(richacl_permission);
+
+/**
+ * __richacl_chmod - update the file masks to reflect the new mode
+ * @acl: access control list
+ * @mode: new file permission bits including the file type
+ *
+ * Return a copy of @acl where the file masks have been replaced by the file
+ * masks corresponding to the file permission bits in @mode, or returns @acl
+ * itself if the file masks are already up to date. Takes over a reference
+ * to @acl.
+ */
+static struct richacl *
+__richacl_chmod(struct richacl *acl, umode_t mode)
+{
+ unsigned int x = S_ISDIR(mode) ? 0 : RICHACE_DELETE_CHILD;
+ unsigned int owner_mask, group_mask, other_mask;
+ struct richacl *clone;
+
+ owner_mask = richacl_mode_to_mask(mode >> 6) & ~x;
+ group_mask = richacl_mode_to_mask(mode >> 3) & ~x;
+ other_mask = richacl_mode_to_mask(mode) & ~x;
+
+ if (acl->a_owner_mask == owner_mask &&
+ acl->a_group_mask == group_mask &&
+ acl->a_other_mask == other_mask &&
+ (acl->a_flags & RICHACL_MASKED) &&
+ (acl->a_flags & RICHACL_WRITE_THROUGH))
+ return acl;
+
+ clone = richacl_clone(acl, GFP_KERNEL);
+ richacl_put(acl);
+ if (!clone)
+ return ERR_PTR(-ENOMEM);
+
+ clone->a_flags |= (RICHACL_WRITE_THROUGH | RICHACL_MASKED);
+ clone->a_owner_mask = owner_mask;
+ clone->a_group_mask = group_mask;
+ clone->a_other_mask = other_mask;
+
+ return clone;
+}
+
+/**
+ * richacl_chmod - filesystem chmod helper
+ * @inode: inode whose file permission bits to change
+ * @mode: new file permission bits including the file type
+ *
+ * Helper for filesystems to use to perform a chmod on the richacl of an inode.
+ */
+int
+richacl_chmod(struct inode *inode, umode_t mode)
+{
+ struct richacl *acl;
+ int retval;
+
+ if (S_ISLNK(mode))
+ return -EOPNOTSUPP;
+ if (!inode->i_op->set_richacl)
+ return -EOPNOTSUPP;
+ acl = get_richacl(inode);
+ if (IS_ERR_OR_NULL(acl))
+ return PTR_ERR(acl);
+ acl = __richacl_chmod(acl, mode);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+ retval = inode->i_op->set_richacl(inode, acl);
+ richacl_put(acl);
+
+ return retval;
+}
+EXPORT_SYMBOL(richacl_chmod);
diff --git a/include/linux/richacl.h b/include/linux/richacl.h
index 3e05c94..db82fab 100644
--- a/include/linux/richacl.h
+++ b/include/linux/richacl.h
@@ -190,5 +190,6 @@ extern unsigned int richacl_mode_to_mask(umode_t);
extern unsigned int richacl_want_to_mask(unsigned int);
extern void richacl_compute_max_masks(struct richacl *);
extern int richacl_permission(struct inode *, const struct richacl *, int);
+extern int richacl_chmod(struct inode *, umode_t);
#endif /* __RICHACL_H */
--
2.5.5
[toc] | [prev] | [next] | [standalone]
| From | Jeff Layton <jlayton@redhat.com> |
|---|---|
| Date | 2016-07-12 13:40 +0200 |
| Subject | Re: [PATCH v23 14/22] richacl: Update the file masks in chmod() |
| Message-ID | <rU4cF-4gU-19@gated-at.bofh.it> |
| In reply to | #1434570 |
On Thu, 2016-06-30 at 15:47 +0200, Andreas Gruenbacher wrote:
> Doing a chmod() sets the file mode, which includes the file permission
> bits. When a file has a richacl, the permissions that the richacl
> grants need to be limited to what the new file permission bits allow.
>
> This is done by setting the file masks in the richacl to what the file
> permission bits map to. The richacl access check algorithm takes the
> file masks into account, which ensures that the richacl cannot grant too
> many permissions.
>
> It is possible to explicitly add permissions to the file masks which go
> beyond what the file permission bits can grant (like the
> RICHACE_WRITE_ACL permission). The POSIX.1 standard calls this an
> alternate file access control mechanism. A subsequent chmod() would
> ensure that those permissions are disabled again.
>
> Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
> Reviewed-by: J. Bruce Fields <bfields@redhat.com>
> ---
> fs/richacl.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++
> include/linux/richacl.h | 1 +
> 2 files changed, 72 insertions(+)
>
> diff --git a/fs/richacl.c b/fs/richacl.c
> index b2a03c1..ba110a6 100644
> --- a/fs/richacl.c
> +++ b/fs/richacl.c
> @@ -547,3 +547,74 @@ out:
> return denied ? -EACCES : 0;
> }
> EXPORT_SYMBOL_GPL(richacl_permission);
> +
> +/**
> + * __richacl_chmod - update the file masks to reflect the new mode
> + * @acl: access control list
> + * @mode: new file permission bits including the file type
> + *
> + * Return a copy of @acl where the file masks have been replaced by the file
> + * masks corresponding to the file permission bits in @mode, or returns @acl
> + * itself if the file masks are already up to date. Takes over a reference
> + * to @acl.
> + */
> +static struct richacl *
> +__richacl_chmod(struct richacl *acl, umode_t mode)
> +{
> + unsigned int x = S_ISDIR(mode) ? 0 : RICHACE_DELETE_CHILD;
> + unsigned int owner_mask, group_mask, other_mask;
> + struct richacl *clone;
> +
> + owner_mask = richacl_mode_to_mask(mode >> 6) & ~x;
> + group_mask = richacl_mode_to_mask(mode >> 3) & ~x;
> + other_mask = richacl_mode_to_mask(mode) & ~x;
> +
> + if (acl->a_owner_mask == owner_mask &&
> + acl->a_group_mask == group_mask &&
> + acl->a_other_mask == other_mask &&
> + (acl->a_flags & RICHACL_MASKED) &&
> + (acl->a_flags & RICHACL_WRITE_THROUGH))
> + return acl;
> +
> + clone = richacl_clone(acl, GFP_KERNEL);
> + richacl_put(acl);
> + if (!clone)
> + return ERR_PTR(-ENOMEM);
> +
> + clone->a_flags |= (RICHACL_WRITE_THROUGH | RICHACL_MASKED);
> + clone->a_owner_mask = owner_mask;
> + clone->a_group_mask = group_mask;
> + clone->a_other_mask = other_mask;
> +
> + return clone;
> +}
> +
> +/**
> + * richacl_chmod - filesystem chmod helper
> + * @inode: inode whose file permission bits to change
> + * @mode: new file permission bits including the file type
> + *
> + * Helper for filesystems to use to perform a chmod on the richacl of an inode.
> + */
> +int
> +richacl_chmod(struct inode *inode, umode_t mode)
> +{
> + struct richacl *acl;
> + int retval;
> +
> + if (S_ISLNK(mode))
> + return -EOPNOTSUPP;
> + if (!inode->i_op->set_richacl)
> + return -EOPNOTSUPP;
> + acl = get_richacl(inode);
> + if (IS_ERR_OR_NULL(acl))
> + return PTR_ERR(acl);
> + acl = __richacl_chmod(acl, mode);
> + if (IS_ERR(acl))
> + return PTR_ERR(acl);
> + retval = inode->i_op->set_richacl(inode, acl);
> + richacl_put(acl);
> +
> + return retval;
> +}
> +EXPORT_SYMBOL(richacl_chmod);
> diff --git a/include/linux/richacl.h b/include/linux/richacl.h
> index 3e05c94..db82fab 100644
> --- a/include/linux/richacl.h
> +++ b/include/linux/richacl.h
> @@ -190,5 +190,6 @@ extern unsigned int richacl_mode_to_mask(umode_t);
> extern unsigned int richacl_want_to_mask(unsigned int);
> extern void richacl_compute_max_masks(struct richacl *);
> extern int richacl_permission(struct inode *, const struct richacl *, int);
> +extern int richacl_chmod(struct inode *, umode_t);
>
> #endif /* __RICHACL_H */
Acked-by: Jeff Layton <jlayton@redhat.com>
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2016-06-30 16:00 +0200 |
| Subject | [PATCH v23 15/22] richacl: Check if an acl is equivalent to a file mode |
| Message-ID | <rPKFA-1Pr-13@gated-at.bofh.it> |
| In reply to | #1434569 |
ACLs are considered equivalent to file modes if they only consist of
owner@, group@, and everyone@ entries, the owner@ permissions do not
depend on whether the owner is a member in the owning group, and no
inheritance flags are set. This test is used to avoid storing richacls
if the acl can be computed from the file permission bits.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Reviewed-by: J. Bruce Fields <bfields@redhat.com>
---
fs/richacl.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/richacl.h | 1 +
2 files changed, 105 insertions(+)
diff --git a/fs/richacl.c b/fs/richacl.c
index ba110a6..e8a383b 100644
--- a/fs/richacl.c
+++ b/fs/richacl.c
@@ -618,3 +618,107 @@ richacl_chmod(struct inode *inode, umode_t mode)
return retval;
}
EXPORT_SYMBOL(richacl_chmod);
+
+/**
+ * richacl_equiv_mode - compute the mode equivalent of @acl
+ *
+ * An acl is considered equivalent to a file mode if it only consists of
+ * owner@, group@, and everyone@ entries and the owner@ permissions do not
+ * depend on whether the owner is a member in the owning group.
+ */
+int
+richacl_equiv_mode(const struct richacl *acl, umode_t *mode_p)
+{
+ umode_t mode = *mode_p;
+
+ /*
+ * The RICHACE_DELETE_CHILD flag is meaningless for non-directories, so
+ * we ignore it.
+ */
+ unsigned int x = S_ISDIR(mode) ? 0 : RICHACE_DELETE_CHILD;
+ struct {
+ unsigned int allowed;
+ unsigned int defined; /* allowed or denied */
+ } owner = {
+ .defined = RICHACE_POSIX_ALWAYS_ALLOWED |
+ RICHACE_POSIX_OWNER_ALLOWED | x,
+ }, group = {
+ .defined = RICHACE_POSIX_ALWAYS_ALLOWED | x,
+ }, everyone = {
+ .defined = RICHACE_POSIX_ALWAYS_ALLOWED | x,
+ };
+ const struct richace *ace;
+
+ if (acl->a_flags & ~(RICHACL_WRITE_THROUGH | RICHACL_MASKED))
+ return -1;
+
+ richacl_for_each_entry(ace, acl) {
+ if (ace->e_flags & ~RICHACE_SPECIAL_WHO)
+ return -1;
+
+ if (richace_is_owner(ace) || richace_is_everyone(ace)) {
+ x = ace->e_mask & ~owner.defined;
+ if (richace_is_allow(ace)) {
+ unsigned int group_denied =
+ group.defined & ~group.allowed;
+
+ if (x & group_denied)
+ return -1;
+ owner.allowed |= x;
+ } else /* if (richace_is_deny(ace)) */ {
+ if (x & group.allowed)
+ return -1;
+ }
+ owner.defined |= x;
+
+ if (richace_is_everyone(ace)) {
+ x = ace->e_mask;
+ if (richace_is_allow(ace)) {
+ group.allowed |=
+ x & ~group.defined;
+ everyone.allowed |=
+ x & ~everyone.defined;
+ }
+ group.defined |= x;
+ everyone.defined |= x;
+ }
+ } else if (richace_is_group(ace)) {
+ x = ace->e_mask & ~group.defined;
+ if (richace_is_allow(ace))
+ group.allowed |= x;
+ group.defined |= x;
+ } else
+ return -1;
+ }
+
+ if (group.allowed & ~owner.defined)
+ return -1;
+
+ if (acl->a_flags & RICHACL_MASKED) {
+ if (acl->a_flags & RICHACL_WRITE_THROUGH) {
+ owner.allowed = acl->a_owner_mask;
+ everyone.allowed = acl->a_other_mask;
+ } else {
+ owner.allowed &= acl->a_owner_mask;
+ everyone.allowed &= acl->a_other_mask;
+ }
+ group.allowed &= acl->a_group_mask;
+ }
+
+ mode = (mode & ~S_IRWXUGO) |
+ (richacl_mask_to_mode(owner.allowed) << 6) |
+ (richacl_mask_to_mode(group.allowed) << 3) |
+ richacl_mask_to_mode(everyone.allowed);
+
+ /* Mask flags we can ignore */
+ x = S_ISDIR(mode) ? 0 : RICHACE_DELETE_CHILD;
+
+ if (((richacl_mode_to_mask(mode >> 6) ^ owner.allowed) & ~x) ||
+ ((richacl_mode_to_mask(mode >> 3) ^ group.allowed) & ~x) ||
+ ((richacl_mode_to_mask(mode) ^ everyone.allowed) & ~x))
+ return -1;
+
+ *mode_p = mode;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(richacl_equiv_mode);
diff --git a/include/linux/richacl.h b/include/linux/richacl.h
index db82fab..9212edb 100644
--- a/include/linux/richacl.h
+++ b/include/linux/richacl.h
@@ -191,5 +191,6 @@ extern unsigned int richacl_want_to_mask(unsigned int);
extern void richacl_compute_max_masks(struct richacl *);
extern int richacl_permission(struct inode *, const struct richacl *, int);
extern int richacl_chmod(struct inode *, umode_t);
+extern int richacl_equiv_mode(const struct richacl *, umode_t *);
#endif /* __RICHACL_H */
--
2.5.5
[toc] | [prev] | [next] | [standalone]
| From | Jeff Layton <jlayton@redhat.com> |
|---|---|
| Date | 2016-07-12 13:40 +0200 |
| Subject | Re: [PATCH v23 15/22] richacl: Check if an acl is equivalent to a file mode |
| Message-ID | <rU4cF-4gU-1@gated-at.bofh.it> |
| In reply to | #1434571 |
On Thu, 2016-06-30 at 15:47 +0200, Andreas Gruenbacher wrote:
> ACLs are considered equivalent to file modes if they only consist of
> owner@, group@, and everyone@ entries, the owner@ permissions do not
> depend on whether the owner is a member in the owning group, and no
> inheritance flags are set. This test is used to avoid storing richacls
> if the acl can be computed from the file permission bits.
>
> Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
> Reviewed-by: J. Bruce Fields <bfields@redhat.com>
> ---
> fs/richacl.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++
> include/linux/richacl.h | 1 +
> 2 files changed, 105 insertions(+)
>
> diff --git a/fs/richacl.c b/fs/richacl.c
> index ba110a6..e8a383b 100644
> --- a/fs/richacl.c
> +++ b/fs/richacl.c
> @@ -618,3 +618,107 @@ richacl_chmod(struct inode *inode, umode_t mode)
> return retval;
> }
> EXPORT_SYMBOL(richacl_chmod);
> +
> +/**
> + * richacl_equiv_mode - compute the mode equivalent of @acl
> + *
> + * An acl is considered equivalent to a file mode if it only consists of
> + * owner@, group@, and everyone@ entries and the owner@ permissions do not
> + * depend on whether the owner is a member in the owning group.
> + */
> +int
> +richacl_equiv_mode(const struct richacl *acl, umode_t *mode_p)
> +{
> + umode_t mode = *mode_p;
> +
> + /*
> + * The RICHACE_DELETE_CHILD flag is meaningless for non-directories, so
> + * we ignore it.
> + */
> + unsigned int x = S_ISDIR(mode) ? 0 : RICHACE_DELETE_CHILD;
> + struct {
> + unsigned int allowed;
> + unsigned int defined; /* allowed or denied */
> + } owner = {
> + .defined = RICHACE_POSIX_ALWAYS_ALLOWED |
> + RICHACE_POSIX_OWNER_ALLOWED | x,
> + }, group = {
> + .defined = RICHACE_POSIX_ALWAYS_ALLOWED | x,
> + }, everyone = {
> + .defined = RICHACE_POSIX_ALWAYS_ALLOWED | x,
> + };
> + const struct richace *ace;
> +
> + if (acl->a_flags & ~(RICHACL_WRITE_THROUGH | RICHACL_MASKED))
> + return -1;
> +
> + richacl_for_each_entry(ace, acl) {
> + if (ace->e_flags & ~RICHACE_SPECIAL_WHO)
> + return -1;
> +
> + if (richace_is_owner(ace) || richace_is_everyone(ace)) {
> + x = ace->e_mask & ~owner.defined;
> + if (richace_is_allow(ace)) {
> + unsigned int group_denied =
> + group.defined & ~group.allowed;
> +
> + if (x & group_denied)
> + return -1;
> + owner.allowed |= x;
> + } else /* if (richace_is_deny(ace)) */ {
> + if (x & group.allowed)
> + return -1;
> + }
> + owner.defined |= x;
> +
> + if (richace_is_everyone(ace)) {
> + x = ace->e_mask;
> + if (richace_is_allow(ace)) {
> + group.allowed |=
> + x & ~group.defined;
> + everyone.allowed |=
> + x & ~everyone.defined;
> + }
> + group.defined |= x;
> + everyone.defined |= x;
> + }
> + } else if (richace_is_group(ace)) {
> + x = ace->e_mask & ~group.defined;
> + if (richace_is_allow(ace))
> + group.allowed |= x;
> + group.defined |= x;
> + } else
> + return -1;
> + }
> +
> + if (group.allowed & ~owner.defined)
> + return -1;
> +
> + if (acl->a_flags & RICHACL_MASKED) {
> + if (acl->a_flags & RICHACL_WRITE_THROUGH) {
> + owner.allowed = acl->a_owner_mask;
> + everyone.allowed = acl->a_other_mask;
> + } else {
> + owner.allowed &= acl->a_owner_mask;
> + everyone.allowed &= acl->a_other_mask;
> + }
> + group.allowed &= acl->a_group_mask;
> + }
> +
> + mode = (mode & ~S_IRWXUGO) |
> + (richacl_mask_to_mode(owner.allowed) << 6) |
> + (richacl_mask_to_mode(group.allowed) << 3) |
> + richacl_mask_to_mode(everyone.allowed);
> +
> + /* Mask flags we can ignore */
> + x = S_ISDIR(mode) ? 0 : RICHACE_DELETE_CHILD;
> +
> + if (((richacl_mode_to_mask(mode >> 6) ^ owner.allowed) & ~x) ||
> + ((richacl_mode_to_mask(mode >> 3) ^ group.allowed) & ~x) ||
> + ((richacl_mode_to_mask(mode) ^ everyone.allowed) & ~x))
> + return -1;
> +
> + *mode_p = mode;
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(richacl_equiv_mode);
> diff --git a/include/linux/richacl.h b/include/linux/richacl.h
> index db82fab..9212edb 100644
> --- a/include/linux/richacl.h
> +++ b/include/linux/richacl.h
> @@ -191,5 +191,6 @@ extern unsigned int richacl_want_to_mask(unsigned int);
> extern void richacl_compute_max_masks(struct richacl *);
> extern int richacl_permission(struct inode *, const struct richacl *, int);
> extern int richacl_chmod(struct inode *, umode_t);
> +extern int richacl_equiv_mode(const struct richacl *, umode_t *);
>
> #endif /* __RICHACL_H */
Reviewed-by: Jeff Layton <jlayton@redhat.com>
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2016-06-30 16:00 +0200 |
| Subject | [PATCH v23 08/22] richacl: Compute maximum file masks from an acl |
| Message-ID | <rPKFA-1Pr-23@gated-at.bofh.it> |
| In reply to | #1434569 |
Compute upper bound owner, group, and other file masks with as few
permissions as possible without denying any permissions that the NFSv4
acl in a richacl grants.
This algorithm is used when a file inherits an acl at create time and
when an acl is set via a mechanism that does not provide file masks
(such as setting an acl via nfsd). When user-space sets an acl via
setxattr, the extended attribute already includes the file masks.
Setting an acl also sets the file mode permission bits: they are
determined by the file masks; see richacl_masks_to_mode().
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Reviewed-by: J. Bruce Fields <bfields@redhat.com>
---
fs/richacl.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/richacl.h | 1 +
2 files changed, 158 insertions(+)
diff --git a/fs/richacl.c b/fs/richacl.c
index d0a4135..056228f 100644
--- a/fs/richacl.c
+++ b/fs/richacl.c
@@ -181,3 +181,160 @@ richacl_want_to_mask(unsigned int want)
return mask;
}
EXPORT_SYMBOL_GPL(richacl_want_to_mask);
+
+/*
+ * Note: functions like richacl_allowed_to_who(), richacl_group_class_allowed(),
+ * and richacl_compute_max_masks() iterate through the entire acl in reverse
+ * order as an optimization.
+ *
+ * In the standard algorithm, aces are considered in forward order. When a
+ * process matches an ace, the permissions in the ace are either allowed or
+ * denied depending on the ace type. Once a permission has been allowed or
+ * denied, it is no longer considered in further aces.
+ *
+ * By iterating through the acl in reverse order, we can compute the same
+ * result without having to keep track of which permissions have been allowed
+ * and denied already.
+ */
+
+/**
+ * richacl_allowed_to_who - permissions allowed to a specific who value
+ *
+ * Compute the maximum mask values allowed to a specific who value, taking
+ * everyone@ aces into account.
+ */
+static unsigned int richacl_allowed_to_who(struct richacl *acl,
+ struct richace *who)
+{
+ struct richace *ace;
+ unsigned int allowed = 0;
+
+ richacl_for_each_entry_reverse(ace, acl) {
+ if (richace_is_inherit_only(ace))
+ continue;
+ if (richace_is_same_identifier(ace, who) ||
+ richace_is_everyone(ace)) {
+ if (richace_is_allow(ace))
+ allowed |= ace->e_mask;
+ else if (richace_is_deny(ace))
+ allowed &= ~ace->e_mask;
+ }
+ }
+ return allowed;
+}
+
+/**
+ * richacl_group_class_allowed - maximum permissions of the group class
+ *
+ * Compute the maximum mask values allowed to a process in the group class
+ * (i.e., a process which is not the owner but is in the owning group or
+ * matches a user or group acl entry). This includes permissions granted or
+ * denied by everyone@ aces.
+ *
+ * See richacl_compute_max_masks().
+ */
+static unsigned int richacl_group_class_allowed(struct richacl *acl)
+{
+ struct richace *ace;
+ unsigned int everyone_allowed = 0, group_class_allowed = 0;
+ int had_group_ace = 0;
+
+ richacl_for_each_entry_reverse(ace, acl) {
+ if (richace_is_inherit_only(ace) ||
+ richace_is_owner(ace))
+ continue;
+
+ if (richace_is_everyone(ace)) {
+ if (richace_is_allow(ace))
+ everyone_allowed |= ace->e_mask;
+ else if (richace_is_deny(ace))
+ everyone_allowed &= ~ace->e_mask;
+ } else {
+ group_class_allowed |=
+ richacl_allowed_to_who(acl, ace);
+
+ if (richace_is_group(ace))
+ had_group_ace = 1;
+ }
+ }
+ /*
+ * If the acl doesn't contain any group@ aces, richacl_allowed_to_who()
+ * wasn't called for the owning group. We could make that call now, but
+ * we already know the result (everyone_allowed).
+ */
+ if (!had_group_ace)
+ group_class_allowed |= everyone_allowed;
+ return group_class_allowed;
+}
+
+/**
+ * richacl_compute_max_masks - compute upper bound masks
+ *
+ * Computes upper bound owner, group, and other masks so that none of the
+ * permissions allowed by the acl are disabled.
+ *
+ * We don't make assumptions about who the owner is so that the owner can
+ * change with no effect on the file masks or file mode permission bits; this
+ * means that we must assume that all entries can match the owner.
+ */
+void richacl_compute_max_masks(struct richacl *acl)
+{
+ unsigned int gmask = ~0;
+ struct richace *ace;
+
+ /*
+ * @gmask contains all permissions which the group class is ever
+ * allowed. We use it to avoid adding permissions to the group mask
+ * from everyone@ allow aces which the group class is always denied
+ * through other aces. For example, the following acl would otherwise
+ * result in a group mask of rw:
+ *
+ * group@:w::deny
+ * everyone@:rw::allow
+ *
+ * Avoid computing @gmask for acls which do not include any group class
+ * deny aces: in such acls, the group class is never denied any
+ * permissions from everyone@ allow aces, and the group class cannot
+ * have fewer permissions than the other class.
+ */
+
+restart:
+ acl->a_owner_mask = 0;
+ acl->a_group_mask = 0;
+ acl->a_other_mask = 0;
+
+ richacl_for_each_entry_reverse(ace, acl) {
+ if (richace_is_inherit_only(ace))
+ continue;
+
+ if (richace_is_owner(ace)) {
+ if (richace_is_allow(ace))
+ acl->a_owner_mask |= ace->e_mask;
+ else if (richace_is_deny(ace))
+ acl->a_owner_mask &= ~ace->e_mask;
+ } else if (richace_is_everyone(ace)) {
+ if (richace_is_allow(ace)) {
+ acl->a_owner_mask |= ace->e_mask;
+ acl->a_group_mask |= ace->e_mask & gmask;
+ acl->a_other_mask |= ace->e_mask;
+ } else if (richace_is_deny(ace)) {
+ acl->a_owner_mask &= ~ace->e_mask;
+ acl->a_group_mask &= ~ace->e_mask;
+ acl->a_other_mask &= ~ace->e_mask;
+ }
+ } else {
+ if (richace_is_allow(ace)) {
+ acl->a_owner_mask |= ace->e_mask & gmask;
+ acl->a_group_mask |= ace->e_mask & gmask;
+ } else if (richace_is_deny(ace) && gmask == ~0) {
+ gmask = richacl_group_class_allowed(acl);
+ if (likely(gmask != ~0))
+ /* should always be true */
+ goto restart;
+ }
+ }
+ }
+
+ acl->a_flags &= ~(RICHACL_WRITE_THROUGH | RICHACL_MASKED);
+}
+EXPORT_SYMBOL_GPL(richacl_compute_max_masks);
diff --git a/include/linux/richacl.h b/include/linux/richacl.h
index 9102ef0..3559b2c 100644
--- a/include/linux/richacl.h
+++ b/include/linux/richacl.h
@@ -178,5 +178,6 @@ 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);
extern unsigned int richacl_want_to_mask(unsigned int);
+extern void richacl_compute_max_masks(struct richacl *);
#endif /* __RICHACL_H */
--
2.5.5
[toc] | [prev] | [next] | [standalone]
| From | "Frank Filz" <ffilzlnx@mindspring.com> |
|---|---|
| Date | 2016-07-05 19:10 +0200 |
| Subject | RE: [PATCH v23 08/22] richacl: Compute maximum file masks from an acl |
| Message-ID | <rRC1c-5HP-23@gated-at.bofh.it> |
| In reply to | #1434572 |
> > + * Note: functions like richacl_allowed_to_who(),
> > +richacl_group_class_allowed(),
> > + * and richacl_compute_max_masks() iterate through the entire acl in
> > +reverse
> > + * order as an optimization.
> > + *
> > + * In the standard algorithm, aces are considered in forward order.
> > +When a
> > + * process matches an ace, the permissions in the ace are either
> > +allowed or
> > + * denied depending on the ace type. Once a permission has been
> > +allowed or
> > + * denied, it is no longer considered in further aces.
> > + *
> > + * By iterating through the acl in reverse order, we can compute the
> > +same
> > + * result without having to keep track of which permissions have been
> > +allowed
> > + * and denied already.
> > + */
> >
>
> Clever!
Hmm, but does that result in examining the whole ACL for most access checks, at least for files where most of the accesses are by the owner, or a member of a specific group (with perhaps a ton of special case users added on the end)?
Frank
> > +
> > +/**
> > + * richacl_allowed_to_who - permissions allowed to a specific who
> > +value
> > + *
> > + * Compute the maximum mask values allowed to a specific who value,
> > +taking
> > + * everyone@ aces into account.
> > + */
> > +static unsigned int richacl_allowed_to_who(struct richacl *acl,
> > + struct richace *who)
> > +{
> > + struct richace *ace;
> > + unsigned int allowed = 0;
> > +
> > + richacl_for_each_entry_reverse(ace, acl) {
> > + if (richace_is_inherit_only(ace))
> > + continue;
> > + if (richace_is_same_identifier(ace, who) ||
> > + richace_is_everyone(ace)) {
> > + if (richace_is_allow(ace))
> > + allowed |= ace->e_mask;
> > + else if (richace_is_deny(ace))
> > + allowed &= ~ace->e_mask;
> > + }
> > + }
> > + return allowed;
> > +}
> > +
> > +/**
> > + * richacl_group_class_allowed - maximum permissions of the group
> > +class
> > + *
> > + * Compute the maximum mask values allowed to a process in the group
> > +class
> > + * (i.e., a process which is not the owner but is in the owning group
> > +or
> > + * matches a user or group acl entry). This includes permissions
> > +granted or
> > + * denied by everyone@ aces.
> > + *
> > + * See richacl_compute_max_masks().
> > + */
> > +static unsigned int richacl_group_class_allowed(struct richacl *acl)
> > +{
> > + struct richace *ace;
> > + unsigned int everyone_allowed = 0, group_class_allowed = 0;
> > + int had_group_ace = 0;
> > +
> > + richacl_for_each_entry_reverse(ace, acl) {
> > + if (richace_is_inherit_only(ace) ||
> > + richace_is_owner(ace))
> > + continue;
> > +
> > + if (richace_is_everyone(ace)) {
> > + if (richace_is_allow(ace))
> > + everyone_allowed |= ace->e_mask;
> > + else if (richace_is_deny(ace))
> > + everyone_allowed &= ~ace->e_mask;
> > + } else {
> > + group_class_allowed |=
> > + richacl_allowed_to_who(acl, ace);
> > +
> > + if (richace_is_group(ace))
> > + had_group_ace = 1;
> > + }
> > + }
> > + /*
> > + * If the acl doesn't contain any group@ aces,
> richacl_allowed_to_who()
> > + * wasn't called for the owning group. We could make that call now,
> but
> > + * we already know the result (everyone_allowed).
> > + */
> > + if (!had_group_ace)
> > + group_class_allowed |= everyone_allowed;
> > + return group_class_allowed;
> > +}
> > +
> > +/**
> > + * richacl_compute_max_masks - compute upper bound masks
> > + *
> > + * Computes upper bound owner, group, and other masks so that none of
> > +the
> > + * permissions allowed by the acl are disabled.
> > + *
> > + * We don't make assumptions about who the owner is so that the owner
> > +can
> > + * change with no effect on the file masks or file mode permission
> > +bits; this
> > + * means that we must assume that all entries can match the owner.
> > + */
> > +void richacl_compute_max_masks(struct richacl *acl) {
> > + unsigned int gmask = ~0;
> > + struct richace *ace;
> > +
> > + /*
> > + * @gmask contains all permissions which the group class is ever
> > + * allowed. We use it to avoid adding permissions to the group mask
> > + * from everyone@ allow aces which the group class is always denied
> > + * through other aces. For example, the following acl would
> otherwise
> > + * result in a group mask of rw:
> > + *
> > + * group@:w::deny
> > + * everyone@:rw::allow
> > + *
> > + * Avoid computing @gmask for acls which do not include any group
> class
> > + * deny aces: in such acls, the group class is never denied any
> > + * permissions from everyone@ allow aces, and the group class
> cannot
> > + * have fewer permissions than the other class.
> > + */
> > +
> > +restart:
> > + acl->a_owner_mask = 0;
> > + acl->a_group_mask = 0;
> > + acl->a_other_mask = 0;
> > +
> > + richacl_for_each_entry_reverse(ace, acl) {
> > + if (richace_is_inherit_only(ace))
> > + continue;
> > +
> > + if (richace_is_owner(ace)) {
> > + if (richace_is_allow(ace))
> > + acl->a_owner_mask |= ace->e_mask;
> > + else if (richace_is_deny(ace))
> > + acl->a_owner_mask &= ~ace->e_mask;
> > + } else if (richace_is_everyone(ace)) {
> > + if (richace_is_allow(ace)) {
> > + acl->a_owner_mask |= ace->e_mask;
> > + acl->a_group_mask |= ace->e_mask &
> gmask;
> > + acl->a_other_mask |= ace->e_mask;
> > + } else if (richace_is_deny(ace)) {
> > + acl->a_owner_mask &= ~ace->e_mask;
> > + acl->a_group_mask &= ~ace->e_mask;
> > + acl->a_other_mask &= ~ace->e_mask;
> > + }
> > + } else {
> > + if (richace_is_allow(ace)) {
> > + acl->a_owner_mask |= ace->e_mask &
> gmask;
> > + acl->a_group_mask |= ace->e_mask &
> gmask;
> > + } else if (richace_is_deny(ace) && gmask == ~0) {
> > + gmask = richacl_group_class_allowed(acl);
> > + if (likely(gmask != ~0))
> > + /* should always be true */
> > + goto restart;
> > + }
> > + }
> > + }
> > +
> > + acl->a_flags &= ~(RICHACL_WRITE_THROUGH | RICHACL_MASKED); }
> > +EXPORT_SYMBOL_GPL(richacl_compute_max_masks);
> > diff --git a/include/linux/richacl.h b/include/linux/richacl.h index
> > 9102ef0..3559b2c 100644
> > --- a/include/linux/richacl.h
> > +++ b/include/linux/richacl.h
> > @@ -178,5 +178,6 @@ 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);
> > extern unsigned int richacl_want_to_mask(unsigned int);
> > +extern void richacl_compute_max_masks(struct richacl *);
> >
> > #endif /* __RICHACL_H */
>
> Reviewed-by: Jeff Layton <jlayton@redhat.com>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the
> body of a message to majordomo@vger.kernel.org More majordomo info at
> http://vger.kernel.org/majordomo-info.html
---
This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2016-07-13 14:40 +0200 |
| Subject | Re: [PATCH v23 08/22] richacl: Compute maximum file masks from an acl |
| Message-ID | <rUrCi-34n-17@gated-at.bofh.it> |
| In reply to | #1437196 |
Frank, On Tue, Jul 5, 2016 at 7:08 PM, Frank Filz <ffilzlnx@mindspring.com> wrote: >> > + * Note: functions like richacl_allowed_to_who(), >> > +richacl_group_class_allowed(), >> > + * and richacl_compute_max_masks() iterate through the entire acl in >> > +reverse >> > + * order as an optimization. >> > + * >> > + * In the standard algorithm, aces are considered in forward order. >> > +When a >> > + * process matches an ace, the permissions in the ace are either >> > +allowed or >> > + * denied depending on the ace type. Once a permission has been >> > +allowed or >> > + * denied, it is no longer considered in further aces. >> > + * >> > + * By iterating through the acl in reverse order, we can compute the >> > +same >> > + * result without having to keep track of which permissions have been >> > +allowed >> > + * and denied already. >> > + */ >> > >> >> Clever! > > Hmm, but does that result in examining the whole ACL for most access checks, at least for files where most of the accesses are by the owner, or a member of a specific group (with perhaps a ton of special case users added on the end)? I don't understand -- what does this algorithm have to do with access checks? Thanks, Andreas
[toc] | [prev] | [next] | [standalone]
| From | "Frank Filz" <ffilzlnx@mindspring.com> |
|---|---|
| Date | 2016-07-13 21:50 +0200 |
| Subject | RE: [PATCH v23 08/22] richacl: Compute maximum file masks from an acl |
| Message-ID | <rUykq-7ut-23@gated-at.bofh.it> |
| In reply to | #1442402 |
> > Hmm, but does that result in examining the whole ACL for most access > checks, at least for files where most of the accesses are by the owner, or a > member of a specific group (with perhaps a ton of special case users added > on the end)? > > I don't understand -- what does this algorithm have to do with access checks? Oh, sorry, misread the patch... got caught up looking at a tree and not seeing the forest... Frank --- This email has been checked for viruses by Avast antivirus software. https://www.avast.com/antivirus
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2016-06-30 16:00 +0200 |
| Subject | [PATCH v23 16/22] richacl: Create-time inheritance |
| Message-ID | <rPKFA-1Pr-25@gated-at.bofh.it> |
| In reply to | #1434569 |
When a new file is created, it can inherit an acl from its parent
directory; this is similar to how default acls work in POSIX ACLs.
As with POSIX ACLs, if a file inherits an acl from its parent directory,
the intersection between the create mode and the permissions granted by
the inherited acl determines the file masks and file permission bits,
and the umask is ignored.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
fs/richacl.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/richacl.h | 2 +
2 files changed, 153 insertions(+)
diff --git a/fs/richacl.c b/fs/richacl.c
index e8a383b..29eaf89 100644
--- a/fs/richacl.c
+++ b/fs/richacl.c
@@ -722,3 +722,154 @@ richacl_equiv_mode(const struct richacl *acl, umode_t *mode_p)
return 0;
}
EXPORT_SYMBOL_GPL(richacl_equiv_mode);
+
+static inline bool
+ace_inherits_to_directory(const struct richace *ace)
+{
+ if (ace->e_flags & RICHACE_DIRECTORY_INHERIT_ACE)
+ return true;
+ if ((ace->e_flags & RICHACE_FILE_INHERIT_ACE) &&
+ !(ace->e_flags & RICHACE_NO_PROPAGATE_INHERIT_ACE))
+ return true;
+ return false;
+}
+
+/**
+ * richacl_inherit - compute the inherited acl of a new file
+ * @dir_acl: acl of the containing directory
+ * @isdir: inherit by a directory or non-directory?
+ *
+ * A directory can have acl entries which files and/or directories created
+ * inside the directory will inherit. This function computes the acl for such
+ * a new file. If there is no inheritable acl, it will return %NULL.
+ */
+struct richacl *
+richacl_inherit(const struct richacl *dir_acl, int isdir)
+{
+ const struct richace *dir_ace;
+ struct richacl *acl = NULL;
+ struct richace *ace;
+ int count = 0;
+
+ if (isdir) {
+ richacl_for_each_entry(dir_ace, dir_acl) {
+ if (!ace_inherits_to_directory(dir_ace))
+ continue;
+ count++;
+ }
+ if (!count)
+ return NULL;
+ acl = richacl_alloc(count, GFP_KERNEL);
+ if (!acl)
+ return ERR_PTR(-ENOMEM);
+ ace = acl->a_entries;
+ richacl_for_each_entry(dir_ace, dir_acl) {
+ if (!ace_inherits_to_directory(dir_ace))
+ continue;
+ richace_copy(ace, dir_ace);
+ if (dir_ace->e_flags & RICHACE_NO_PROPAGATE_INHERIT_ACE)
+ ace->e_flags &= ~RICHACE_INHERITANCE_FLAGS;
+ else if (dir_ace->e_flags & RICHACE_DIRECTORY_INHERIT_ACE)
+ ace->e_flags &= ~RICHACE_INHERIT_ONLY_ACE;
+ else
+ ace->e_flags |= RICHACE_INHERIT_ONLY_ACE;
+ ace++;
+ }
+ } else {
+ richacl_for_each_entry(dir_ace, dir_acl) {
+ if (!(dir_ace->e_flags & RICHACE_FILE_INHERIT_ACE))
+ continue;
+ count++;
+ }
+ if (!count)
+ return NULL;
+ acl = richacl_alloc(count, GFP_KERNEL);
+ if (!acl)
+ return ERR_PTR(-ENOMEM);
+ ace = acl->a_entries;
+ richacl_for_each_entry(dir_ace, dir_acl) {
+ if (!(dir_ace->e_flags & RICHACE_FILE_INHERIT_ACE))
+ continue;
+ richace_copy(ace, dir_ace);
+ ace->e_flags &= ~RICHACE_INHERITANCE_FLAGS;
+ /*
+ * RICHACE_DELETE_CHILD is meaningless for
+ * non-directories, so clear it.
+ */
+ ace->e_mask &= ~RICHACE_DELETE_CHILD;
+ ace++;
+ }
+ }
+
+ return acl;
+}
+
+/*
+ * richacl_inherit_inode - compute inherited acl and file mode
+ * @dir_acl: acl of the containing directory
+ * @mode_p: mode of the new inode
+ *
+ * The file permission bits in @mode_p must be set to the create mode by the
+ * caller.
+ *
+ * If there is an inheritable acl, the maximum permissions that the acl grants
+ * are computed and the file masks of the new acl are set accordingly.
+ */
+static struct richacl *
+richacl_inherit_inode(const struct richacl *dir_acl, umode_t *mode_p)
+{
+ struct richacl *acl;
+ umode_t mode = *mode_p;
+
+ acl = richacl_inherit(dir_acl, S_ISDIR(mode));
+ if (acl) {
+ if (richacl_equiv_mode(acl, &mode) == 0) {
+ *mode_p &= mode;
+ richacl_put(acl);
+ acl = NULL;
+ } else {
+ richacl_compute_max_masks(acl);
+ /*
+ * Ensure that the acl will not grant any permissions
+ * beyond the create mode.
+ */
+ acl->a_flags |= RICHACL_MASKED;
+ acl->a_owner_mask &=
+ richacl_mode_to_mask(mode >> 6);
+ acl->a_group_mask &=
+ richacl_mode_to_mask(mode >> 3);
+ acl->a_other_mask &=
+ richacl_mode_to_mask(mode);
+ }
+ } else
+ *mode_p &= ~current_umask();
+
+ return acl;
+}
+
+/**
+ * richacl_create - filesystem create helper
+ * @mode_p: mode of the new inode
+ * @dir: containing directory
+ *
+ * Compute the inherited acl for a new inode. If there is no acl to inherit,
+ * apply the umask. Use when creating a new inode on a richacl enabled file
+ * system.
+ */
+struct richacl *richacl_create(umode_t *mode_p, struct inode *dir)
+{
+ struct richacl *dir_acl, *acl = NULL;
+
+ if (S_ISLNK(*mode_p))
+ return NULL;
+ dir_acl = get_richacl(dir);
+ if (dir_acl) {
+ if (IS_ERR(dir_acl))
+ return dir_acl;
+ acl = richacl_inherit_inode(dir_acl, mode_p);
+ richacl_put(dir_acl);
+ } else
+ *mode_p &= ~current_umask();
+ return acl;
+}
+EXPORT_SYMBOL_GPL(richacl_create);
diff --git a/include/linux/richacl.h b/include/linux/richacl.h
index 9212edb..7aca1a3 100644
--- a/include/linux/richacl.h
+++ b/include/linux/richacl.h
@@ -192,5 +192,7 @@ extern void richacl_compute_max_masks(struct richacl *);
extern int richacl_permission(struct inode *, const struct richacl *, int);
extern int richacl_chmod(struct inode *, umode_t);
extern int richacl_equiv_mode(const struct richacl *, umode_t *);
+extern struct richacl *richacl_inherit(const struct richacl *, int);
+extern struct richacl *richacl_create(umode_t *, struct inode *);
#endif /* __RICHACL_H */
--
2.5.5
[toc] | [prev] | [next] | [standalone]
| From | Jeff Layton <jlayton@redhat.com> |
|---|---|
| Date | 2016-07-12 13:50 +0200 |
| Subject | Re: [PATCH v23 16/22] richacl: Create-time inheritance |
| Message-ID | <rU4mm-4l8-19@gated-at.bofh.it> |
| In reply to | #1434573 |
On Thu, 2016-06-30 at 15:47 +0200, Andreas Gruenbacher wrote:
> When a new file is created, it can inherit an acl from its parent
> directory; this is similar to how default acls work in POSIX ACLs.
>
> As with POSIX ACLs, if a file inherits an acl from its parent directory,
> the intersection between the create mode and the permissions granted by
> the inherited acl determines the file masks and file permission bits,
> and the umask is ignored.
>
> Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
> ---
> fs/richacl.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++++
> include/linux/richacl.h | 2 +
> 2 files changed, 153 insertions(+)
>
> diff --git a/fs/richacl.c b/fs/richacl.c
> index e8a383b..29eaf89 100644
> --- a/fs/richacl.c
> +++ b/fs/richacl.c
> @@ -722,3 +722,154 @@ richacl_equiv_mode(const struct richacl *acl, umode_t *mode_p)
> return 0;
> }
> EXPORT_SYMBOL_GPL(richacl_equiv_mode);
> +
> +static inline bool
> +ace_inherits_to_directory(const struct richace *ace)
> +{
> + if (ace->e_flags & RICHACE_DIRECTORY_INHERIT_ACE)
> + return true;
> + if ((ace->e_flags & RICHACE_FILE_INHERIT_ACE) &&
> + !(ace->e_flags & RICHACE_NO_PROPAGATE_INHERIT_ACE))
> + return true;
> + return false;
> +}
> +
> +/**
> + * richacl_inherit - compute the inherited acl of a new file
> + * @dir_acl: acl of the containing directory
> + * @isdir: inherit by a directory or non-directory?
> + *
> + * A directory can have acl entries which files and/or directories created
> + * inside the directory will inherit. This function computes the acl for such
> + * a new file. If there is no inheritable acl, it will return %NULL.
> + */
> +struct richacl *
> +richacl_inherit(const struct richacl *dir_acl, int isdir)
> +{
> + const struct richace *dir_ace;
> + struct richacl *acl = NULL;
> + struct richace *ace;
> + int count = 0;
> +
> + if (isdir) {
> + richacl_for_each_entry(dir_ace, dir_acl) {
> + if (!ace_inherits_to_directory(dir_ace))
> + continue;
> + count++;
> + }
> + if (!count)
> + return NULL;
> + acl = richacl_alloc(count, GFP_KERNEL);
> + if (!acl)
> + return ERR_PTR(-ENOMEM);
> + ace = acl->a_entries;
> + richacl_for_each_entry(dir_ace, dir_acl) {
> + if (!ace_inherits_to_directory(dir_ace))
> + continue;
> + richace_copy(ace, dir_ace);
> + if (dir_ace->e_flags & RICHACE_NO_PROPAGATE_INHERIT_ACE)
> + ace->e_flags &= ~RICHACE_INHERITANCE_FLAGS;
> + else if (dir_ace->e_flags & RICHACE_DIRECTORY_INHERIT_ACE)
> + ace->e_flags &= ~RICHACE_INHERIT_ONLY_ACE;
> + else
> + ace->e_flags |= RICHACE_INHERIT_ONLY_ACE;
> + ace++;
> + }
> + } else {
> + richacl_for_each_entry(dir_ace, dir_acl) {
> + if (!(dir_ace->e_flags & RICHACE_FILE_INHERIT_ACE))
> + continue;
> + count++;
> + }
> + if (!count)
> + return NULL;
> + acl = richacl_alloc(count, GFP_KERNEL);
> + if (!acl)
> + return ERR_PTR(-ENOMEM);
> + ace = acl->a_entries;
> + richacl_for_each_entry(dir_ace, dir_acl) {
> + if (!(dir_ace->e_flags & RICHACE_FILE_INHERIT_ACE))
> + continue;
> + richace_copy(ace, dir_ace);
> + ace->e_flags &= ~RICHACE_INHERITANCE_FLAGS;
> + /*
> + * RICHACE_DELETE_CHILD is meaningless for
> + * non-directories, so clear it.
> + */
> + ace->e_mask &= ~RICHACE_DELETE_CHILD;
> + ace++;
> + }
> + }
> +
> + return acl;
> +}
> +
> +/*
> + * richacl_inherit_inode - compute inherited acl and file mode
> + * @dir_acl: acl of the containing directory
> + * @mode_p: mode of the new inode
> + *
> + * The file permission bits in @mode_p must be set to the create mode by the
> + * caller.
> + *
> + * If there is an inheritable acl, the maximum permissions that the acl grants
> + * are computed and the file masks of the new acl are set accordingly.
> + */
> +static struct richacl *
> +richacl_inherit_inode(const struct richacl *dir_acl, umode_t *mode_p)
> +{
> + struct richacl *acl;
> + umode_t mode = *mode_p;
> +
> + acl = richacl_inherit(dir_acl, S_ISDIR(mode));
> + if (acl) {
> + if (richacl_equiv_mode(acl, &mode) == 0) {
> + *mode_p &= mode;
> + richacl_put(acl);
> + acl = NULL;
> + } else {
> + richacl_compute_max_masks(acl);
> + /*
> + * Ensure that the acl will not grant any permissions
> + * beyond the create mode.
> + */
> + acl->a_flags |= RICHACL_MASKED;
> + acl->a_owner_mask &=
> + richacl_mode_to_mask(mode >> 6);
> + acl->a_group_mask &=
> + richacl_mode_to_mask(mode >> 3);
> + acl->a_other_mask &=
> + richacl_mode_to_mask(mode);
> + }
> + } else
> + *mode_p &= ~current_umask();
> +
> + return acl;
> +}
> +
> +/**
> + * richacl_create - filesystem create helper
> + * @mode_p: mode of the new inode
> + * @dir: containing directory
> + *
> + * Compute the inherited acl for a new inode. If there is no acl to inherit,
> + * apply the umask. Use when creating a new inode on a richacl enabled file
> + * system.
> + */
> +struct richacl *richacl_create(umode_t *mode_p, struct inode *dir)
> +{
> + struct richacl *dir_acl, *acl = NULL;
> +
> + if (S_ISLNK(*mode_p))
> + return NULL;
> + dir_acl = get_richacl(dir);
> + if (dir_acl) {
> + if (IS_ERR(dir_acl))
> + return dir_acl;
> + acl = richacl_inherit_inode(dir_acl, mode_p);
> + richacl_put(dir_acl);
> + } else
> + *mode_p &= ~current_umask();
> + return acl;
> +}
> +EXPORT_SYMBOL_GPL(richacl_create);
> diff --git a/include/linux/richacl.h b/include/linux/richacl.h
> index 9212edb..7aca1a3 100644
> --- a/include/linux/richacl.h
> +++ b/include/linux/richacl.h
> @@ -192,5 +192,7 @@ extern void richacl_compute_max_masks(struct richacl *);
> extern int richacl_permission(struct inode *, const struct richacl *, int);
> extern int richacl_chmod(struct inode *, umode_t);
> extern int richacl_equiv_mode(const struct richacl *, umode_t *);
> +extern struct richacl *richacl_inherit(const struct richacl *, int);
> +extern struct richacl *richacl_create(umode_t *, struct inode *);
>
> #endif /* __RICHACL_H */
Reviewed-by: Jeff Layton <jlayton@redhat.com>
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2016-06-30 16:00 +0200 |
| Subject | [PATCH v23 06/22] richacl: In-memory representation and helper functions |
| Message-ID | <rPKFA-1Pr-27@gated-at.bofh.it> |
| In reply to | #1434569 |
A richacl consists of an NFSv4 acl and an owner, group, and other mask.
These three masks correspond to the owner, group, and other file
permission bits, but they contain NFSv4 permissions instead of POSIX
permissions.
Each entry in the NFSv4 acl applies to the file owner (OWNER@), the
owning group (GROUP@), everyone (EVERYONE@), or to a specific uid or
gid.
As in the standard POSIX file permission model, each process is the
owner, group, or other file class. A richacl grants a requested access
only if the NFSv4 acl in the richacl grants the access (according to the
NFSv4 permission check algorithm), and the file mask that applies to the
process includes the requested permissions.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Reviewed-by: J. Bruce Fields <bfields@redhat.com>
---
fs/Makefile | 1 +
fs/richacl.c | 65 ++++++++++++++++
include/linux/richacl.h | 179 +++++++++++++++++++++++++++++++++++++++++++
include/uapi/linux/Kbuild | 1 +
include/uapi/linux/richacl.h | 99 ++++++++++++++++++++++++
5 files changed, 345 insertions(+)
create mode 100644 fs/richacl.c
create mode 100644 include/linux/richacl.h
create mode 100644 include/uapi/linux/richacl.h
diff --git a/fs/Makefile b/fs/Makefile
index 85b6e13..2b3e6f1 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -49,6 +49,7 @@ obj-$(CONFIG_COREDUMP) += coredump.o
obj-$(CONFIG_SYSCTL) += drop_caches.o
obj-$(CONFIG_FHANDLE) += fhandle.o
+obj-$(CONFIG_FS_RICHACL) += richacl.o
obj-y += quota/
diff --git a/fs/richacl.c b/fs/richacl.c
new file mode 100644
index 0000000..bcc6591
--- /dev/null
+++ b/fs/richacl.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2006, 2010 Novell, Inc.
+ * Copyright (C) 2015 Red Hat, Inc.
+ * Written by Andreas Gruenbacher <agruenba@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/richacl.h>
+
+/**
+ * richacl_alloc - allocate a richacl
+ * @count: number of entries
+ */
+struct richacl *
+richacl_alloc(int count, gfp_t gfp)
+{
+ size_t size = sizeof(struct richacl) + count * sizeof(struct richace);
+ struct richacl *acl = kzalloc(size, gfp);
+
+ if (acl) {
+ atomic_set(&acl->a_refcount, 1);
+ acl->a_count = count;
+ }
+ return acl;
+}
+EXPORT_SYMBOL_GPL(richacl_alloc);
+
+/**
+ * richacl_clone - create a copy of a richacl
+ */
+struct richacl *
+richacl_clone(const struct richacl *acl, gfp_t gfp)
+{
+ int count = acl->a_count;
+ size_t size = sizeof(struct richacl) + count * sizeof(struct richace);
+ struct richacl *dup = kmalloc(size, gfp);
+
+ if (dup) {
+ memcpy(dup, acl, size);
+ atomic_set(&dup->a_refcount, 1);
+ }
+ return dup;
+}
+
+/**
+ * richace_copy - copy an acl entry
+ */
+void
+richace_copy(struct richace *to, const struct richace *from)
+{
+ memcpy(to, from, sizeof(struct richace));
+}
diff --git a/include/linux/richacl.h b/include/linux/richacl.h
new file mode 100644
index 0000000..edb8480
--- /dev/null
+++ b/include/linux/richacl.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2006, 2010 Novell, Inc.
+ * Copyright (C) 2015 Red Hat, Inc.
+ * Written by Andreas Gruenbacher <agruenba@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __RICHACL_H
+#define __RICHACL_H
+
+#include <uapi/linux/richacl.h>
+
+struct richace {
+ unsigned short e_type;
+ unsigned short e_flags;
+ unsigned int e_mask;
+ union {
+ kuid_t uid;
+ kgid_t gid;
+ unsigned int special;
+ } e_id;
+};
+
+struct richacl {
+ atomic_t a_refcount;
+ unsigned int a_owner_mask;
+ unsigned int a_group_mask;
+ unsigned int a_other_mask;
+ unsigned short a_count;
+ unsigned short a_flags;
+ struct richace a_entries[0];
+};
+
+#define richacl_for_each_entry(_ace, _acl) \
+ for (_ace = (_acl)->a_entries; \
+ _ace != (_acl)->a_entries + (_acl)->a_count; \
+ _ace++)
+
+#define richacl_for_each_entry_reverse(_ace, _acl) \
+ for (_ace = (_acl)->a_entries + (_acl)->a_count - 1; \
+ _ace != (_acl)->a_entries - 1; \
+ _ace--)
+
+/**
+ * richacl_get - grab another reference to a richacl handle
+ */
+static inline struct richacl *
+richacl_get(struct richacl *acl)
+{
+ if (acl)
+ atomic_inc(&acl->a_refcount);
+ return acl;
+}
+
+/**
+ * richacl_put - free a richacl handle
+ */
+static inline void
+richacl_put(struct richacl *acl)
+{
+ if (acl && atomic_dec_and_test(&acl->a_refcount))
+ kfree(acl);
+}
+
+/**
+ * richace_is_owner - check if @ace is an OWNER@ entry
+ */
+static inline bool
+richace_is_owner(const struct richace *ace)
+{
+ return (ace->e_flags & RICHACE_SPECIAL_WHO) &&
+ ace->e_id.special == RICHACE_OWNER_SPECIAL_ID;
+}
+
+/**
+ * richace_is_group - check if @ace is a GROUP@ entry
+ */
+static inline bool
+richace_is_group(const struct richace *ace)
+{
+ return (ace->e_flags & RICHACE_SPECIAL_WHO) &&
+ ace->e_id.special == RICHACE_GROUP_SPECIAL_ID;
+}
+
+/**
+ * richace_is_everyone - check if @ace is an EVERYONE@ entry
+ */
+static inline bool
+richace_is_everyone(const struct richace *ace)
+{
+ return (ace->e_flags & RICHACE_SPECIAL_WHO) &&
+ ace->e_id.special == RICHACE_EVERYONE_SPECIAL_ID;
+}
+
+/**
+ * richace_is_unix_user - check if @ace applies to a specific user
+ */
+static inline bool
+richace_is_unix_user(const struct richace *ace)
+{
+ return !(ace->e_flags & RICHACE_SPECIAL_WHO) &&
+ !(ace->e_flags & RICHACE_IDENTIFIER_GROUP);
+}
+
+/**
+ * richace_is_unix_group - check if @ace applies to a specific group
+ */
+static inline bool
+richace_is_unix_group(const struct richace *ace)
+{
+ return !(ace->e_flags & RICHACE_SPECIAL_WHO) &&
+ (ace->e_flags & RICHACE_IDENTIFIER_GROUP);
+}
+
+/**
+ * richace_is_inherit_only - check if @ace is for inheritance only
+ *
+ * ACEs with the %RICHACE_INHERIT_ONLY_ACE flag set have no effect during
+ * permission checking.
+ */
+static inline bool
+richace_is_inherit_only(const struct richace *ace)
+{
+ return ace->e_flags & RICHACE_INHERIT_ONLY_ACE;
+}
+
+/**
+ * richace_is_inheritable - check if @ace is inheritable
+ */
+static inline bool
+richace_is_inheritable(const struct richace *ace)
+{
+ return ace->e_flags & (RICHACE_FILE_INHERIT_ACE |
+ RICHACE_DIRECTORY_INHERIT_ACE);
+}
+
+/**
+ * richace_is_allow - check if @ace is an %ALLOW type entry
+ */
+static inline bool
+richace_is_allow(const struct richace *ace)
+{
+ return ace->e_type == RICHACE_ACCESS_ALLOWED_ACE_TYPE;
+}
+
+/**
+ * richace_is_deny - check if @ace is a %DENY type entry
+ */
+static inline bool
+richace_is_deny(const struct richace *ace)
+{
+ return ace->e_type == RICHACE_ACCESS_DENIED_ACE_TYPE;
+}
+
+/**
+ * richace_is_same_identifier - are both identifiers the same?
+ */
+static inline bool
+richace_is_same_identifier(const struct richace *a, const struct richace *b)
+{
+ return !((a->e_flags ^ b->e_flags) &
+ (RICHACE_SPECIAL_WHO | RICHACE_IDENTIFIER_GROUP)) &&
+ !memcmp(&a->e_id, &b->e_id, sizeof(a->e_id));
+}
+
+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 *);
+
+#endif /* __RICHACL_H */
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
index 8bdae34..abeaa98 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -355,6 +355,7 @@ header-y += reboot.h
header-y += reiserfs_fs.h
header-y += reiserfs_xattr.h
header-y += resource.h
+header-y += richacl.h
header-y += rfkill.h
header-y += rio_mport_cdev.h
header-y += romfs_fs.h
diff --git a/include/uapi/linux/richacl.h b/include/uapi/linux/richacl.h
new file mode 100644
index 0000000..08856f8
--- /dev/null
+++ b/include/uapi/linux/richacl.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2006, 2010 Novell, Inc.
+ * Copyright (C) 2015 Red Hat, Inc.
+ * Written by Andreas Gruenbacher <agruenba@redhat.com>
+ *
+ * This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifndef __UAPI_RICHACL_H
+#define __UAPI_RICHACL_H
+
+/* a_flags values */
+#define RICHACL_WRITE_THROUGH 0x40
+#define RICHACL_MASKED 0x80
+
+/* e_type values */
+#define RICHACE_ACCESS_ALLOWED_ACE_TYPE 0x0000
+#define RICHACE_ACCESS_DENIED_ACE_TYPE 0x0001
+
+/* e_flags bitflags */
+#define RICHACE_FILE_INHERIT_ACE 0x0001
+#define RICHACE_DIRECTORY_INHERIT_ACE 0x0002
+#define RICHACE_NO_PROPAGATE_INHERIT_ACE 0x0004
+#define RICHACE_INHERIT_ONLY_ACE 0x0008
+#define RICHACE_IDENTIFIER_GROUP 0x0040
+#define RICHACE_SPECIAL_WHO 0x4000
+
+/* e_mask bitflags */
+#define RICHACE_READ_DATA 0x00000001
+#define RICHACE_LIST_DIRECTORY 0x00000001
+#define RICHACE_WRITE_DATA 0x00000002
+#define RICHACE_ADD_FILE 0x00000002
+#define RICHACE_APPEND_DATA 0x00000004
+#define RICHACE_ADD_SUBDIRECTORY 0x00000004
+#define RICHACE_READ_NAMED_ATTRS 0x00000008
+#define RICHACE_WRITE_NAMED_ATTRS 0x00000010
+#define RICHACE_EXECUTE 0x00000020
+#define RICHACE_DELETE_CHILD 0x00000040
+#define RICHACE_READ_ATTRIBUTES 0x00000080
+#define RICHACE_WRITE_ATTRIBUTES 0x00000100
+#define RICHACE_WRITE_RETENTION 0x00000200
+#define RICHACE_WRITE_RETENTION_HOLD 0x00000400
+#define RICHACE_DELETE 0x00010000
+#define RICHACE_READ_ACL 0x00020000
+#define RICHACE_WRITE_ACL 0x00040000
+#define RICHACE_WRITE_OWNER 0x00080000
+#define RICHACE_SYNCHRONIZE 0x00100000
+
+/* e_id values */
+#define RICHACE_OWNER_SPECIAL_ID 0
+#define RICHACE_GROUP_SPECIAL_ID 1
+#define RICHACE_EVERYONE_SPECIAL_ID 2
+
+#define RICHACL_VALID_FLAGS ( \
+ RICHACL_WRITE_THROUGH | \
+ RICHACL_MASKED )
+
+#define RICHACE_VALID_FLAGS ( \
+ RICHACE_FILE_INHERIT_ACE | \
+ RICHACE_DIRECTORY_INHERIT_ACE | \
+ RICHACE_NO_PROPAGATE_INHERIT_ACE | \
+ RICHACE_INHERIT_ONLY_ACE | \
+ RICHACE_IDENTIFIER_GROUP | \
+ RICHACE_SPECIAL_WHO )
+
+#define RICHACE_INHERITANCE_FLAGS ( \
+ RICHACE_FILE_INHERIT_ACE | \
+ RICHACE_DIRECTORY_INHERIT_ACE | \
+ RICHACE_NO_PROPAGATE_INHERIT_ACE | \
+ RICHACE_INHERIT_ONLY_ACE )
+
+/* Valid RICHACE_* flags for directories and non-directories */
+#define RICHACE_VALID_MASK ( \
+ RICHACE_READ_DATA | RICHACE_LIST_DIRECTORY | \
+ RICHACE_WRITE_DATA | RICHACE_ADD_FILE | \
+ RICHACE_APPEND_DATA | RICHACE_ADD_SUBDIRECTORY | \
+ RICHACE_READ_NAMED_ATTRS | \
+ RICHACE_WRITE_NAMED_ATTRS | \
+ RICHACE_EXECUTE | \
+ RICHACE_DELETE_CHILD | \
+ RICHACE_READ_ATTRIBUTES | \
+ RICHACE_WRITE_ATTRIBUTES | \
+ RICHACE_WRITE_RETENTION | \
+ RICHACE_WRITE_RETENTION_HOLD | \
+ RICHACE_DELETE | \
+ RICHACE_READ_ACL | \
+ RICHACE_WRITE_ACL | \
+ RICHACE_WRITE_OWNER | \
+ RICHACE_SYNCHRONIZE )
+
+#endif /* __UAPI_RICHACL_H */
--
2.5.5
[toc] | [prev] | [next] | [standalone]
| From | Jeff Layton <jlayton@redhat.com> |
|---|---|
| Date | 2016-07-05 13:40 +0200 |
| Subject | Re: [PATCH v23 06/22] richacl: In-memory representation and helper functions |
| Message-ID | <rRwRP-2bm-1@gated-at.bofh.it> |
| In reply to | #1434574 |
On Thu, 2016-06-30 at 15:46 +0200, Andreas Gruenbacher wrote:
> A richacl consists of an NFSv4 acl and an owner, group, and other mask.
> These three masks correspond to the owner, group, and other file
> permission bits, but they contain NFSv4 permissions instead of POSIX
> permissions.
>
> Each entry in the NFSv4 acl applies to the file owner (OWNER@), the
> owning group (GROUP@), everyone (EVERYONE@), or to a specific uid or
> gid.
>
> As in the standard POSIX file permission model, each process is the
> owner, group, or other file class. A richacl grants a requested access
> only if the NFSv4 acl in the richacl grants the access (according to the
> NFSv4 permission check algorithm), and the file mask that applies to the
> process includes the requested permissions.
>
> Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
> Reviewed-by: J. Bruce Fields <bfields@redhat.com>
> ---
> fs/Makefile | 1 +
> fs/richacl.c | 65 ++++++++++++++++
> include/linux/richacl.h | 179 +++++++++++++++++++++++++++++++++++++++++++
> include/uapi/linux/Kbuild | 1 +
> include/uapi/linux/richacl.h | 99 ++++++++++++++++++++++++
> 5 files changed, 345 insertions(+)
> create mode 100644 fs/richacl.c
> create mode 100644 include/linux/richacl.h
> create mode 100644 include/uapi/linux/richacl.h
>
> diff --git a/fs/Makefile b/fs/Makefile
> index 85b6e13..2b3e6f1 100644
> --- a/fs/Makefile
> +++ b/fs/Makefile
> @@ -49,6 +49,7 @@ obj-$(CONFIG_COREDUMP) += coredump.o
> obj-$(CONFIG_SYSCTL) += drop_caches.o
>
> obj-$(CONFIG_FHANDLE) += fhandle.o
> +obj-$(CONFIG_FS_RICHACL) += richacl.o
>
> obj-y += quota/
>
> diff --git a/fs/richacl.c b/fs/richacl.c
> new file mode 100644
> index 0000000..bcc6591
> --- /dev/null
> +++ b/fs/richacl.c
> @@ -0,0 +1,65 @@
> +/*
> + * Copyright (C) 2006, 2010 Novell, Inc.
> + * Copyright (C) 2015 Red Hat, Inc.
> + * Written by Andreas Gruenbacher <agruenba@redhat.com>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; either version 2, or (at your option) any
> + * later version.
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * General Public License for more details.
> + */
> +
> +#include
> +#include
> +#include
> +#include
> +#include
> +
> +/**
> + * richacl_alloc - allocate a richacl
> + * @count: number of entries
> + */
> +struct richacl *
> +richacl_alloc(int count, gfp_t gfp)
> +{
> + size_t size = sizeof(struct richacl) + count * sizeof(struct richace);
> + struct richacl *acl = kzalloc(size, gfp);
> +
> + if (acl) {
> + atomic_set(&acl->a_refcount, 1);
> + acl->a_count = count;
> + }
> + return acl;
> +}
> +EXPORT_SYMBOL_GPL(richacl_alloc);
> +
I imagine we could have a lot of these at any given time. It might be
nice to consider how to do this with dedicated slabcaches for better
packing, but I think that would add to the complexity, unfortunately.
> +/**
> + * richacl_clone - create a copy of a richacl
> + */
> +struct richacl *
> +richacl_clone(const struct richacl *acl, gfp_t gfp)
> +{
> + int count = acl->a_count;
> + size_t size = sizeof(struct richacl) + count * sizeof(struct richace);
> + struct richacl *dup = kmalloc(size, gfp);
> +
> + if (dup) {
> + memcpy(dup, acl, size);
> + atomic_set(&dup->a_refcount, 1);
> + }
> + return dup;
> +}
> +
> +/**
> + * richace_copy - copy an acl entry
> + */
> +void
> +richace_copy(struct richace *to, const struct richace *from)
> +{
> + memcpy(to, from, sizeof(struct richace));
> +}
> diff --git a/include/linux/richacl.h b/include/linux/richacl.h
> new file mode 100644
> index 0000000..edb8480
> --- /dev/null
> +++ b/include/linux/richacl.h
> @@ -0,0 +1,179 @@
> +/*
> + * Copyright (C) 2006, 2010 Novell, Inc.
> + * Copyright (C) 2015 Red Hat, Inc.
> + * Written by Andreas Gruenbacher <agruenba@redhat.com>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; either version 2, or (at your option) any
> + * later version.
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * General Public License for more details.
> + */
> +
> +#ifndef __RICHACL_H
> +#define __RICHACL_H
> +
> +#include
> +
> +struct richace {
> + unsigned short e_type;
> + unsigned short e_flags;
> + unsigned int e_mask;
> + union {
> + kuid_t uid;
> + kgid_t gid;
> + unsigned int special;
> + } e_id;
> +};
> +
> +struct richacl {
> + atomic_t a_refcount;
> + unsigned int a_owner_mask;
> + unsigned int a_group_mask;
> + unsigned int a_other_mask;
> + unsigned short a_count;
> + unsigned short a_flags;
> + struct richace a_entries[0];
> +};
> +
> +#define richacl_for_each_entry(_ace, _acl) \
> + for (_ace = (_acl)->a_entries; \
> + _ace != (_acl)->a_entries + (_acl)->a_count; \
> + _ace++)
> +
> +#define richacl_for_each_entry_reverse(_ace, _acl) \
> + for (_ace = (_acl)->a_entries + (_acl)->a_count - 1; \
> + _ace != (_acl)->a_entries - 1; \
> + _ace--)
> +
> +/**
> + * richacl_get - grab another reference to a richacl handle
> + */
> +static inline struct richacl *
> +richacl_get(struct richacl *acl)
> +{
> + if (acl)
> + atomic_inc(&acl->a_refcount);
> + return acl;
> +}
> +
> +/**
> + * richacl_put - free a richacl handle
> + */
> +static inline void
> +richacl_put(struct richacl *acl)
> +{
> + if (acl && atomic_dec_and_test(&acl->a_refcount))
> + kfree(acl);
> +}
> +
> +/**
> + * richace_is_owner - check if @ace is an OWNER@ entry
> + */
> +static inline bool
> +richace_is_owner(const struct richace *ace)
> +{
> + return (ace->e_flags & RICHACE_SPECIAL_WHO) &&
> + ace->e_id.special == RICHACE_OWNER_SPECIAL_ID;
> +}
> +
> +/**
> + * richace_is_group - check if @ace is a GROUP@ entry
> + */
> +static inline bool
> +richace_is_group(const struct richace *ace)
> +{
> + return (ace->e_flags & RICHACE_SPECIAL_WHO) &&
> + ace->e_id.special == RICHACE_GROUP_SPECIAL_ID;
> +}
> +
> +/**
> + * richace_is_everyone - check if @ace is an EVERYONE@ entry
> + */
> +static inline bool
> +richace_is_everyone(const struct richace *ace)
> +{
> + return (ace->e_flags & RICHACE_SPECIAL_WHO) &&
> + ace->e_id.special == RICHACE_EVERYONE_SPECIAL_ID;
> +}
> +
> +/**
> + * richace_is_unix_user - check if @ace applies to a specific user
> + */
> +static inline bool
> +richace_is_unix_user(const struct richace *ace)
> +{
> + return !(ace->e_flags & RICHACE_SPECIAL_WHO) &&
> + !(ace->e_flags & RICHACE_IDENTIFIER_GROUP);
> +}
> +
> +/**
> + * richace_is_unix_group - check if @ace applies to a specific group
> + */
> +static inline bool
> +richace_is_unix_group(const struct richace *ace)
> +{
> + return !(ace->e_flags & RICHACE_SPECIAL_WHO) &&
> + (ace->e_flags & RICHACE_IDENTIFIER_GROUP);
> +}
> +
> +/**
> + * richace_is_inherit_only - check if @ace is for inheritance only
> + *
> + * ACEs with the %RICHACE_INHERIT_ONLY_ACE flag set have no effect during
> + * permission checking.
> + */
> +static inline bool
> +richace_is_inherit_only(const struct richace *ace)
> +{
> + return ace->e_flags & RICHACE_INHERIT_ONLY_ACE;
> +}
> +
> +/**
> + * richace_is_inheritable - check if @ace is inheritable
> + */
> +static inline bool
> +richace_is_inheritable(const struct richace *ace)
> +{
> + return ace->e_flags & (RICHACE_FILE_INHERIT_ACE |
> + RICHACE_DIRECTORY_INHERIT_ACE);
> +}
> +
> +/**
> + * richace_is_allow - check if @ace is an %ALLOW type entry
> + */
> +static inline bool
> +richace_is_allow(const struct richace *ace)
> +{
> + return ace->e_type == RICHACE_ACCESS_ALLOWED_ACE_TYPE;
> +}
> +
> +/**
> + * richace_is_deny - check if @ace is a %DENY type entry
> + */
> +static inline bool
> +richace_is_deny(const struct richace *ace)
> +{
> + return ace->e_type == RICHACE_ACCESS_DENIED_ACE_TYPE;
> +}
> +
> +/**
> + * richace_is_same_identifier - are both identifiers the same?
> + */
> +static inline bool
> +richace_is_same_identifier(const struct richace *a, const struct richace *b)
> +{
> + return !((a->e_flags ^ b->e_flags) &
> + (RICHACE_SPECIAL_WHO | RICHACE_IDENTIFIER_GROUP)) &&
> + !memcmp(&a->e_id, &b->e_id, sizeof(a->e_id));
> +}
> +
> +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 *);
> +
> +#endif /* __RICHACL_H */
> diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
> index 8bdae34..abeaa98 100644
> --- a/include/uapi/linux/Kbuild
> +++ b/include/uapi/linux/Kbuild
> @@ -355,6 +355,7 @@ header-y += reboot.h
> header-y += reiserfs_fs.h
> header-y += reiserfs_xattr.h
> header-y += resource.h
> +header-y += richacl.h
> header-y += rfkill.h
> header-y += rio_mport_cdev.h
> header-y += romfs_fs.h
> diff --git a/include/uapi/linux/richacl.h b/include/uapi/linux/richacl.h
> new file mode 100644
> index 0000000..08856f8
> --- /dev/null
> +++ b/include/uapi/linux/richacl.h
> @@ -0,0 +1,99 @@
> +/*
> + * Copyright (C) 2006, 2010 Novell, Inc.
> + * Copyright (C) 2015 Red Hat, Inc.
> + * Written by Andreas Gruenbacher <agruenba@redhat.com>
> + *
> + * This file is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This file is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * Lesser General Public License for more details.
> + */
> +
> +#ifndef __UAPI_RICHACL_H
> +#define __UAPI_RICHACL_H
> +
> +/* a_flags values */
> +#define RICHACL_WRITE_THROUGH 0x40
> +#define RICHACL_MASKED 0x80
> +
> +/* e_type values */
> +#define RICHACE_ACCESS_ALLOWED_ACE_TYPE 0x0000
> +#define RICHACE_ACCESS_DENIED_ACE_TYPE 0x0001
> +
> +/* e_flags bitflags */
> +#define RICHACE_FILE_INHERIT_ACE 0x0001
> +#define RICHACE_DIRECTORY_INHERIT_ACE 0x0002
> +#define RICHACE_NO_PROPAGATE_INHERIT_ACE 0x0004
> +#define RICHACE_INHERIT_ONLY_ACE 0x0008
> +#define RICHACE_IDENTIFIER_GROUP 0x0040
> +#define RICHACE_SPECIAL_WHO 0x4000
> +
> +/* e_mask bitflags */
> +#define RICHACE_READ_DATA 0x00000001
> +#define RICHACE_LIST_DIRECTORY 0x00000001
> +#define RICHACE_WRITE_DATA 0x00000002
> +#define RICHACE_ADD_FILE 0x00000002
> +#define RICHACE_APPEND_DATA 0x00000004
> +#define RICHACE_ADD_SUBDIRECTORY 0x00000004
> +#define RICHACE_READ_NAMED_ATTRS 0x00000008
> +#define RICHACE_WRITE_NAMED_ATTRS 0x00000010
> +#define RICHACE_EXECUTE 0x00000020
> +#define RICHACE_DELETE_CHILD 0x00000040
> +#define RICHACE_READ_ATTRIBUTES 0x00000080
> +#define RICHACE_WRITE_ATTRIBUTES 0x00000100
> +#define RICHACE_WRITE_RETENTION 0x00000200
> +#define RICHACE_WRITE_RETENTION_HOLD 0x00000400
> +#define RICHACE_DELETE 0x00010000
> +#define RICHACE_READ_ACL 0x00020000
> +#define RICHACE_WRITE_ACL 0x00040000
> +#define RICHACE_WRITE_OWNER 0x00080000
> +#define RICHACE_SYNCHRONIZE 0x00100000
> +
> +/* e_id values */
> +#define RICHACE_OWNER_SPECIAL_ID 0
> +#define RICHACE_GROUP_SPECIAL_ID 1
> +#define RICHACE_EVERYONE_SPECIAL_ID 2
> +
> +#define RICHACL_VALID_FLAGS ( \
> + RICHACL_WRITE_THROUGH | \
> + RICHACL_MASKED )
> +
> +#define RICHACE_VALID_FLAGS ( \
> + RICHACE_FILE_INHERIT_ACE | \
> + RICHACE_DIRECTORY_INHERIT_ACE | \
> + RICHACE_NO_PROPAGATE_INHERIT_ACE | \
> + RICHACE_INHERIT_ONLY_ACE | \
> + RICHACE_IDENTIFIER_GROUP | \
> + RICHACE_SPECIAL_WHO )
> +
> +#define RICHACE_INHERITANCE_FLAGS ( \
> + RICHACE_FILE_INHERIT_ACE | \
> + RICHACE_DIRECTORY_INHERIT_ACE | \
> + RICHACE_NO_PROPAGATE_INHERIT_ACE | \
> + RICHACE_INHERIT_ONLY_ACE )
> +
> +/* Valid RICHACE_* flags for directories and non-directories */
> +#define RICHACE_VALID_MASK ( \
> + RICHACE_READ_DATA | RICHACE_LIST_DIRECTORY | \
> + RICHACE_WRITE_DATA | RICHACE_ADD_FILE | \
> + RICHACE_APPEND_DATA | RICHACE_ADD_SUBDIRECTORY | \
> + RICHACE_READ_NAMED_ATTRS | \
> + RICHACE_WRITE_NAMED_ATTRS | \
> + RICHACE_EXECUTE | \
> + RICHACE_DELETE_CHILD | \
> + RICHACE_READ_ATTRIBUTES | \
> + RICHACE_WRITE_ATTRIBUTES | \
> + RICHACE_WRITE_RETENTION | \
> + RICHACE_WRITE_RETENTION_HOLD | \
> + RICHACE_DELETE | \
> + RICHACE_READ_ACL | \
> + RICHACE_WRITE_ACL | \
> + RICHACE_WRITE_OWNER | \
> + RICHACE_SYNCHRONIZE )
> +
> +#endif /* __UAPI_RICHACL_H */
Reviewed-by: Jeff Layton <jlayton@redhat.com>
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2016-07-11 12:20 +0200 |
| Subject | Re: [PATCH v23 06/22] richacl: In-memory representation and helper functions |
| Message-ID | <rTGtH-5FU-5@gated-at.bofh.it> |
| In reply to | #1436939 |
On Tue, Jul 5, 2016 at 1:34 PM, Jeff Layton <jlayton@redhat.com> wrote:
> On Thu, 2016-06-30 at 15:46 +0200, Andreas Gruenbacher wrote:
>> A richacl consists of an NFSv4 acl and an owner, group, and other mask.
>> These three masks correspond to the owner, group, and other file
>> permission bits, but they contain NFSv4 permissions instead of POSIX
>> permissions.
>>
>> Each entry in the NFSv4 acl applies to the file owner (OWNER@), the
>> owning group (GROUP@), everyone (EVERYONE@), or to a specific uid or
>> gid.
>>
>> As in the standard POSIX file permission model, each process is the
>> owner, group, or other file class. A richacl grants a requested access
>> only if the NFSv4 acl in the richacl grants the access (according to the
>> NFSv4 permission check algorithm), and the file mask that applies to the
>> process includes the requested permissions.
>>
>> Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
>> Reviewed-by: J. Bruce Fields <bfields@redhat.com>
>> ---
>> fs/Makefile | 1 +
>> fs/richacl.c | 65 ++++++++++++++++
>> include/linux/richacl.h | 179 +++++++++++++++++++++++++++++++++++++++++++
>> include/uapi/linux/Kbuild | 1 +
>> include/uapi/linux/richacl.h | 99 ++++++++++++++++++++++++
>> 5 files changed, 345 insertions(+)
>> create mode 100644 fs/richacl.c
>> create mode 100644 include/linux/richacl.h
>> create mode 100644 include/uapi/linux/richacl.h
>>
>> diff --git a/fs/Makefile b/fs/Makefile
>> index 85b6e13..2b3e6f1 100644
>> --- a/fs/Makefile
>> +++ b/fs/Makefile
>> @@ -49,6 +49,7 @@ obj-$(CONFIG_COREDUMP) += coredump.o
>> obj-$(CONFIG_SYSCTL) += drop_caches.o
>>
>> obj-$(CONFIG_FHANDLE) += fhandle.o
>> +obj-$(CONFIG_FS_RICHACL) += richacl.o
>>
>> obj-y += quota/
>>
>> diff --git a/fs/richacl.c b/fs/richacl.c
>> new file mode 100644
>> index 0000000..bcc6591
>> --- /dev/null
>> +++ b/fs/richacl.c
>> @@ -0,0 +1,65 @@
>> +/*
>> + * Copyright (C) 2006, 2010 Novell, Inc.
>> + * Copyright (C) 2015 Red Hat, Inc.
>> + * Written by Andreas Gruenbacher <agruenba@redhat.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License as published by the
>> + * Free Software Foundation; either version 2, or (at your option) any
>> + * later version.
>> + *
>> + * This program is distributed in the hope that it will be useful, but
>> + * WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
>> + * General Public License for more details.
>> + */
>> +
>> +#include
>> +#include
>> +#include
>> +#include
>> +#include
>> +
>> +/**
>> + * richacl_alloc - allocate a richacl
>> + * @count: number of entries
>> + */
>> +struct richacl *
>> +richacl_alloc(int count, gfp_t gfp)
>> +{
>> + size_t size = sizeof(struct richacl) + count * sizeof(struct richace);
>> + struct richacl *acl = kzalloc(size, gfp);
>> +
>> + if (acl) {
>> + atomic_set(&acl->a_refcount, 1);
>> + acl->a_count = count;
>> + }
>> + return acl;
>> +}
>> +EXPORT_SYMBOL_GPL(richacl_alloc);
>> +
>
> I imagine we could have a lot of these at any given time. It might be
> nice to consider how to do this with dedicated slabcaches for better
> packing, but I think that would add to the complexity, unfortunately.
The objects are variable in size, so that wouldn't work.
>> +/**
>> + * richacl_clone - create a copy of a richacl
>> + */
>> +struct richacl *
>> +richacl_clone(const struct richacl *acl, gfp_t gfp)
>> +{
>> + int count = acl->a_count;
>> + size_t size = sizeof(struct richacl) + count * sizeof(struct richace);
>> + struct richacl *dup = kmalloc(size, gfp);
>> +
>> + if (dup) {
>> + memcpy(dup, acl, size);
>> + atomic_set(&dup->a_refcount, 1);
>> + }
>> + return dup;
>> +}
>> +
>> +/**
>> + * richace_copy - copy an acl entry
>> + */
>> +void
>> +richace_copy(struct richace *to, const struct richace *from)
>> +{
>> + memcpy(to, from, sizeof(struct richace));
>> +}
>> diff --git a/include/linux/richacl.h b/include/linux/richacl.h
>> new file mode 100644
>> index 0000000..edb8480
>> --- /dev/null
>> +++ b/include/linux/richacl.h
>> @@ -0,0 +1,179 @@
>> +/*
>> + * Copyright (C) 2006, 2010 Novell, Inc.
>> + * Copyright (C) 2015 Red Hat, Inc.
>> + * Written by Andreas Gruenbacher <agruenba@redhat.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License as published by the
>> + * Free Software Foundation; either version 2, or (at your option) any
>> + * later version.
>> + *
>> + * This program is distributed in the hope that it will be useful, but
>> + * WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
>> + * General Public License for more details.
>> + */
>> +
>> +#ifndef __RICHACL_H
>> +#define __RICHACL_H
>> +
>> +#include
>> +
>> +struct richace {
>> + unsigned short e_type;
>> + unsigned short e_flags;
>> + unsigned int e_mask;
>> + union {
>> + kuid_t uid;
>> + kgid_t gid;
>> + unsigned int special;
>> + } e_id;
>> +};
>> +
>> +struct richacl {
>> + atomic_t a_refcount;
>> + unsigned int a_owner_mask;
>> + unsigned int a_group_mask;
>> + unsigned int a_other_mask;
>> + unsigned short a_count;
>> + unsigned short a_flags;
>> + struct richace a_entries[0];
>> +};
>> +
>> +#define richacl_for_each_entry(_ace, _acl) \
>> + for (_ace = (_acl)->a_entries; \
>> + _ace != (_acl)->a_entries + (_acl)->a_count; \
>> + _ace++)
>> +
>> +#define richacl_for_each_entry_reverse(_ace, _acl) \
>> + for (_ace = (_acl)->a_entries + (_acl)->a_count - 1; \
>> + _ace != (_acl)->a_entries - 1; \
>> + _ace--)
>> +
>> +/**
>> + * richacl_get - grab another reference to a richacl handle
>> + */
>> +static inline struct richacl *
>> +richacl_get(struct richacl *acl)
>> +{
>> + if (acl)
>> + atomic_inc(&acl->a_refcount);
>> + return acl;
>> +}
>> +
>> +/**
>> + * richacl_put - free a richacl handle
>> + */
>> +static inline void
>> +richacl_put(struct richacl *acl)
>> +{
>> + if (acl && atomic_dec_and_test(&acl->a_refcount))
>> + kfree(acl);
>> +}
>> +
>> +/**
>> + * richace_is_owner - check if @ace is an OWNER@ entry
>> + */
>> +static inline bool
>> +richace_is_owner(const struct richace *ace)
>> +{
>> + return (ace->e_flags & RICHACE_SPECIAL_WHO) &&
>> + ace->e_id.special == RICHACE_OWNER_SPECIAL_ID;
>> +}
>> +
>> +/**
>> + * richace_is_group - check if @ace is a GROUP@ entry
>> + */
>> +static inline bool
>> +richace_is_group(const struct richace *ace)
>> +{
>> + return (ace->e_flags & RICHACE_SPECIAL_WHO) &&
>> + ace->e_id.special == RICHACE_GROUP_SPECIAL_ID;
>> +}
>> +
>> +/**
>> + * richace_is_everyone - check if @ace is an EVERYONE@ entry
>> + */
>> +static inline bool
>> +richace_is_everyone(const struct richace *ace)
>> +{
>> + return (ace->e_flags & RICHACE_SPECIAL_WHO) &&
>> + ace->e_id.special == RICHACE_EVERYONE_SPECIAL_ID;
>> +}
>> +
>> +/**
>> + * richace_is_unix_user - check if @ace applies to a specific user
>> + */
>> +static inline bool
>> +richace_is_unix_user(const struct richace *ace)
>> +{
>> + return !(ace->e_flags & RICHACE_SPECIAL_WHO) &&
>> + !(ace->e_flags & RICHACE_IDENTIFIER_GROUP);
>> +}
>> +
>> +/**
>> + * richace_is_unix_group - check if @ace applies to a specific group
>> + */
>> +static inline bool
>> +richace_is_unix_group(const struct richace *ace)
>> +{
>> + return !(ace->e_flags & RICHACE_SPECIAL_WHO) &&
>> + (ace->e_flags & RICHACE_IDENTIFIER_GROUP);
>> +}
>> +
>> +/**
>> + * richace_is_inherit_only - check if @ace is for inheritance only
>> + *
>> + * ACEs with the %RICHACE_INHERIT_ONLY_ACE flag set have no effect during
>> + * permission checking.
>> + */
>> +static inline bool
>> +richace_is_inherit_only(const struct richace *ace)
>> +{
>> + return ace->e_flags & RICHACE_INHERIT_ONLY_ACE;
>> +}
>> +
>> +/**
>> + * richace_is_inheritable - check if @ace is inheritable
>> + */
>> +static inline bool
>> +richace_is_inheritable(const struct richace *ace)
>> +{
>> + return ace->e_flags & (RICHACE_FILE_INHERIT_ACE |
>> + RICHACE_DIRECTORY_INHERIT_ACE);
>> +}
>> +
>> +/**
>> + * richace_is_allow - check if @ace is an %ALLOW type entry
>> + */
>> +static inline bool
>> +richace_is_allow(const struct richace *ace)
>> +{
>> + return ace->e_type == RICHACE_ACCESS_ALLOWED_ACE_TYPE;
>> +}
>> +
>> +/**
>> + * richace_is_deny - check if @ace is a %DENY type entry
>> + */
>> +static inline bool
>> +richace_is_deny(const struct richace *ace)
>> +{
>> + return ace->e_type == RICHACE_ACCESS_DENIED_ACE_TYPE;
>> +}
>> +
>> +/**
>> + * richace_is_same_identifier - are both identifiers the same?
>> + */
>> +static inline bool
>> +richace_is_same_identifier(const struct richace *a, const struct richace *b)
>> +{
>> + return !((a->e_flags ^ b->e_flags) &
>> + (RICHACE_SPECIAL_WHO | RICHACE_IDENTIFIER_GROUP)) &&
>> + !memcmp(&a->e_id, &b->e_id, sizeof(a->e_id));
>> +}
>> +
>> +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 *);
>> +
>> +#endif /* __RICHACL_H */
>> diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
>> index 8bdae34..abeaa98 100644
>> --- a/include/uapi/linux/Kbuild
>> +++ b/include/uapi/linux/Kbuild
>> @@ -355,6 +355,7 @@ header-y += reboot.h
>> header-y += reiserfs_fs.h
>> header-y += reiserfs_xattr.h
>> header-y += resource.h
>> +header-y += richacl.h
>> header-y += rfkill.h
>> header-y += rio_mport_cdev.h
>> header-y += romfs_fs.h
>> diff --git a/include/uapi/linux/richacl.h b/include/uapi/linux/richacl.h
>> new file mode 100644
>> index 0000000..08856f8
>> --- /dev/null
>> +++ b/include/uapi/linux/richacl.h
>> @@ -0,0 +1,99 @@
>> +/*
>> + * Copyright (C) 2006, 2010 Novell, Inc.
>> + * Copyright (C) 2015 Red Hat, Inc.
>> + * Written by Andreas Gruenbacher <agruenba@redhat.com>
>> + *
>> + * This file is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU Lesser General Public
>> + * License as published by the Free Software Foundation; either
>> + * version 2.1 of the License, or (at your option) any later version.
>> + *
>> + * This file is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
>> + * Lesser General Public License for more details.
>> + */
>> +
>> +#ifndef __UAPI_RICHACL_H
>> +#define __UAPI_RICHACL_H
>> +
>> +/* a_flags values */
>> +#define RICHACL_WRITE_THROUGH 0x40
>> +#define RICHACL_MASKED 0x80
>> +
>> +/* e_type values */
>> +#define RICHACE_ACCESS_ALLOWED_ACE_TYPE 0x0000
>> +#define RICHACE_ACCESS_DENIED_ACE_TYPE 0x0001
>> +
>> +/* e_flags bitflags */
>> +#define RICHACE_FILE_INHERIT_ACE 0x0001
>> +#define RICHACE_DIRECTORY_INHERIT_ACE 0x0002
>> +#define RICHACE_NO_PROPAGATE_INHERIT_ACE 0x0004
>> +#define RICHACE_INHERIT_ONLY_ACE 0x0008
>> +#define RICHACE_IDENTIFIER_GROUP 0x0040
>> +#define RICHACE_SPECIAL_WHO 0x4000
>> +
>> +/* e_mask bitflags */
>> +#define RICHACE_READ_DATA 0x00000001
>> +#define RICHACE_LIST_DIRECTORY 0x00000001
>> +#define RICHACE_WRITE_DATA 0x00000002
>> +#define RICHACE_ADD_FILE 0x00000002
>> +#define RICHACE_APPEND_DATA 0x00000004
>> +#define RICHACE_ADD_SUBDIRECTORY 0x00000004
>> +#define RICHACE_READ_NAMED_ATTRS 0x00000008
>> +#define RICHACE_WRITE_NAMED_ATTRS 0x00000010
>> +#define RICHACE_EXECUTE 0x00000020
>> +#define RICHACE_DELETE_CHILD 0x00000040
>> +#define RICHACE_READ_ATTRIBUTES 0x00000080
>> +#define RICHACE_WRITE_ATTRIBUTES 0x00000100
>> +#define RICHACE_WRITE_RETENTION 0x00000200
>> +#define RICHACE_WRITE_RETENTION_HOLD 0x00000400
>> +#define RICHACE_DELETE 0x00010000
>> +#define RICHACE_READ_ACL 0x00020000
>> +#define RICHACE_WRITE_ACL 0x00040000
>> +#define RICHACE_WRITE_OWNER 0x00080000
>> +#define RICHACE_SYNCHRONIZE 0x00100000
>> +
>> +/* e_id values */
>> +#define RICHACE_OWNER_SPECIAL_ID 0
>> +#define RICHACE_GROUP_SPECIAL_ID 1
>> +#define RICHACE_EVERYONE_SPECIAL_ID 2
>> +
>> +#define RICHACL_VALID_FLAGS ( \
>> + RICHACL_WRITE_THROUGH | \
>> + RICHACL_MASKED )
>> +
>> +#define RICHACE_VALID_FLAGS ( \
>> + RICHACE_FILE_INHERIT_ACE | \
>> + RICHACE_DIRECTORY_INHERIT_ACE | \
>> + RICHACE_NO_PROPAGATE_INHERIT_ACE | \
>> + RICHACE_INHERIT_ONLY_ACE | \
>> + RICHACE_IDENTIFIER_GROUP | \
>> + RICHACE_SPECIAL_WHO )
>> +
>> +#define RICHACE_INHERITANCE_FLAGS ( \
>> + RICHACE_FILE_INHERIT_ACE | \
>> + RICHACE_DIRECTORY_INHERIT_ACE | \
>> + RICHACE_NO_PROPAGATE_INHERIT_ACE | \
>> + RICHACE_INHERIT_ONLY_ACE )
>> +
>> +/* Valid RICHACE_* flags for directories and non-directories */
>> +#define RICHACE_VALID_MASK ( \
>> + RICHACE_READ_DATA | RICHACE_LIST_DIRECTORY | \
>> + RICHACE_WRITE_DATA | RICHACE_ADD_FILE | \
>> + RICHACE_APPEND_DATA | RICHACE_ADD_SUBDIRECTORY | \
>> + RICHACE_READ_NAMED_ATTRS | \
>> + RICHACE_WRITE_NAMED_ATTRS | \
>> + RICHACE_EXECUTE | \
>> + RICHACE_DELETE_CHILD | \
>> + RICHACE_READ_ATTRIBUTES | \
>> + RICHACE_WRITE_ATTRIBUTES | \
>> + RICHACE_WRITE_RETENTION | \
>> + RICHACE_WRITE_RETENTION_HOLD | \
>> + RICHACE_DELETE | \
>> + RICHACE_READ_ACL | \
>> + RICHACE_WRITE_ACL | \
>> + RICHACE_WRITE_OWNER | \
>> + RICHACE_SYNCHRONIZE )
>> +
>> +#endif /* __UAPI_RICHACL_H */
>
> Reviewed-by: Jeff Layton <jlayton@redhat.com>
Thanks,
Andreas
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2016-06-30 16:00 +0200 |
| Subject | [PATCH v23 22/22] ext4: Add richacl feature flag |
| Message-ID | <rPKFA-1Pr-31@gated-at.bofh.it> |
| In reply to | #1434569 |
From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
This feature flag selects richacl instead of POSIX ACL support on the
filesystem. When this feature is off, the "acl" and "noacl" mount options
control whether POSIX ACLs are enabled. When it is on, richacls are
automatically enabled and using the "noacl" mount option leads to an error.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Reviewed-by: Andreas Dilger <adilger@dilger.ca>
---
fs/ext4/ext4.h | 6 ++++--
fs/ext4/super.c | 49 ++++++++++++++++++++++++++++++++++++++++---------
2 files changed, 44 insertions(+), 11 deletions(-)
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index b84aa1c..ff48f07 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1126,7 +1126,7 @@ struct ext4_inode_info {
#define EXT4_MOUNT_UPDATE_JOURNAL 0x01000 /* Update the journal format */
#define EXT4_MOUNT_NO_UID32 0x02000 /* Disable 32-bit UIDs */
#define EXT4_MOUNT_XATTR_USER 0x04000 /* Extended user attributes */
-#define EXT4_MOUNT_POSIX_ACL 0x08000 /* POSIX Access Control Lists */
+#define EXT4_MOUNT_ACL 0x08000 /* Access Control Lists */
#define EXT4_MOUNT_NO_AUTO_DA_ALLOC 0x10000 /* No auto delalloc mapping */
#define EXT4_MOUNT_BARRIER 0x20000 /* Use block barriers */
#define EXT4_MOUNT_QUOTA 0x80000 /* Some quota option set */
@@ -1707,6 +1707,7 @@ static inline int ext4_encrypted_inode(struct inode *inode)
#define EXT4_FEATURE_INCOMPAT_LARGEDIR 0x4000 /* >2GB or 3-lvl htree */
#define EXT4_FEATURE_INCOMPAT_INLINE_DATA 0x8000 /* data in inode */
#define EXT4_FEATURE_INCOMPAT_ENCRYPT 0x10000
+#define EXT4_FEATURE_INCOMPAT_RICHACL 0x20000
#define EXT4_FEATURE_COMPAT_FUNCS(name, flagname) \
static inline bool ext4_has_feature_##name(struct super_block *sb) \
@@ -1821,7 +1822,8 @@ EXT4_FEATURE_INCOMPAT_FUNCS(encrypt, ENCRYPT)
EXT4_FEATURE_INCOMPAT_MMP | \
EXT4_FEATURE_INCOMPAT_INLINE_DATA | \
EXT4_FEATURE_INCOMPAT_ENCRYPT | \
- EXT4_FEATURE_INCOMPAT_CSUM_SEED)
+ EXT4_FEATURE_INCOMPAT_CSUM_SEED | \
+ EXT4_FEATURE_INCOMPAT_RICHACL)
#define EXT4_FEATURE_RO_COMPAT_SUPP (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \
EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \
EXT4_FEATURE_RO_COMPAT_GDT_CSUM| \
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 3822a5a..122410f 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1306,6 +1306,28 @@ static ext4_fsblk_t get_sb_block(void **data)
return sb_block;
}
+static int enable_acl(struct super_block *sb)
+{
+ sb->s_flags &= ~(MS_POSIXACL | MS_RICHACL);
+ if (test_opt(sb, ACL)) {
+ if (EXT4_HAS_INCOMPAT_FEATURE(sb,
+ EXT4_FEATURE_INCOMPAT_RICHACL)) {
+#ifdef CONFIG_EXT4_FS_RICHACL
+ sb->s_flags |= MS_RICHACL;
+#else
+ return -EOPNOTSUPP;
+#endif
+ } else {
+#ifdef CONFIG_EXT4_FS_POSIX_ACL
+ sb->s_flags |= MS_POSIXACL;
+#else
+ return -EOPNOTSUPP;
+#endif
+ }
+ }
+ return 0;
+}
+
#define DEFAULT_JOURNAL_IOPRIO (IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 3))
static char deprecated_msg[] = "Mount option \"%s\" will be removed by %s\n"
"Contact linux-ext4@vger.kernel.org if you think we should keep it.\n";
@@ -1452,9 +1474,9 @@ static const struct mount_opts {
MOPT_NO_EXT2 | MOPT_DATAJ},
{Opt_user_xattr, EXT4_MOUNT_XATTR_USER, MOPT_SET},
{Opt_nouser_xattr, EXT4_MOUNT_XATTR_USER, MOPT_CLEAR},
-#ifdef CONFIG_EXT4_FS_POSIX_ACL
- {Opt_acl, EXT4_MOUNT_POSIX_ACL, MOPT_SET},
- {Opt_noacl, EXT4_MOUNT_POSIX_ACL, MOPT_CLEAR},
+#if defined(CONFIG_EXT4_FS_POSIX_ACL) || defined(CONFIG_EXT4_FS_RICHACL)
+ {Opt_acl, EXT4_MOUNT_ACL, MOPT_SET},
+ {Opt_noacl, EXT4_MOUNT_ACL, MOPT_CLEAR},
#else
{Opt_acl, 0, MOPT_NOSUPPORT},
{Opt_noacl, 0, MOPT_NOSUPPORT},
@@ -1502,6 +1524,13 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
#endif
switch (token) {
case Opt_noacl:
+#ifdef CONFIG_EXT4_FS_RICHACL
+ if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RICHACL)) {
+ ext4_msg(sb, KERN_ERR, "Mount option \"%s\" incompatible "
+ "with richacl feature", opt);
+ return -1;
+ }
+#endif
case Opt_nouser_xattr:
ext4_msg(sb, KERN_WARNING, deprecated_msg, opt, "3.5");
break;
@@ -3274,8 +3303,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
set_opt(sb, NO_UID32);
/* xattr user namespace & acls are now defaulted on */
set_opt(sb, XATTR_USER);
-#ifdef CONFIG_EXT4_FS_POSIX_ACL
- set_opt(sb, POSIX_ACL);
+#if defined(CONFIG_EXT4_FS_POSIX_ACL) || defined(CONFIG_EXT4_FS_RICHACL)
+ set_opt(sb, ACL);
#endif
/* don't forget to enable journal_csum when metadata_csum is enabled. */
if (ext4_has_metadata_csum(sb))
@@ -3358,8 +3387,9 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
sb->s_iflags |= SB_I_CGROUPWB;
}
- sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
- (test_opt(sb, POSIX_ACL) ? MS_POSIXACL : 0);
+ err = enable_acl(sb);
+ if (err)
+ goto failed_mount;
if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV &&
(ext4_has_compat_features(sb) ||
@@ -4673,8 +4703,9 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
if (sbi->s_mount_flags & EXT4_MF_FS_ABORTED)
ext4_abort(sb, "Abort forced by user");
- sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
- (test_opt(sb, POSIX_ACL) ? MS_POSIXACL : 0);
+ err = enable_acl(sb);
+ if (err)
+ goto restore_opts;
es = sbi->s_es;
--
2.5.5
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2016-06-30 16:00 +0200 |
| Subject | [PATCH v23 21/22] ext4: Add richacl support |
| Message-ID | <rPKFA-1Pr-39@gated-at.bofh.it> |
| In reply to | #1434569 |
From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
Support the richacl permission model in ext4. The richacls are stored
in "system.richacl" xattrs. Richacls need to be enabled by tune2fs or
at file system create time.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Reviewed-by: Andreas Dilger <adilger@dilger.ca>
---
fs/ext4/Kconfig | 11 +++++
fs/ext4/Makefile | 1 +
fs/ext4/file.c | 3 ++
fs/ext4/ialloc.c | 11 ++++-
fs/ext4/inode.c | 5 +-
fs/ext4/namei.c | 5 ++
fs/ext4/richacl.c | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++++
fs/ext4/richacl.h | 40 ++++++++++++++++
fs/ext4/xattr.c | 7 +++
include/linux/acl.h | 15 ++++++
10 files changed, 228 insertions(+), 4 deletions(-)
create mode 100644 fs/ext4/richacl.c
create mode 100644 fs/ext4/richacl.h
create mode 100644 include/linux/acl.h
diff --git a/fs/ext4/Kconfig b/fs/ext4/Kconfig
index b46e9fc..4e21c18 100644
--- a/fs/ext4/Kconfig
+++ b/fs/ext4/Kconfig
@@ -22,6 +22,17 @@ config EXT3_FS_POSIX_ACL
This config option is here only for backward compatibility. ext3
filesystem is now handled by the ext4 driver.
+config EXT4_FS_RICHACL
+ bool "Ext4 Rich Access Control Lists"
+ depends on EXT4_FS
+ select FS_RICHACL
+ help
+ Richacls are an implementation of NFSv4 ACLs, extended by file masks
+ to cleanly integrate into the POSIX file permission model. To learn
+ more about them, see http://www.bestbits.at/richacl/.
+
+ If you don't know what Richacls are, say N.
+
config EXT3_FS_SECURITY
bool "Ext3 Security Labels"
depends on EXT3_FS
diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile
index f52cf54..1fb7f11 100644
--- a/fs/ext4/Makefile
+++ b/fs/ext4/Makefile
@@ -14,3 +14,4 @@ ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o
ext4-$(CONFIG_EXT4_FS_SECURITY) += xattr_security.o
ext4-$(CONFIG_EXT4_FS_ENCRYPTION) += crypto_policy.o crypto.o \
crypto_key.o crypto_fname.o
+ext4-$(CONFIG_EXT4_FS_RICHACL) += richacl.o
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index df44c87..6e7b4b9 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -30,6 +30,7 @@
#include "ext4_jbd2.h"
#include "xattr.h"
#include "acl.h"
+#include "richacl.h"
/*
* Called when an inode is released. Note that this is different
@@ -717,6 +718,8 @@ const struct inode_operations ext4_file_inode_operations = {
.removexattr = generic_removexattr,
.get_acl = ext4_get_acl,
.set_acl = ext4_set_acl,
+ .get_richacl = ext4_get_richacl,
+ .set_richacl = ext4_set_richacl,
.fiemap = ext4_fiemap,
};
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index 3da4cf8..5bd382a 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -27,6 +27,7 @@
#include "ext4_jbd2.h"
#include "xattr.h"
#include "acl.h"
+#include "richacl.h"
#include <trace/events/ext4.h>
@@ -729,6 +730,14 @@ out:
return ret;
}
+static inline int
+ext4_new_acl(handle_t *handle, struct inode *inode, struct inode *dir)
+{
+ if (IS_RICHACL(dir))
+ return ext4_init_richacl(handle, inode, dir);
+ return ext4_init_acl(handle, inode, dir);
+}
+
/*
* There are two policies for allocating an inode. If the new inode is
* a directory, then a forward search is made for a block group with both
@@ -1093,7 +1102,7 @@ got:
if (err)
goto fail_drop;
- err = ext4_init_acl(handle, inode, dir);
+ err = ext4_new_acl(handle, inode, dir);
if (err)
goto fail_free_drop;
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index f7140ca..7b8d96f 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -37,10 +37,10 @@
#include <linux/printk.h>
#include <linux/slab.h>
#include <linux/bitops.h>
+#include <linux/acl.h>
#include "ext4_jbd2.h"
#include "xattr.h"
-#include "acl.h"
#include "truncate.h"
#include <trace/events/ext4.h>
@@ -5183,8 +5183,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
ext4_orphan_del(NULL, inode);
if (!rc && (ia_valid & ATTR_MODE))
- rc = posix_acl_chmod(inode, inode->i_mode);
-
+ rc = acl_chmod(inode);
err_out:
ext4_std_error(inode->i_sb, error);
if (!error)
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index ec4c399..09e36b7 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -38,6 +38,7 @@
#include "xattr.h"
#include "acl.h"
+#include "richacl.h"
#include <trace/events/ext4.h>
/*
@@ -3893,6 +3894,8 @@ const struct inode_operations ext4_dir_inode_operations = {
.removexattr = generic_removexattr,
.get_acl = ext4_get_acl,
.set_acl = ext4_set_acl,
+ .get_richacl = ext4_get_richacl,
+ .set_richacl = ext4_set_richacl,
.fiemap = ext4_fiemap,
};
@@ -3904,4 +3907,6 @@ const struct inode_operations ext4_special_inode_operations = {
.removexattr = generic_removexattr,
.get_acl = ext4_get_acl,
.set_acl = ext4_set_acl,
+ .get_richacl = ext4_get_richacl,
+ .set_richacl = ext4_set_richacl,
};
diff --git a/fs/ext4/richacl.c b/fs/ext4/richacl.c
new file mode 100644
index 0000000..0c316ff
--- /dev/null
+++ b/fs/ext4/richacl.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright IBM Corporation, 2010
+ * Copyright (C) 2015 Red Hat, Inc.
+ * Author: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>,
+ * Andreas Gruenbacher <agruenba@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/richacl_xattr.h>
+
+#include "ext4.h"
+#include "ext4_jbd2.h"
+#include "xattr.h"
+#include "acl.h"
+#include "richacl.h"
+
+struct richacl *
+ext4_get_richacl(struct inode *inode)
+{
+ const int name_index = EXT4_XATTR_INDEX_RICHACL;
+ void *value = NULL;
+ struct richacl *acl = NULL;
+ int retval;
+
+ retval = ext4_xattr_get(inode, name_index, "", NULL, 0);
+ if (retval > 0) {
+ value = kmalloc(retval, GFP_NOFS);
+ if (!value)
+ return ERR_PTR(-ENOMEM);
+ retval = ext4_xattr_get(inode, name_index, "", value, retval);
+ }
+ if (retval > 0)
+ acl = richacl_from_xattr(&init_user_ns, value, retval, -EIO);
+ else if (retval != -ENODATA && retval != -ENOSYS)
+ acl = ERR_PTR(retval);
+ kfree(value);
+
+ return acl;
+}
+
+static int
+__ext4_remove_richacl(handle_t *handle, struct inode *inode)
+{
+ const int name_index = EXT4_XATTR_INDEX_RICHACL;
+ int retval;
+
+ retval = ext4_xattr_set_handle(handle, inode, name_index, "",
+ NULL, 0, 0);
+ if (!retval)
+ set_cached_richacl(inode, NULL);
+ return retval;
+}
+
+static int
+__ext4_set_richacl(handle_t *handle, struct inode *inode, struct richacl *acl)
+{
+ const int name_index = EXT4_XATTR_INDEX_RICHACL;
+ umode_t mode = inode->i_mode;
+ int retval, size;
+ void *value;
+
+ if (richacl_equiv_mode(acl, &mode) == 0) {
+ inode->i_ctime = ext4_current_time(inode);
+ inode->i_mode = mode;
+ ext4_mark_inode_dirty(handle, inode);
+ return __ext4_remove_richacl(handle, inode);
+ }
+
+ mode &= ~S_IRWXUGO;
+ mode |= richacl_masks_to_mode(acl);
+
+ size = richacl_xattr_size(acl);
+ value = kmalloc(size, GFP_NOFS);
+ if (!value)
+ return -ENOMEM;
+ richacl_to_xattr(&init_user_ns, acl, value, size);
+ inode->i_mode = mode;
+ retval = ext4_xattr_set_handle(handle, inode, name_index, "",
+ value, size, 0);
+ kfree(value);
+ if (retval)
+ return retval;
+
+ set_cached_richacl(inode, acl);
+
+ return 0;
+}
+
+int
+ext4_set_richacl(struct inode *inode, struct richacl *acl)
+{
+ handle_t *handle;
+ int retval, retries = 0;
+
+retry:
+ handle = ext4_journal_start(inode, EXT4_HT_XATTR,
+ ext4_jbd2_credits_xattr(inode));
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+
+ if (acl)
+ retval = __ext4_set_richacl(handle, inode, acl);
+ else
+ retval = __ext4_remove_richacl(handle, inode);
+
+ ext4_journal_stop(handle);
+ if (retval == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
+ goto retry;
+ return retval;
+}
+
+int
+ext4_init_richacl(handle_t *handle, struct inode *inode, struct inode *dir)
+{
+ struct richacl *acl = richacl_create(&inode->i_mode, dir);
+ int error;
+
+ error = PTR_ERR(acl);
+ if (!IS_ERR_OR_NULL(acl)) {
+ error = __ext4_set_richacl(handle, inode, acl);
+ richacl_put(acl);
+ }
+ return error;
+}
diff --git a/fs/ext4/richacl.h b/fs/ext4/richacl.h
new file mode 100644
index 0000000..6fe9a92
--- /dev/null
+++ b/fs/ext4/richacl.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright IBM Corporation, 2010
+ * Copyright (C) 2015 Red Hat, Inc.
+ * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#ifndef __FS_EXT4_RICHACL_H
+#define __FS_EXT4_RICHACL_H
+
+#include <linux/richacl.h>
+
+#ifdef CONFIG_EXT4_FS_RICHACL
+
+extern struct richacl *ext4_get_richacl(struct inode *);
+extern int ext4_set_richacl(struct inode *, struct richacl *);
+
+extern int ext4_init_richacl(handle_t *, struct inode *, struct inode *);
+
+#else /* CONFIG_EXT4_FS_RICHACL */
+
+#define ext4_get_richacl NULL
+#define ext4_set_richacl NULL
+
+static inline int
+ext4_init_richacl(handle_t *handle, struct inode *inode, struct inode *dir)
+{
+ return 0;
+}
+
+#endif /* CONFIG_EXT4_FS_RICHACL */
+#endif /* __FS_EXT4_RICHACL_H */
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index e79bd32..e5ca483 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -55,6 +55,7 @@
#include <linux/slab.h>
#include <linux/mbcache.h>
#include <linux/quotaops.h>
+#include <linux/richacl_xattr.h>
#include "ext4_jbd2.h"
#include "ext4.h"
#include "xattr.h"
@@ -97,6 +98,9 @@ static const struct xattr_handler *ext4_xattr_handler_map[] = {
#ifdef CONFIG_EXT4_FS_SECURITY
[EXT4_XATTR_INDEX_SECURITY] = &ext4_xattr_security_handler,
#endif
+#ifdef CONFIG_EXT4_FS_RICHACL
+ [EXT4_XATTR_INDEX_RICHACL] = &richacl_xattr_handler,
+#endif
};
const struct xattr_handler *ext4_xattr_handlers[] = {
@@ -109,6 +113,9 @@ const struct xattr_handler *ext4_xattr_handlers[] = {
#ifdef CONFIG_EXT4_FS_SECURITY
&ext4_xattr_security_handler,
#endif
+#ifdef CONFIG_EXT4_FS_RICHACL
+ &richacl_xattr_handler,
+#endif
NULL
};
diff --git a/include/linux/acl.h b/include/linux/acl.h
new file mode 100644
index 0000000..3c3b5ce
--- /dev/null
+++ b/include/linux/acl.h
@@ -0,0 +1,15 @@
+#ifndef __LINUX_ACL_H
+#define __LINUX_ACL_H
+
+#include <linux/posix_acl.h>
+#include <linux/richacl.h>
+
+static inline int
+acl_chmod(struct inode *inode)
+{
+ if (IS_RICHACL(inode))
+ return richacl_chmod(inode, inode->i_mode);
+ return posix_acl_chmod(inode, inode->i_mode);
+}
+
+#endif
--
2.5.5
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2016-06-30 16:00 +0200 |
| Subject | [PATCH v23 19/22] richacl: Add richacl xattr handler |
| Message-ID | <rPKFA-1Pr-43@gated-at.bofh.it> |
| In reply to | #1434569 |
Add richacl xattr handler implementing the xattr operations based on the
get_richacl and set_richacl inode operations.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
fs/richacl.c | 22 ++++++++++++++++
fs/richacl_xattr.c | 61 +++++++++++++++++++++++++++++++++++++++++++
include/linux/richacl.h | 1 +
include/linux/richacl_xattr.h | 2 ++
4 files changed, 86 insertions(+)
diff --git a/fs/richacl.c b/fs/richacl.c
index 40e4af9..b7d7104 100644
--- a/fs/richacl.c
+++ b/fs/richacl.c
@@ -549,6 +549,28 @@ out:
EXPORT_SYMBOL_GPL(richacl_permission);
/**
+ * set_richacl - set the richacl of an inode
+ * @inode: inode whose richacl to set
+ * @acl: access control list
+ */
+int
+set_richacl(struct inode *inode, struct richacl *acl)
+{
+ if (!IS_RICHACL(inode))
+ return -EOPNOTSUPP;
+ if (!inode->i_op->set_richacl)
+ return -EOPNOTSUPP;
+
+ if (!uid_eq(current_fsuid(), inode->i_uid) &&
+ inode_permission(inode, MAY_CHMOD) &&
+ !capable(CAP_FOWNER))
+ return -EPERM;
+
+ return inode->i_op->set_richacl(inode, acl);
+}
+EXPORT_SYMBOL(set_richacl);
+
+/**
* __richacl_chmod - update the file masks to reflect the new mode
* @acl: access control list
* @mode: new file permission bits including the file type
diff --git a/fs/richacl_xattr.c b/fs/richacl_xattr.c
index dc1ad36..5eb4aba 100644
--- a/fs/richacl_xattr.c
+++ b/fs/richacl_xattr.c
@@ -18,7 +18,9 @@
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/module.h>
+#include <linux/xattr.h>
#include <linux/richacl_xattr.h>
+#include <uapi/linux/xattr.h>
/**
* richacl_from_xattr - convert a richacl xattr into the in-memory representation
@@ -159,3 +161,62 @@ richacl_to_xattr(struct user_namespace *user_ns,
return real_size;
}
EXPORT_SYMBOL_GPL(richacl_to_xattr);
+
+static bool
+richacl_xattr_list(struct dentry *dentry)
+{
+ return IS_RICHACL(d_backing_inode(dentry));
+}
+
+static int
+richacl_xattr_get(const struct xattr_handler *handler,
+ struct dentry *unused, struct inode *inode,
+ const char *name, void *buffer, size_t buffer_size)
+{
+ struct richacl *acl;
+ int error;
+
+ if (*name)
+ return -EINVAL;
+ if (!IS_RICHACL(inode))
+ return -EOPNOTSUPP;
+ if (S_ISLNK(inode->i_mode))
+ return -EOPNOTSUPP;
+ acl = get_richacl(inode);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+ if (acl == NULL)
+ return -ENODATA;
+ error = richacl_to_xattr(current_user_ns(), acl, buffer, buffer_size);
+ richacl_put(acl);
+ return error;
+}
+
+static int
+richacl_xattr_set(const struct xattr_handler *handler,
+ struct dentry *unused, struct inode *inode,
+ const char *name, const void *value, size_t size,
+ int flags)
+{
+ struct richacl *acl = NULL;
+ int ret;
+
+ if (value) {
+ acl = richacl_from_xattr(current_user_ns(), value, size,
+ -EINVAL);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+ }
+
+ ret = set_richacl(inode, acl);
+ richacl_put(acl);
+ return ret;
+}
+
+struct xattr_handler richacl_xattr_handler = {
+ .name = XATTR_NAME_RICHACL,
+ .list = richacl_xattr_list,
+ .get = richacl_xattr_get,
+ .set = richacl_xattr_set,
+};
+EXPORT_SYMBOL(richacl_xattr_handler);
diff --git a/include/linux/richacl.h b/include/linux/richacl.h
index a442372..e7db066 100644
--- a/include/linux/richacl.h
+++ b/include/linux/richacl.h
@@ -206,5 +206,6 @@ extern int richacl_chmod(struct inode *, umode_t);
extern int richacl_equiv_mode(const struct richacl *, umode_t *);
extern struct richacl *richacl_inherit(const struct richacl *, int);
extern struct richacl *richacl_create(umode_t *, struct inode *);
+extern int set_richacl(struct inode *, struct richacl *);
#endif /* __RICHACL_H */
diff --git a/include/linux/richacl_xattr.h b/include/linux/richacl_xattr.h
index 0efa14b..6c6adb1 100644
--- a/include/linux/richacl_xattr.h
+++ b/include/linux/richacl_xattr.h
@@ -26,4 +26,6 @@ extern size_t richacl_xattr_size(const struct richacl *);
extern int richacl_to_xattr(struct user_namespace *, const struct richacl *,
void *, size_t);
+extern struct xattr_handler richacl_xattr_handler;
+
#endif /* __RICHACL_XATTR_H */
--
2.5.5
[toc] | [prev] | [next] | [standalone]
| From | Jeff Layton <jlayton@redhat.com> |
|---|---|
| Date | 2016-07-12 14:20 +0200 |
| Subject | Re: [PATCH v23 19/22] richacl: Add richacl xattr handler |
| Message-ID | <rU4Po-4KV-19@gated-at.bofh.it> |
| In reply to | #1434579 |
On Thu, 2016-06-30 at 15:47 +0200, Andreas Gruenbacher wrote:
> Add richacl xattr handler implementing the xattr operations based on the
> get_richacl and set_richacl inode operations.
>
> Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
> ---
> fs/richacl.c | 22 ++++++++++++++++
> fs/richacl_xattr.c | 61 +++++++++++++++++++++++++++++++++++++++++++
> include/linux/richacl.h | 1 +
> include/linux/richacl_xattr.h | 2 ++
> 4 files changed, 86 insertions(+)
>
> diff --git a/fs/richacl.c b/fs/richacl.c
> index 40e4af9..b7d7104 100644
> --- a/fs/richacl.c
> +++ b/fs/richacl.c
> @@ -549,6 +549,28 @@ out:
> EXPORT_SYMBOL_GPL(richacl_permission);
>
> /**
> + * set_richacl - set the richacl of an inode
> + * @inode: inode whose richacl to set
> + * @acl: access control list
> + */
> +int
> +set_richacl(struct inode *inode, struct richacl *acl)
> +{
> + if (!IS_RICHACL(inode))
> + return -EOPNOTSUPP;
> + if (!inode->i_op->set_richacl)
> + return -EOPNOTSUPP;
> +
> + if (!uid_eq(current_fsuid(), inode->i_uid) &&
> + inode_permission(inode, MAY_CHMOD) &&
> + !capable(CAP_FOWNER))
> + return -EPERM;
> +
> + return inode->i_op->set_richacl(inode, acl);
> +}
> +EXPORT_SYMBOL(set_richacl);
> +
> +/**
> * __richacl_chmod - update the file masks to reflect the new mode
> * @acl: access control list
> * @mode: new file permission bits including the file type
> diff --git a/fs/richacl_xattr.c b/fs/richacl_xattr.c
> index dc1ad36..5eb4aba 100644
> --- a/fs/richacl_xattr.c
> +++ b/fs/richacl_xattr.c
> @@ -18,7 +18,9 @@
> #include
> #include
> #include
> +#include
> #include
> +#include
>
> /**
> * richacl_from_xattr - convert a richacl xattr into the in-memory representation
> @@ -159,3 +161,62 @@ richacl_to_xattr(struct user_namespace *user_ns,
> return real_size;
> }
> EXPORT_SYMBOL_GPL(richacl_to_xattr);
> +
> +static bool
> +richacl_xattr_list(struct dentry *dentry)
> +{
> + return IS_RICHACL(d_backing_inode(dentry));
> +}
> +
> +static int
> +richacl_xattr_get(const struct xattr_handler *handler,
> + struct dentry *unused, struct inode *inode,
> + const char *name, void *buffer, size_t buffer_size)
> +{
> + struct richacl *acl;
> + int error;
> +
> + if (*name)
> + return -EINVAL;
> + if (!IS_RICHACL(inode))
> + return -EOPNOTSUPP;
> + if (S_ISLNK(inode->i_mode))
> + return -EOPNOTSUPP;
> + acl = get_richacl(inode);
> + if (IS_ERR(acl))
> + return PTR_ERR(acl);
> + if (acl == NULL)
> + return -ENODATA;
> + error = richacl_to_xattr(current_user_ns(), acl, buffer, buffer_size);
> + richacl_put(acl);
> + return error;
> +}
> +
> +static int
> +richacl_xattr_set(const struct xattr_handler *handler,
> + struct dentry *unused, struct inode *inode,
> + const char *name, const void *value, size_t size,
> + int flags)
> +{
> + struct richacl *acl = NULL;
> + int ret;
> +
> + if (value) {
> + acl = richacl_from_xattr(current_user_ns(), value, size,
> + -EINVAL);
> + if (IS_ERR(acl))
> + return PTR_ERR(acl);
> + }
> +
> + ret = set_richacl(inode, acl);
> + richacl_put(acl);
> + return ret;
> +}
> +
> +struct xattr_handler richacl_xattr_handler = {
> + .name = XATTR_NAME_RICHACL,
> + .list = richacl_xattr_list,
> + .get = richacl_xattr_get,
> + .set = richacl_xattr_set,
> +};
> +EXPORT_SYMBOL(richacl_xattr_handler);
> diff --git a/include/linux/richacl.h b/include/linux/richacl.h
> index a442372..e7db066 100644
> --- a/include/linux/richacl.h
> +++ b/include/linux/richacl.h
> @@ -206,5 +206,6 @@ extern int richacl_chmod(struct inode *, umode_t);
> extern int richacl_equiv_mode(const struct richacl *, umode_t *);
> extern struct richacl *richacl_inherit(const struct richacl *, int);
> extern struct richacl *richacl_create(umode_t *, struct inode *);
> +extern int set_richacl(struct inode *, struct richacl *);
>
> #endif /* __RICHACL_H */
> diff --git a/include/linux/richacl_xattr.h b/include/linux/richacl_xattr.h
> index 0efa14b..6c6adb1 100644
> --- a/include/linux/richacl_xattr.h
> +++ b/include/linux/richacl_xattr.h
> @@ -26,4 +26,6 @@ extern size_t richacl_xattr_size(const struct richacl *);
> extern int richacl_to_xattr(struct user_namespace *, const struct richacl *,
> void *, size_t);
>
> +extern struct xattr_handler richacl_xattr_handler;
> +
> #endif /* __RICHACL_XATTR_H */
Cue same refrain about syscalls vs. xattrs. Otherwise:
Reviewed-by: Jeff Layton <jlayton@redhat.com>
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2016-06-30 16:00 +0200 |
| Subject | [PATCH v23 12/22] vfs: Add get_richacl and set_richacl inode operations |
| Message-ID | <rPKFB-1Pr-51@gated-at.bofh.it> |
| In reply to | #1434569 |
These operations are similar to the get_acl and set_acl operations for
POSIX ACLs. The distinction between access and default ACLs doesn't exist
for richacls.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Reviewed-by: Steve French <steve.french@primarydata.com>
---
include/linux/fs.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 06a30b0..ac96bda 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1726,6 +1726,7 @@ struct inode_operations {
const char * (*get_link) (struct dentry *, struct inode *, struct delayed_call *);
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);
@@ -1756,6 +1757,7 @@ struct inode_operations {
umode_t create_mode, int *opened);
int (*tmpfile) (struct inode *, struct dentry *, umode_t);
int (*set_acl)(struct inode *, struct posix_acl *, int);
+ int (*set_richacl)(struct inode *, struct richacl *);
} ____cacheline_aligned;
ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
--
2.5.5
[toc] | [prev] | [next] | [standalone]
| From | Jeff Layton <jlayton@redhat.com> |
|---|---|
| Date | 2016-07-06 20:40 +0200 |
| Subject | Re: [PATCH v23 12/22] vfs: Add get_richacl and set_richacl inode operations |
| Message-ID | <rRZTQ-4h6-9@gated-at.bofh.it> |
| In reply to | #1434580 |
On Thu, 2016-06-30 at 15:47 +0200, Andreas Gruenbacher wrote:
> These operations are similar to the get_acl and set_acl operations for
> POSIX ACLs. The distinction between access and default ACLs doesn't exist
> for richacls.
>
> Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
> Reviewed-by: Steve French <steve.french@primarydata.com>
> ---
> include/linux/fs.h | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index 06a30b0..ac96bda 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -1726,6 +1726,7 @@ struct inode_operations {
> const char * (*get_link) (struct dentry *, struct inode *, struct delayed_call *);
> 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);
>
> @@ -1756,6 +1757,7 @@ struct inode_operations {
> umode_t create_mode, int *opened);
> int (*tmpfile) (struct inode *, struct dentry *, umode_t);
> int (*set_acl)(struct inode *, struct posix_acl *, int);
> + int (*set_richacl)(struct inode *, struct richacl *);
> } ____cacheline_aligned;
>
> ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
Looks OK, though it's hard to review something like this without some
context. Maybe this patch should be folded in with the patch that
actually adds the calls for these operations?
Reviewed-by: Jeff Layton <jlayton@redhat.com>
[toc] | [prev] | [next] | [standalone]
Page 1 of 3 [1] 2 3 Next page →
Back to top | Article view | linux.kernel
csiph-web