Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1434569 > unrolled thread

[PATCH v23 00/22] Richacls (Core and Ext4)

Started byAndreas Gruenbacher <agruenba@redhat.com>
First post2016-06-30 16:00 +0200
Last post2016-06-30 17:00 +0200
Articles 20 on this page of 44 — 6 participants

Back to article view | Back to linux.kernel


Contents

  [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 →


#1434569 — [PATCH v23 00/22] Richacls (Core and Ext4)

FromAndreas Gruenbacher <agruenba@redhat.com>
Date2016-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]


#1434570 — [PATCH v23 14/22] richacl: Update the file masks in chmod()

FromAndreas Gruenbacher <agruenba@redhat.com>
Date2016-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]


#1441272 — Re: [PATCH v23 14/22] richacl: Update the file masks in chmod()

FromJeff Layton <jlayton@redhat.com>
Date2016-07-12 13:40 +0200
SubjectRe: [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]


#1434571 — [PATCH v23 15/22] richacl: Check if an acl is equivalent to a file mode

FromAndreas Gruenbacher <agruenba@redhat.com>
Date2016-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]


#1441270 — Re: [PATCH v23 15/22] richacl: Check if an acl is equivalent to a file mode

FromJeff Layton <jlayton@redhat.com>
Date2016-07-12 13:40 +0200
SubjectRe: [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]


#1434572 — [PATCH v23 08/22] richacl: Compute maximum file masks from an acl

FromAndreas Gruenbacher <agruenba@redhat.com>
Date2016-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]


#1437196 — RE: [PATCH v23 08/22] richacl: Compute maximum file masks from an acl

From"Frank Filz" <ffilzlnx@mindspring.com>
Date2016-07-05 19:10 +0200
SubjectRE: [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]


#1442402 — Re: [PATCH v23 08/22] richacl: Compute maximum file masks from an acl

FromAndreas Gruenbacher <agruenba@redhat.com>
Date2016-07-13 14:40 +0200
SubjectRe: [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]


#1442791 — RE: [PATCH v23 08/22] richacl: Compute maximum file masks from an acl

From"Frank Filz" <ffilzlnx@mindspring.com>
Date2016-07-13 21:50 +0200
SubjectRE: [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]


#1434573 — [PATCH v23 16/22] richacl: Create-time inheritance

FromAndreas Gruenbacher <agruenba@redhat.com>
Date2016-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]


#1441282 — Re: [PATCH v23 16/22] richacl: Create-time inheritance

FromJeff Layton <jlayton@redhat.com>
Date2016-07-12 13:50 +0200
SubjectRe: [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]


#1434574 — [PATCH v23 06/22] richacl: In-memory representation and helper functions

FromAndreas Gruenbacher <agruenba@redhat.com>
Date2016-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]


#1436939 — Re: [PATCH v23 06/22] richacl: In-memory representation and helper functions

FromJeff Layton <jlayton@redhat.com>
Date2016-07-05 13:40 +0200
SubjectRe: [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]


#1440434 — Re: [PATCH v23 06/22] richacl: In-memory representation and helper functions

FromAndreas Gruenbacher <agruenba@redhat.com>
Date2016-07-11 12:20 +0200
SubjectRe: [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]


#1434576 — [PATCH v23 22/22] ext4: Add richacl feature flag

FromAndreas Gruenbacher <agruenba@redhat.com>
Date2016-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]


#1434578 — [PATCH v23 21/22] ext4: Add richacl support

FromAndreas Gruenbacher <agruenba@redhat.com>
Date2016-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]


#1434579 — [PATCH v23 19/22] richacl: Add richacl xattr handler

FromAndreas Gruenbacher <agruenba@redhat.com>
Date2016-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]


#1441304 — Re: [PATCH v23 19/22] richacl: Add richacl xattr handler

FromJeff Layton <jlayton@redhat.com>
Date2016-07-12 14:20 +0200
SubjectRe: [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]


#1434580 — [PATCH v23 12/22] vfs: Add get_richacl and set_richacl inode operations

FromAndreas Gruenbacher <agruenba@redhat.com>
Date2016-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]


#1437905 — Re: [PATCH v23 12/22] vfs: Add get_richacl and set_richacl inode operations

FromJeff Layton <jlayton@redhat.com>
Date2016-07-06 20:40 +0200
SubjectRe: [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