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


Groups > linux.kernel > #1248844 > unrolled thread

[PATCH v11 00/48] Richacls

Started byAndreas Gruenbacher <agruenba@redhat.com>
First post2015-10-16 17:20 +0200
Last post2015-10-16 18:10 +0200
Articles 20 on this page of 52 — 4 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH v11 00/48] Richacls Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:20 +0200
    [PATCH v11 10/48] vfs: Cache base_acl objects in inodes Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:20 +0200
    [PATCH v11 04/48] vfs: Make the inode passed to inode_change_ok non-const Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:20 +0200
    [PATCH v11 11/48] vfs: Add get_richacl and set_richacl inode operations Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:20 +0200
    [PATCH v11 05/48] vfs: Add permission flags for setting file attributes Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:20 +0200
    [PATCH v11 06/48] richacl: In-memory representation and helper functions Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:20 +0200
    [PATCH v11 01/48] vfs: Add IS_ACL() and IS_RICHACL() tests Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:20 +0200
    [PATCH v11 03/48] vfs: Add MAY_DELETE_SELF and MAY_DELETE_CHILD permission flags Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:20 +0200
    [PATCH v11 41/48] xfs: Don't allow unmapped identifiers in richacls Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:30 +0200
    [PATCH v11 39/48] nfsd: Add support for unmapped richace identifiers Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:30 +0200
    [PATCH v11 25/48] richacl: acl editing helper functions Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:30 +0200
    [PATCH v11 22/48] xfs: Fix error path in xfs_get_acl Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:30 +0200
    [PATCH v11 46/48] nfs: Distinguish missing users and groups from nobody Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:30 +0200
    [PATCH v11 42/48] sunrpc: Allow to demand-allocate pages to encode into Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:30 +0200
    [PATCH v11 31/48] richacl: Apply the file masks to a richacl Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:30 +0200
    [PATCH v11 29/48] richacl: Set the other permissions to the other mask Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:30 +0200
    [PATCH v11 38/48] richacl: Add support for unmapped identifiers Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:30 +0200
    [PATCH v11 48/48] nfs: Add support for the v4.1 dacl attribute Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:30 +0200
    [PATCH v11 24/48] xfs: Add richacl support Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:30 +0200
    [PATCH v11 45/48] nfs: Remove unused xdr page offsets in getacl/setacl arguments Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:30 +0200
    [PATCH v11 47/48] nfs: Add richacl support Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:30 +0200
    [PATCH v11 12/48] vfs: Cache richacl in struct inode Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:30 +0200
    [PATCH v11 19/48] vfs: Add richacl permission checking Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:30 +0200
    [PATCH v11 23/48] xfs: Make xfs_set_mode non-static Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:30 +0200
    [PATCH v11 21/48] ext4: Add richacl feature flag Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:30 +0200
      Re: [PATCH v11 21/48] ext4: Add richacl feature flag Austin S Hemmelgarn <ahferroin7@gmail.com> - 2015-10-16 19:40 +0200
        Re: [PATCH v11 21/48] ext4: Add richacl feature flag Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 19:50 +0200
          Re: [PATCH v11 21/48] ext4: Add richacl feature flag Austin S Hemmelgarn <ahferroin7@gmail.com> - 2015-10-16 20:30 +0200
            Re: [PATCH v11 21/48] ext4: Add richacl feature flag Dave Chinner <david@fromorbit.com> - 2015-10-18 01:30 +0200
    [PATCH v11 44/48] nfs: Fix GETATTR bitmap verification Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:30 +0200
    [PATCH v11 37/48] nfsd: Add support for the MAY_CREATE_{FILE,DIR} permissions Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:30 +0200
    [PATCH v11 16/48] richacl: Automatic Inheritance Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:30 +0200
      Re: [PATCH v11 16/48] richacl: Automatic Inheritance Andy Lutomirski <luto@amacapital.net> - 2015-10-16 18:10 +0200
        Re: [PATCH v11 16/48] richacl: Automatic Inheritance Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 18:20 +0200
    [PATCH v11 18/48] richacl: Add richacl xattr handler Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:30 +0200
    [PATCH v11 43/48] sunrpc: Add xdr_init_encode_pages Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:30 +0200
    [PATCH v11 28/48] richacl: Set the owner permissions to the owner mask Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:30 +0200
    [PATCH v11 36/48] nfsd: Add support for the v4.1 dacl attribute Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:30 +0200
    [PATCH v11 35/48] nfsd: Add richacl support Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:30 +0200
    [PATCH v11 13/48] richacl: Update the file masks in chmod() Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:30 +0200
    [PATCH v11 30/48] richacl: Isolate the owner and group classes Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:30 +0200
    [PATCH v11 20/48] ext4: Add richacl support Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:30 +0200
    [PATCH v11 27/48] richacl: Propagate everyone@ permissions to other aces Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:30 +0200
    [PATCH v11 40/48] ext4: Don't allow unmapped identifiers in richacls Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:40 +0200
    [PATCH v11 26/48] richacl: Move everyone@ aces down the acl Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:50 +0200
    [PATCH v11 33/48] nfsd: Keep list of acls to dispose of in compoundargs Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:50 +0200
    [PATCH v11 32/48] richacl: Create richacl from mode values Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:50 +0200
    [PATCH v11 34/48] nfsd: Use richacls as internal acl representation Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 17:50 +0200
    [PATCH v11 15/48] richacl: Create-time inheritance Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 18:00 +0200
    [PATCH v11 17/48] richacl: xattr mapping functions Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 18:00 +0200
    [PATCH v11 14/48] richacl: Check if an acl is equivalent to a file mode Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 18:10 +0200
    [PATCH v11 09/48] richacl: Permission check algorithm Andreas Gruenbacher <agruenba@redhat.com> - 2015-10-16 18:10 +0200

Page 1 of 3  [1] 2 3  Next page →


#1248844 — [PATCH v11 00/48] Richacls

FromAndreas Gruenbacher <agruenba@redhat.com>
Date2015-10-16 17:20 +0200
Subject[PATCH v11 00/48] Richacls
Message-ID<qkeXv-1Ha-3@gated-at.bofh.it>
Here is another update of the richacl patch queue.  I would like to ask for
feedback so that the core and local filesystem code (patches 1-24) can be
merged in the 4.4 merge window.

Changes since the last posting (http://lwn.net/Articles/660392/):

 * The kernel nfs client can now distinguish between users and
   groups which have no ID mapping and the nobody user/group.
   This requires an extension to the nfsidmap user-space helper
   from the nfs-utils package [2].  When the kernel detects
   that nfsidmap doesn't support the new mapping, it falls
   back to the old one.

 * Minor bugs with unmapped user and group names in nfs and nfsd
   have been fixed.  Some functions have been split to be easier
   to understand.

 * The ext4 and xfs filesystem code has been simplified based on
   feedback from Dave Chinner.  On xfs, richacls can no longer
   be compiled out (but they will only be effective on file
   systems with the richacl feature set).


The complete patch queue is available in git form at [1].  The richacl
user-space utilitites and test suite are available at [3].  Please see the
richacl homepage [4] for more information.

[1] git://git.kernel.org/pub/scm/linux/kernel/git/agruen/linux-richacl.git \
	richacl-2015-10-16
[2] https://github.com/andreas-gruenbacher/nfs-utils
[3] https://github.com/andreas-gruenbacher/richacl/
[4] http://www.bestbits.at/richacl/


Thanks,
Andreas


Andreas Gruenbacher (46):
  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
  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
  xfs: Fix error path in xfs_get_acl
  xfs: Make xfs_set_mode non-static
  xfs: Add richacl support
  richacl: acl editing helper functions
  richacl: Move everyone@ aces down the acl
  richacl: Propagate everyone@ permissions to other aces
  richacl: Set the owner permissions to the owner mask
  richacl: Set the other permissions to the other mask
  richacl: Isolate the owner and group classes
  richacl: Apply the file masks to a richacl
  richacl: Create richacl from mode values
  nfsd: Keep list of acls to dispose of in compoundargs
  nfsd: Use richacls as internal acl representation
  nfsd: Add richacl support
  nfsd: Add support for the v4.1 dacl attribute
  nfsd: Add support for the MAY_CREATE_{FILE,DIR} permissions
  richacl: Add support for unmapped identifiers
  nfsd: Add support for unmapped richace identifiers
  ext4: Don't allow unmapped identifiers in richacls
  xfs: Don't allow unmapped identifiers in richacls
  sunrpc: Allow to demand-allocate pages to encode into
  sunrpc: Add xdr_init_encode_pages
  nfs: Fix GETATTR bitmap verification
  nfs: Remove unused xdr page offsets in getacl/setacl arguments
  nfs: Distinguish missing users and groups from nobody
  nfs: Add richacl support
  nfs: Add support for the v4.1 dacl attribute

Aneesh Kumar K.V (2):
  ext4: Add richacl support
  ext4: Add richacl feature flag

 drivers/staging/lustre/lustre/llite/llite_lib.c |   2 +-
 fs/Kconfig                                      |   9 +
 fs/Makefile                                     |   3 +
 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                                 |  12 +-
 fs/ext4/namei.c                                 |   5 +
 fs/ext4/richacl.c                               | 145 ++++
 fs/ext4/richacl.h                               |  40 ++
 fs/ext4/super.c                                 |  42 +-
 fs/ext4/xattr.c                                 |   7 +
 fs/f2fs/acl.c                                   |   4 +-
 fs/inode.c                                      |  15 +-
 fs/jffs2/acl.c                                  |   6 +-
 fs/namei.c                                      | 111 ++-
 fs/nfs/inode.c                                  |   3 -
 fs/nfs/nfs4idmap.c                              |  57 +-
 fs/nfs/nfs4proc.c                               | 734 ++++++++++++++-----
 fs/nfs/nfs4xdr.c                                | 261 ++++++-
 fs/nfs/super.c                                  |   4 +-
 fs/nfs_common/Makefile                          |   1 +
 fs/nfs_common/nfs4acl.c                         |  44 ++
 fs/nfsd/Kconfig                                 |   1 +
 fs/nfsd/acl.h                                   |  23 +-
 fs/nfsd/nfs4acl.c                               | 487 +++++++------
 fs/nfsd/nfs4proc.c                              |  25 +-
 fs/nfsd/nfs4xdr.c                               | 268 ++++---
 fs/nfsd/nfsd.h                                  |   6 +-
 fs/nfsd/nfsfh.c                                 |   8 +-
 fs/nfsd/vfs.c                                   |  28 +-
 fs/nfsd/vfs.h                                   |  17 +-
 fs/nfsd/xdr4.h                                  |  12 +-
 fs/posix_acl.c                                  |  26 +-
 fs/richacl_base.c                               | 685 ++++++++++++++++++
 fs/richacl_compat.c                             | 915 ++++++++++++++++++++++++
 fs/richacl_inode.c                              | 333 +++++++++
 fs/richacl_xattr.c                              | 345 +++++++++
 fs/xattr.c                                      |  34 +-
 fs/xfs/Kconfig                                  |   1 +
 fs/xfs/Makefile                                 |   1 +
 fs/xfs/libxfs/xfs_format.h                      |  11 +-
 fs/xfs/xfs_acl.c                                |  19 +-
 fs/xfs/xfs_acl.h                                |   1 -
 fs/xfs/xfs_inode.c                              |  24 +
 fs/xfs/xfs_inode.h                              |   2 +
 fs/xfs/xfs_iops.c                               |  44 +-
 fs/xfs/xfs_richacl.c                            | 106 +++
 fs/xfs/xfs_richacl.h                            |  23 +
 fs/xfs/xfs_super.c                              |   6 +-
 fs/xfs/xfs_super.h                              |   4 +
 fs/xfs/xfs_xattr.c                              |   2 +
 include/linux/fs.h                              |  51 +-
 include/linux/nfs4.h                            |  24 +-
 include/linux/nfs4acl.h                         |   7 +
 include/linux/nfs_fs.h                          |   1 -
 include/linux/nfs_fs_sb.h                       |   3 +
 include/linux/nfs_xdr.h                         |  13 +-
 include/linux/posix_acl.h                       |  12 +-
 include/linux/richacl.h                         | 276 +++++++
 include/linux/richacl_compat.h                  |  40 ++
 include/linux/richacl_xattr.h                   |  44 ++
 include/linux/sunrpc/xdr.h                      |   2 +
 include/uapi/linux/Kbuild                       |   2 +
 include/uapi/linux/fs.h                         |   3 +-
 include/uapi/linux/nfs4.h                       |   3 +-
 include/uapi/linux/richacl.h                    | 111 +++
 include/uapi/linux/richacl_xattr.h              |  44 ++
 include/uapi/linux/xattr.h                      |   2 +
 net/sunrpc/xdr.c                                |  34 +
 73 files changed, 4985 insertions(+), 762 deletions(-)
 create mode 100644 fs/ext4/richacl.c
 create mode 100644 fs/ext4/richacl.h
 create mode 100644 fs/nfs_common/nfs4acl.c
 create mode 100644 fs/richacl_base.c
 create mode 100644 fs/richacl_compat.c
 create mode 100644 fs/richacl_inode.c
 create mode 100644 fs/richacl_xattr.c
 create mode 100644 fs/xfs/xfs_richacl.c
 create mode 100644 fs/xfs/xfs_richacl.h
 create mode 100644 include/linux/nfs4acl.h
 create mode 100644 include/linux/richacl.h
 create mode 100644 include/linux/richacl_compat.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.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [next] | [standalone]


#1248845 — [PATCH v11 10/48] vfs: Cache base_acl objects in inodes

FromAndreas Gruenbacher <agruenba@redhat.com>
Date2015-10-16 17:20 +0200
Subject[PATCH v11 10/48] vfs: Cache base_acl objects in inodes
Message-ID<qkeXv-1Ha-11@gated-at.bofh.it>
In reply to#1248844
POSIX ACLs and richacls are both objects allocated by kmalloc() with a
reference count which are freed by kfree_rcu().  An inode can either
cache an access and a default POSIX ACL, or a richacl (richacls do not
have default acls).  To allow an inode to cache either of the two kinds
of acls, introduce a new base_acl type and convert i_acl and
i_default_acl to that type. In most cases, the vfs then doesn't have to
care which kind of acl an inode caches (if any).

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
 drivers/staging/lustre/lustre/llite/llite_lib.c |  2 +-
 fs/f2fs/acl.c                                   |  4 ++--
 fs/inode.c                                      |  4 ++--
 fs/jffs2/acl.c                                  |  6 ++++--
 fs/posix_acl.c                                  | 18 +++++++++---------
 include/linux/fs.h                              | 25 ++++++++++++++++++++++---
 include/linux/posix_acl.h                       | 12 ++++--------
 include/linux/richacl.h                         |  2 +-
 8 files changed, 45 insertions(+), 28 deletions(-)

diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c
index b4ed6c8..5766f69 100644
--- a/drivers/staging/lustre/lustre/llite/llite_lib.c
+++ b/drivers/staging/lustre/lustre/llite/llite_lib.c
@@ -1118,7 +1118,7 @@ void ll_clear_inode(struct inode *inode)
 	}
 #ifdef CONFIG_FS_POSIX_ACL
 	else if (lli->lli_posix_acl) {
-		LASSERT(atomic_read(&lli->lli_posix_acl->a_refcount) == 1);
+		LASSERT(atomic_read(&lli->lli_posix_acl->a_base.ba_refcount) == 1);
 		LASSERT(lli->lli_remote_perms == NULL);
 		posix_acl_release(lli->lli_posix_acl);
 		lli->lli_posix_acl = NULL;
diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c
index c8f25f7..a4207de 100644
--- a/fs/f2fs/acl.c
+++ b/fs/f2fs/acl.c
@@ -270,7 +270,7 @@ static struct posix_acl *f2fs_acl_clone(const struct posix_acl *acl,
 				sizeof(struct posix_acl_entry);
 		clone = kmemdup(acl, size, flags);
 		if (clone)
-			atomic_set(&clone->a_refcount, 1);
+			atomic_set(&clone->a_base.ba_refcount, 1);
 	}
 	return clone;
 }
@@ -282,7 +282,7 @@ static int f2fs_acl_create_masq(struct posix_acl *acl, umode_t *mode_p)
 	umode_t mode = *mode_p;
 	int not_equiv = 0;
 
-	/* assert(atomic_read(acl->a_refcount) == 1); */
+	/* assert(atomic_read(acl->a_base.ba_refcount) == 1); */
 
 	FOREACH_ACL_ENTRY(pa, acl, pe) {
 		switch(pa->e_tag) {
diff --git a/fs/inode.c b/fs/inode.c
index 78a17b8..2a387f4 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -233,9 +233,9 @@ void __destroy_inode(struct inode *inode)
 
 #ifdef CONFIG_FS_POSIX_ACL
 	if (inode->i_acl && inode->i_acl != ACL_NOT_CACHED)
-		posix_acl_release(inode->i_acl);
+		put_base_acl(inode->i_acl);
 	if (inode->i_default_acl && inode->i_default_acl != ACL_NOT_CACHED)
-		posix_acl_release(inode->i_default_acl);
+		put_base_acl(inode->i_default_acl);
 #endif
 	this_cpu_dec(nr_inodes);
 }
diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c
index 2f7a3c0..04a5836 100644
--- a/fs/jffs2/acl.c
+++ b/fs/jffs2/acl.c
@@ -294,13 +294,15 @@ int jffs2_init_acl_post(struct inode *inode)
 	int rc;
 
 	if (inode->i_default_acl) {
-		rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_DEFAULT, inode->i_default_acl);
+		rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_DEFAULT,
+				     *acl_by_type(inode, ACL_TYPE_DEFAULT));
 		if (rc)
 			return rc;
 	}
 
 	if (inode->i_acl) {
-		rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_ACCESS, inode->i_acl);
+		rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_ACCESS,
+				     *acl_by_type(inode, ACL_TYPE_ACCESS));
 		if (rc)
 			return rc;
 	}
diff --git a/fs/posix_acl.c b/fs/posix_acl.c
index 4fb17de..b3b2265 100644
--- a/fs/posix_acl.c
+++ b/fs/posix_acl.c
@@ -25,9 +25,9 @@ struct posix_acl **acl_by_type(struct inode *inode, int type)
 {
 	switch (type) {
 	case ACL_TYPE_ACCESS:
-		return &inode->i_acl;
+		return (struct posix_acl **)&inode->i_acl;
 	case ACL_TYPE_DEFAULT:
-		return &inode->i_default_acl;
+		return (struct posix_acl **)&inode->i_default_acl;
 	default:
 		BUG();
 	}
@@ -83,16 +83,16 @@ EXPORT_SYMBOL(forget_cached_acl);
 
 void forget_all_cached_acls(struct inode *inode)
 {
-	struct posix_acl *old_access, *old_default;
+	struct base_acl *old_access, *old_default;
 	spin_lock(&inode->i_lock);
 	old_access = inode->i_acl;
 	old_default = inode->i_default_acl;
 	inode->i_acl = inode->i_default_acl = ACL_NOT_CACHED;
 	spin_unlock(&inode->i_lock);
 	if (old_access != ACL_NOT_CACHED)
-		posix_acl_release(old_access);
+		put_base_acl(old_access);
 	if (old_default != ACL_NOT_CACHED)
-		posix_acl_release(old_default);
+		put_base_acl(old_default);
 }
 EXPORT_SYMBOL(forget_all_cached_acls);
 
@@ -129,7 +129,7 @@ EXPORT_SYMBOL(get_acl);
 void
 posix_acl_init(struct posix_acl *acl, int count)
 {
-	atomic_set(&acl->a_refcount, 1);
+	atomic_set(&acl->a_base.ba_refcount, 1);
 	acl->a_count = count;
 }
 EXPORT_SYMBOL(posix_acl_init);
@@ -162,7 +162,7 @@ posix_acl_clone(const struct posix_acl *acl, gfp_t flags)
 		           sizeof(struct posix_acl_entry);
 		clone = kmemdup(acl, size, flags);
 		if (clone)
-			atomic_set(&clone->a_refcount, 1);
+			atomic_set(&clone->a_base.ba_refcount, 1);
 	}
 	return clone;
 }
@@ -384,7 +384,7 @@ static int posix_acl_create_masq(struct posix_acl *acl, umode_t *mode_p)
 	umode_t mode = *mode_p;
 	int not_equiv = 0;
 
-	/* assert(atomic_read(acl->a_refcount) == 1); */
+	/* assert(atomic_read(acl->a_base.ba_refcount) == 1); */
 
 	FOREACH_ACL_ENTRY(pa, acl, pe) {
                 switch(pa->e_tag) {
@@ -439,7 +439,7 @@ static int __posix_acl_chmod_masq(struct posix_acl *acl, umode_t mode)
 	struct posix_acl_entry *group_obj = NULL, *mask_obj = NULL;
 	struct posix_acl_entry *pa, *pe;
 
-	/* assert(atomic_read(acl->a_refcount) == 1); */
+	/* assert(atomic_read(acl->a_base.ba_refcount) == 1); */
 
 	FOREACH_ACL_ENTRY(pa, acl, pe) {
 		switch(pa->e_tag) {
diff --git a/include/linux/fs.h b/include/linux/fs.h
index ba91a89..3c22c92 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -576,6 +576,12 @@ static inline void mapping_allow_writable(struct address_space *mapping)
 #define i_size_ordered_init(inode) do { } while (0)
 #endif
 
+struct base_acl {
+	union {
+		atomic_t ba_refcount;
+		struct rcu_head ba_rcu;
+	};
+};
 struct posix_acl;
 #define ACL_NOT_CACHED ((void *)(-1))
 
@@ -595,9 +601,9 @@ struct inode {
 	kgid_t			i_gid;
 	unsigned int		i_flags;
 
-#ifdef CONFIG_FS_POSIX_ACL
-	struct posix_acl	*i_acl;
-	struct posix_acl	*i_default_acl;
+#if defined(CONFIG_FS_POSIX_ACL)
+	struct base_acl		*i_acl;
+	struct base_acl		*i_default_acl;
 #endif
 
 	const struct inode_operations	*i_op;
@@ -3059,4 +3065,17 @@ static inline bool dir_relax(struct inode *inode)
 
 extern bool path_noexec(const struct path *path);
 
+static inline struct base_acl *get_base_acl(struct base_acl *acl)
+{
+	if (acl)
+		atomic_inc(&acl->ba_refcount);
+	return acl;
+}
+
+static inline void put_base_acl(struct base_acl *acl)
+{
+	if (acl && atomic_dec_and_test(&acl->ba_refcount))
+		kfree_rcu(acl, ba_rcu);
+}
+
 #endif /* _LINUX_FS_H */
diff --git a/include/linux/posix_acl.h b/include/linux/posix_acl.h
index 3e96a6a..2c46441 100644
--- a/include/linux/posix_acl.h
+++ b/include/linux/posix_acl.h
@@ -43,10 +43,7 @@ struct posix_acl_entry {
 };
 
 struct posix_acl {
-	union {
-		atomic_t		a_refcount;
-		struct rcu_head		a_rcu;
-	};
+	struct base_acl		a_base;
 	unsigned int		a_count;
 	struct posix_acl_entry	a_entries[0];
 };
@@ -61,8 +58,7 @@ struct posix_acl {
 static inline struct posix_acl *
 posix_acl_dup(struct posix_acl *acl)
 {
-	if (acl)
-		atomic_inc(&acl->a_refcount);
+	get_base_acl(&acl->a_base);
 	return acl;
 }
 
@@ -72,8 +68,8 @@ posix_acl_dup(struct posix_acl *acl)
 static inline void
 posix_acl_release(struct posix_acl *acl)
 {
-	if (acl && atomic_dec_and_test(&acl->a_refcount))
-		kfree_rcu(acl, a_rcu);
+	BUILD_BUG_ON(offsetof(struct posix_acl, a_base) != 0);
+	put_base_acl(&acl->a_base);
 }
 
 
diff --git a/include/linux/richacl.h b/include/linux/richacl.h
index d5fa7b9..575ec32 100644
--- a/include/linux/richacl.h
+++ b/include/linux/richacl.h
@@ -94,7 +94,7 @@ static inline struct richacl *
 richacl_get(struct richacl *acl)
 {
 	if (acl)
-		atomic_inc(&acl->a_refcount);
+		atomic_inc(&acl->a_base.ba_refcount);
 	return acl;
 }
 
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1248848 — [PATCH v11 04/48] vfs: Make the inode passed to inode_change_ok non-const

FromAndreas Gruenbacher <agruenba@redhat.com>
Date2015-10-16 17:20 +0200
Subject[PATCH v11 04/48] vfs: Make the inode passed to inode_change_ok non-const
Message-ID<qkeXw-1Ha-19@gated-at.bofh.it>
In reply to#1248844
We will need to call iop->permission and iop->get_acl from
inode_change_ok() for additional permission checks, and both take a
non-const inode.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Reviewed-by: J. Bruce Fields <bfields@redhat.com>
---
 fs/attr.c          | 2 +-
 include/linux/fs.h | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/fs/attr.c b/fs/attr.c
index 6530ced..328be71 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -28,7 +28,7 @@
  * Should be called as the first thing in ->setattr implementations,
  * possibly after taking additional locks.
  */
-int inode_change_ok(const struct inode *inode, struct iattr *attr)
+int inode_change_ok(struct inode *inode, struct iattr *attr)
 {
 	unsigned int ia_valid = attr->ia_valid;
 
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 402acd7..aab32c8 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2871,7 +2871,7 @@ extern int buffer_migrate_page(struct address_space *,
 #define buffer_migrate_page NULL
 #endif
 
-extern int inode_change_ok(const struct inode *, struct iattr *);
+extern int inode_change_ok(struct inode *, struct iattr *);
 extern int inode_newsize_ok(const struct inode *, loff_t offset);
 extern void setattr_copy(struct inode *inode, const struct iattr *attr);
 
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1248850 — [PATCH v11 11/48] vfs: Add get_richacl and set_richacl inode operations

FromAndreas Gruenbacher <agruenba@redhat.com>
Date2015-10-16 17:20 +0200
Subject[PATCH v11 11/48] vfs: Add get_richacl and set_richacl inode operations
Message-ID<qkeXw-1Ha-25@gated-at.bofh.it>
In reply to#1248844
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>
---
 include/linux/fs.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/linux/fs.h b/include/linux/fs.h
index 3c22c92..08fde42 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1662,6 +1662,7 @@ struct inode_operations {
 	const char * (*follow_link) (struct dentry *, void **);
 	int (*permission) (struct inode *, int);
 	struct posix_acl * (*get_acl)(struct inode *, int);
+	struct richacl * (*get_richacl)(struct inode *);
 
 	int (*readlink) (struct dentry *, char __user *,int);
 	void (*put_link) (struct inode *, void *);
@@ -1691,6 +1692,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 *);
 
 	/* WARNING: probably going away soon, do not use! */
 } ____cacheline_aligned;
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1248854 — [PATCH v11 05/48] vfs: Add permission flags for setting file attributes

FromAndreas Gruenbacher <agruenba@redhat.com>
Date2015-10-16 17:20 +0200
Subject[PATCH v11 05/48] vfs: Add permission flags for setting file attributes
Message-ID<qkeXw-1Ha-33@gated-at.bofh.it>
In reply to#1248844
Richacls support permissions that allow to take ownership of a file,
change the file permissions, and set the file timestamps.  Support that
by introducing new permission mask flags and by checking for those mask
flags in inode_change_ok().

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Reviewed-by: J. Bruce Fields <bfields@redhat.com>
---
 fs/attr.c          | 79 +++++++++++++++++++++++++++++++++++++++++++++---------
 include/linux/fs.h |  3 +++
 2 files changed, 70 insertions(+), 12 deletions(-)

diff --git a/fs/attr.c b/fs/attr.c
index 328be71..85483e0 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -17,6 +17,65 @@
 #include <linux/ima.h>
 
 /**
+ * inode_extended_permission  -  permissions beyond read/write/execute
+ *
+ * Check for permissions that only richacls can currently grant.
+ */
+static int inode_extended_permission(struct inode *inode, int mask)
+{
+	if (!IS_RICHACL(inode))
+		return -EPERM;
+	return inode_permission(inode, mask);
+}
+
+static bool inode_uid_change_ok(struct inode *inode, kuid_t ia_uid)
+{
+	if (uid_eq(current_fsuid(), inode->i_uid) &&
+	    uid_eq(ia_uid, inode->i_uid))
+		return true;
+	if (uid_eq(current_fsuid(), ia_uid) &&
+	    inode_extended_permission(inode, MAY_TAKE_OWNERSHIP) == 0)
+		return true;
+	if (capable_wrt_inode_uidgid(inode, CAP_CHOWN))
+		return true;
+	return false;
+}
+
+static bool inode_gid_change_ok(struct inode *inode, kgid_t ia_gid)
+{
+	int in_group = in_group_p(ia_gid);
+	if (uid_eq(current_fsuid(), inode->i_uid) &&
+	    (in_group || gid_eq(ia_gid, inode->i_gid)))
+		return true;
+	if (in_group && inode_extended_permission(inode, MAY_TAKE_OWNERSHIP) == 0)
+		return true;
+	if (capable_wrt_inode_uidgid(inode, CAP_CHOWN))
+		return true;
+	return false;
+}
+
+/**
+ * inode_owner_permitted_or_capable
+ *
+ * Check for permissions implicitly granted to the owner, like MAY_CHMOD or
+ * MAY_SET_TIMES.  Equivalent to inode_owner_or_capable for file systems
+ * without support for those permissions.
+ */
+static bool inode_owner_permitted_or_capable(struct inode *inode, int mask)
+{
+	struct user_namespace *ns;
+
+	if (uid_eq(current_fsuid(), inode->i_uid))
+		return true;
+	if (inode_extended_permission(inode, mask) == 0)
+		return true;
+	ns = current_user_ns();
+	if (ns_capable(ns, CAP_FOWNER) && kuid_has_mapping(ns, inode->i_uid))
+		return true;
+	return false;
+}
+
+/**
  * inode_change_ok - check if attribute changes to an inode are allowed
  * @inode:	inode to check
  * @attr:	attributes to change
@@ -47,22 +106,18 @@ int inode_change_ok(struct inode *inode, struct iattr *attr)
 		return 0;
 
 	/* Make sure a caller can chown. */
-	if ((ia_valid & ATTR_UID) &&
-	    (!uid_eq(current_fsuid(), inode->i_uid) ||
-	     !uid_eq(attr->ia_uid, inode->i_uid)) &&
-	    !capable_wrt_inode_uidgid(inode, CAP_CHOWN))
-		return -EPERM;
+	if (ia_valid & ATTR_UID)
+		if (!inode_uid_change_ok(inode, attr->ia_uid))
+			return -EPERM;
 
 	/* Make sure caller can chgrp. */
-	if ((ia_valid & ATTR_GID) &&
-	    (!uid_eq(current_fsuid(), inode->i_uid) ||
-	    (!in_group_p(attr->ia_gid) && !gid_eq(attr->ia_gid, inode->i_gid))) &&
-	    !capable_wrt_inode_uidgid(inode, CAP_CHOWN))
-		return -EPERM;
+	if (ia_valid & ATTR_GID)
+		if (!inode_gid_change_ok(inode, attr->ia_gid))
+			return -EPERM;
 
 	/* Make sure a caller can chmod. */
 	if (ia_valid & ATTR_MODE) {
-		if (!inode_owner_or_capable(inode))
+		if (!inode_owner_permitted_or_capable(inode, MAY_CHMOD))
 			return -EPERM;
 		/* Also check the setgid bit! */
 		if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
@@ -73,7 +128,7 @@ int inode_change_ok(struct inode *inode, struct iattr *attr)
 
 	/* Check for setting the inode time. */
 	if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) {
-		if (!inode_owner_or_capable(inode))
+		if (!inode_owner_permitted_or_capable(inode, MAY_SET_TIMES))
 			return -EPERM;
 	}
 
diff --git a/include/linux/fs.h b/include/linux/fs.h
index aab32c8..ba91a89 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -86,6 +86,9 @@ typedef void (dax_iodone_t)(struct buffer_head *bh_map, int uptodate);
 #define MAY_CREATE_DIR		0x00000200
 #define MAY_DELETE_CHILD	0x00000400
 #define MAY_DELETE_SELF		0x00000800
+#define MAY_TAKE_OWNERSHIP	0x00001000
+#define MAY_CHMOD		0x00002000
+#define MAY_SET_TIMES		0x00004000
 
 /*
  * flags in file.f_mode.  Note that FMODE_READ and FMODE_WRITE must correspond
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1248855 — [PATCH v11 06/48] richacl: In-memory representation and helper functions

FromAndreas Gruenbacher <agruenba@redhat.com>
Date2015-10-16 17:20 +0200
Subject[PATCH v11 06/48] richacl: In-memory representation and helper functions
Message-ID<qkeXw-1Ha-35@gated-at.bofh.it>
In reply to#1248844
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                  |   2 +
 fs/richacl_base.c            |  67 ++++++++++++++
 include/linux/richacl.h      | 216 +++++++++++++++++++++++++++++++++++++++++++
 include/uapi/linux/Kbuild    |   1 +
 include/uapi/linux/richacl.h |  62 +++++++++++++
 5 files changed, 348 insertions(+)
 create mode 100644 fs/richacl_base.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 f79cf40..fe3e9dd 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -48,6 +48,8 @@ obj-$(CONFIG_COREDUMP)		+= coredump.o
 obj-$(CONFIG_SYSCTL)		+= drop_caches.o
 
 obj-$(CONFIG_FHANDLE)		+= fhandle.o
+obj-$(CONFIG_FS_RICHACL)	+= richacl.o
+richacl-y			:= richacl_base.o
 
 obj-y				+= quota/
 
diff --git a/fs/richacl_base.c b/fs/richacl_base.c
new file mode 100644
index 0000000..6d9a073
--- /dev/null
+++ b/fs/richacl_base.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2006, 2010  Novell, Inc.
+ * Copyright (C) 2015  Red Hat, Inc.
+ * Written by Andreas Gruenbacher <agruen@kernel.org>
+ *
+ * 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>
+
+MODULE_LICENSE("GPL");
+
+/**
+ * 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..6109f84
--- /dev/null
+++ b/include/linux/richacl.h
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2006, 2010  Novell, Inc.
+ * Copyright (C) 2015  Red Hat, Inc.
+ * Written by Andreas Gruenbacher <agruen@kernel.org>
+ *
+ * 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_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)
+
+#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 f7b2db4..8c82010 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -348,6 +348,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 += romfs_fs.h
 header-y += rose.h
diff --git a/include/uapi/linux/richacl.h b/include/uapi/linux/richacl.h
new file mode 100644
index 0000000..de29a17
--- /dev/null
+++ b/include/uapi/linux/richacl.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2006, 2010  Novell, Inc.
+ * Copyright (C) 2015  Red Hat, Inc.
+ * Written by Andreas Gruenbacher <agruen@kernel.org>
+ *
+ * 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 __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
+
+#endif /* __UAPI_RICHACL_H */
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1248856 — [PATCH v11 01/48] vfs: Add IS_ACL() and IS_RICHACL() tests

FromAndreas Gruenbacher <agruenba@redhat.com>
Date2015-10-16 17:20 +0200
Subject[PATCH v11 01/48] vfs: Add IS_ACL() and IS_RICHACL() tests
Message-ID<qkeXw-1Ha-37@gated-at.bofh.it>
In reply to#1248844
The vfs does not apply the umask for file systems that support acls. The
test used for this used to be called IS_POSIXACL(). Switch to a new
IS_ACL() test to check for either posix acls or richacls instead. Add a new
MS_RICHACL flag and IS_RICHACL() test for richacls alone. The IS_POSIXACL()
test is still needed by nfsd.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Reviewed-by: J. Bruce Fields <bfields@redhat.com>
---
 fs/Kconfig              |  3 +++
 fs/namei.c              |  8 ++++----
 include/linux/fs.h      | 12 ++++++++++++
 include/uapi/linux/fs.h |  3 ++-
 4 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/fs/Kconfig b/fs/Kconfig
index da3f32f..bff2879 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -56,6 +56,9 @@ endif # BLOCK
 config FS_POSIX_ACL
 	def_bool n
 
+config FS_RICHACL
+	def_bool n
+
 config EXPORTFS
 	tristate
 
diff --git a/fs/namei.c b/fs/namei.c
index 33e9495..224ecf1 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2798,7 +2798,7 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
 	}
 
 	mode = op->mode;
-	if ((open_flag & O_CREAT) && !IS_POSIXACL(dir))
+	if ((open_flag & O_CREAT) && !IS_ACL(dir))
 		mode &= ~current_umask();
 
 	excl = (open_flag & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT);
@@ -2982,7 +2982,7 @@ static int lookup_open(struct nameidata *nd, struct path *path,
 	/* Negative dentry, just create the file */
 	if (!dentry->d_inode && (op->open_flag & O_CREAT)) {
 		umode_t mode = op->mode;
-		if (!IS_POSIXACL(dir->d_inode))
+		if (!IS_ACL(dir->d_inode))
 			mode &= ~current_umask();
 		/*
 		 * This write is needed to ensure that a
@@ -3553,7 +3553,7 @@ retry:
 	if (IS_ERR(dentry))
 		return PTR_ERR(dentry);
 
-	if (!IS_POSIXACL(path.dentry->d_inode))
+	if (!IS_ACL(path.dentry->d_inode))
 		mode &= ~current_umask();
 	error = security_path_mknod(&path, dentry, mode, dev);
 	if (error)
@@ -3622,7 +3622,7 @@ retry:
 	if (IS_ERR(dentry))
 		return PTR_ERR(dentry);
 
-	if (!IS_POSIXACL(path.dentry->d_inode))
+	if (!IS_ACL(path.dentry->d_inode))
 		mode &= ~current_umask();
 	error = security_path_mkdir(&path, dentry, mode);
 	if (!error)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 72d8a84..4efa435 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1781,6 +1781,12 @@ struct super_operations {
 #define IS_IMMUTABLE(inode)	((inode)->i_flags & S_IMMUTABLE)
 #define IS_POSIXACL(inode)	__IS_FLG(inode, MS_POSIXACL)
 
+#ifdef CONFIG_FS_RICHACL
+#define IS_RICHACL(inode)	__IS_FLG(inode, MS_RICHACL)
+#else
+#define IS_RICHACL(inode)	0
+#endif
+
 #define IS_DEADDIR(inode)	((inode)->i_flags & S_DEAD)
 #define IS_NOCMTIME(inode)	((inode)->i_flags & S_NOCMTIME)
 #define IS_SWAPFILE(inode)	((inode)->i_flags & S_SWAPFILE)
@@ -1794,6 +1800,12 @@ struct super_operations {
 				 (inode)->i_rdev == WHITEOUT_DEV)
 
 /*
+ * IS_ACL() tells the VFS to not apply the umask
+ * and use check_acl for acl permission checks when defined.
+ */
+#define IS_ACL(inode)		__IS_FLG(inode, MS_POSIXACL | MS_RICHACL)
+
+/*
  * Inode state bits.  Protected by inode->i_lock
  *
  * Three bits determine the dirty state of the inode, I_DIRTY_SYNC,
diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
index 9b964a5..6ac6bc9 100644
--- a/include/uapi/linux/fs.h
+++ b/include/uapi/linux/fs.h
@@ -81,7 +81,7 @@ struct inodes_stat_t {
 #define MS_VERBOSE	32768	/* War is peace. Verbosity is silence.
 				   MS_VERBOSE is deprecated. */
 #define MS_SILENT	32768
-#define MS_POSIXACL	(1<<16)	/* VFS does not apply the umask */
+#define MS_POSIXACL	(1<<16)	/* Supports POSIX ACLs */
 #define MS_UNBINDABLE	(1<<17)	/* change to unbindable */
 #define MS_PRIVATE	(1<<18)	/* change to private */
 #define MS_SLAVE	(1<<19)	/* change to slave */
@@ -91,6 +91,7 @@ struct inodes_stat_t {
 #define MS_I_VERSION	(1<<23) /* Update inode I_version field */
 #define MS_STRICTATIME	(1<<24) /* Always perform atime updates */
 #define MS_LAZYTIME	(1<<25) /* Update the on-disk [acm]times lazily */
+#define MS_RICHACL	(1<<26) /* Supports richacls */
 
 /* These sb flags are internal to the kernel */
 #define MS_NOSEC	(1<<28)
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1248857 — [PATCH v11 03/48] vfs: Add MAY_DELETE_SELF and MAY_DELETE_CHILD permission flags

FromAndreas Gruenbacher <agruenba@redhat.com>
Date2015-10-16 17:20 +0200
Subject[PATCH v11 03/48] vfs: Add MAY_DELETE_SELF and MAY_DELETE_CHILD permission flags
Message-ID<qkeXw-1Ha-39@gated-at.bofh.it>
In reply to#1248844
Normally, deleting a file requires MAY_WRITE access to the parent
directory.  With richacls, a file may be deleted with MAY_DELETE_CHILD access
to the parent directory or with MAY_DELETE_SELF access to the file.

To support that, pass the MAY_DELETE_CHILD mask flag to inode_permission()
when checking for delete access inside a directory, and MAY_DELETE_SELF
when checking for delete access to a file itelf.

The MAY_DELETE_SELF permission overrides the sticky directory check.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Reviewed-by: J. Bruce Fields <bfields@redhat.com>
---
 fs/namei.c         | 21 ++++++++++++---------
 include/linux/fs.h |  2 ++
 2 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index 0259392..2eab19e 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -453,9 +453,9 @@ static int sb_permission(struct super_block *sb, struct inode *inode, int mask)
  * this, letting us set arbitrary permissions for filesystem access without
  * changing the "normal" UIDs which are used for other things.
  *
- * MAY_WRITE must be set in @mask whenever MAY_APPEND, MAY_CREATE_FILE, or
- * MAY_CREATE_DIR are set.  That way, file systems that don't support these
- * permissions will check for MAY_WRITE instead.
+ * MAY_WRITE must be set in @mask whenever MAY_APPEND, MAY_CREATE_FILE,
+ * MAY_CREATE_DIR, or MAY_DELETE_CHILD are set.  That way, file systems that
+ * don't support these permissions will check for MAY_WRITE instead.
  */
 int inode_permission(struct inode *inode, int mask)
 {
@@ -2555,7 +2555,7 @@ static int may_delete(struct inode *dir, struct dentry *victim,
 		      bool isdir, bool replace)
 {
 	struct inode *inode = d_backing_inode(victim);
-	int error, mask = MAY_WRITE | MAY_EXEC;
+	int error, mask = MAY_EXEC;
 
 	if (d_is_negative(victim))
 		return -ENOENT;
@@ -2565,15 +2565,18 @@ static int may_delete(struct inode *dir, struct dentry *victim,
 	audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE);
 
 	if (replace)
-		mask |= isdir ? MAY_CREATE_DIR : MAY_CREATE_FILE;
-	error = inode_permission(dir, mask);
+		mask |= MAY_WRITE | (isdir ? MAY_CREATE_DIR : MAY_CREATE_FILE);
+	error = inode_permission(dir, mask | MAY_WRITE | MAY_DELETE_CHILD);
+	if (!error && check_sticky(dir, inode))
+		error = -EPERM;
+	if (error && IS_RICHACL(inode) &&
+	    inode_permission(inode, MAY_DELETE_SELF) == 0)
+		error = 0;
 	if (error)
 		return error;
 	if (IS_APPEND(dir))
 		return -EPERM;
-
-	if (check_sticky(dir, inode) || IS_APPEND(inode) ||
-	    IS_IMMUTABLE(inode) || IS_SWAPFILE(inode))
+	if (IS_APPEND(inode) || IS_IMMUTABLE(inode) || IS_SWAPFILE(inode))
 		return -EPERM;
 	if (isdir) {
 		if (!d_is_dir(victim))
diff --git a/include/linux/fs.h b/include/linux/fs.h
index d6e2330..402acd7 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -84,6 +84,8 @@ typedef void (dax_iodone_t)(struct buffer_head *bh_map, int uptodate);
 #define MAY_NOT_BLOCK		0x00000080
 #define MAY_CREATE_FILE		0x00000100
 #define MAY_CREATE_DIR		0x00000200
+#define MAY_DELETE_CHILD	0x00000400
+#define MAY_DELETE_SELF		0x00000800
 
 /*
  * flags in file.f_mode.  Note that FMODE_READ and FMODE_WRITE must correspond
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1248858 — [PATCH v11 41/48] xfs: Don't allow unmapped identifiers in richacls

FromAndreas Gruenbacher <agruenba@redhat.com>
Date2015-10-16 17:30 +0200
Subject[PATCH v11 41/48] xfs: Don't allow unmapped identifiers in richacls
Message-ID<qkf7b-1SN-1@gated-at.bofh.it>
In reply to#1248844
Don't allow acls which contain unmapped identifiers: they are meaningful
for remote file systems only.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
 fs/xfs/xfs_richacl.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/fs/xfs/xfs_richacl.c b/fs/xfs/xfs_richacl.c
index 73c2d24..4f938b7 100644
--- a/fs/xfs/xfs_richacl.c
+++ b/fs/xfs/xfs_richacl.c
@@ -77,6 +77,10 @@ xfs_set_richacl(struct inode *inode, struct richacl *acl)
 	if (!acl)
 		return xfs_remove_richacl(inode);
 
+	/* Don't allow acls with unmapped identifiers. */
+	if (richacl_has_unmapped_identifiers(acl))
+		return -EINVAL;
+
 	if (richacl_equiv_mode(acl, &mode) == 0) {
 		xfs_set_mode(inode, mode);
 		return xfs_remove_richacl(inode);
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1248859 — [PATCH v11 39/48] nfsd: Add support for unmapped richace identifiers

FromAndreas Gruenbacher <agruenba@redhat.com>
Date2015-10-16 17:30 +0200
Subject[PATCH v11 39/48] nfsd: Add support for unmapped richace identifiers
Message-ID<qkf7b-1SN-3@gated-at.bofh.it>
In reply to#1248844
Add support for encoding unmapped identifiers in richacl entries: local
filesystems are not usually supposed to store unmapped identifiers, but
allowing that for debugging purposes can be useful; for that, nfsd must
also be able to encode them.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
 fs/nfsd/acl.h     |  2 +-
 fs/nfsd/nfs4acl.c | 17 +++++++++++------
 fs/nfsd/nfs4xdr.c |  4 ++--
 3 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/fs/nfsd/acl.h b/fs/nfsd/acl.h
index d73c664..4935144 100644
--- a/fs/nfsd/acl.h
+++ b/fs/nfsd/acl.h
@@ -51,7 +51,7 @@ struct svc_rqst;
 __be32 nfsd4_decode_ace_who(struct richace *ace, struct svc_rqst *rqstp,
 			    char *who, u32 len);
 __be32 nfsd4_encode_ace_who(struct xdr_stream *xdr, struct svc_rqst *rqstp,
-			    struct richace *ace);
+			    struct richace *ace, struct richacl *acl);
 
 struct richacl *nfsd4_get_acl(struct svc_rqst *rqstp, struct dentry *dentry);
 __be32 nfsd4_set_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c
index f017a76..3cc83fd 100644
--- a/fs/nfsd/nfs4acl.c
+++ b/fs/nfsd/nfs4acl.c
@@ -885,17 +885,22 @@ __be32 nfsd4_decode_ace_who(struct richace *ace, struct svc_rqst *rqstp,
 }
 
 __be32 nfsd4_encode_ace_who(struct xdr_stream *xdr, struct svc_rqst *rqstp,
-			    struct richace *ace)
+			    struct richace *ace, struct richacl *acl)
 {
-	if (ace->e_flags & RICHACE_SPECIAL_WHO) {
-		unsigned int special_id = ace->e_id.special;
+	if (ace->e_flags & (RICHACE_SPECIAL_WHO | RICHACE_UNMAPPED_WHO)) {
 		const char *who;
 		unsigned int len;
 		__be32 *p;
 
-		if (!nfs4acl_special_id_to_who(special_id, &who, &len)) {
-			WARN_ON_ONCE(1);
-			return nfserr_serverfault;
+		if (ace->e_flags & RICHACE_SPECIAL_WHO) {
+			if (!nfs4acl_special_id_to_who(ace->e_id.special,
+						       &who, &len)) {
+				WARN_ON_ONCE(1);
+				return nfserr_serverfault;
+			}
+		} else {
+			who = richace_unmapped_identifier(ace, acl);
+			len = strlen(who);
 		}
 		p = xdr_reserve_space(xdr, len + 4);
 		if (!p)
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 33d028c..8728d0e 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -2325,7 +2325,7 @@ static __be32 nfsd4_encode_acl_entries(struct xdr_stream *xdr,
 {
 	__be32 *p;
 
-	flags_mask &= ~RICHACE_SPECIAL_WHO;
+	flags_mask &= ~(RICHACE_SPECIAL_WHO | RICHACE_UNMAPPED_WHO);
 
 	p = xdr_reserve_space(xdr, 4);
 	if (!p)
@@ -2347,7 +2347,7 @@ static __be32 nfsd4_encode_acl_entries(struct xdr_stream *xdr,
 			*p++ = cpu_to_be32(ace->e_type);
 			*p++ = cpu_to_be32(ace->e_flags & flags_mask);
 			*p++ = cpu_to_be32(ace->e_mask & ace_mask);
-			status = nfsd4_encode_ace_who(xdr, rqstp, ace);
+			status = nfsd4_encode_ace_who(xdr, rqstp, ace, acl);
 			if (status)
 				return status;
 		}
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1248860 — [PATCH v11 25/48] richacl: acl editing helper functions

FromAndreas Gruenbacher <agruenba@redhat.com>
Date2015-10-16 17:30 +0200
Subject[PATCH v11 25/48] richacl: acl editing helper functions
Message-ID<qkf7b-1SN-5@gated-at.bofh.it>
In reply to#1248844
The file masks in richacls make chmod and creating new files more
efficient than having to apply file permission bits to the acl directly.
They also allow us to regain permissions from an acl even after a
restrictive chmod, because the permissions in the acl itself are not
being destroyed.  In POSIX ACLs, the mask entry has a similar function.

Protocols like nfsv4 do not understand file masks.  For those protocols,
we need to compute nfs4 acls which represent the effective permissions
granted by a richacl: we need to "apply" the file masks to the acl.

This is the first in a series of richacl transformation patches; it
implements basic richacl editing functions.  The following patches
implement algorithms for transforming a richacl so that it can be
evaluated as a plain nfs4 acl, with identical permission check results.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Reviewed-by: J. Bruce Fields <bfields@redhat.com>
---
 fs/Makefile                    |   3 +-
 fs/richacl_compat.c            | 155 +++++++++++++++++++++++++++++++++++++++++
 include/linux/richacl_compat.h |  40 +++++++++++
 3 files changed, 197 insertions(+), 1 deletion(-)
 create mode 100644 fs/richacl_compat.c
 create mode 100644 include/linux/richacl_compat.h

diff --git a/fs/Makefile b/fs/Makefile
index 35e640d..32b391b 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -49,7 +49,8 @@ obj-$(CONFIG_SYSCTL)		+= drop_caches.o
 
 obj-$(CONFIG_FHANDLE)		+= fhandle.o
 obj-$(CONFIG_FS_RICHACL)	+= richacl.o
-richacl-y			:= richacl_base.o richacl_inode.o richacl_xattr.o
+richacl-y			:= richacl_base.o richacl_inode.o \
+				   richacl_xattr.o richacl_compat.o
 
 obj-y				+= quota/
 
diff --git a/fs/richacl_compat.c b/fs/richacl_compat.c
new file mode 100644
index 0000000..341e429
--- /dev/null
+++ b/fs/richacl_compat.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2006, 2010  Novell, Inc.
+ * Copyright (C) 2015  Red Hat, Inc.
+ * Written by Andreas Gruenbacher <agruen@kernel.org>
+ *
+ * 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/module.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/richacl_compat.h>
+
+/**
+ * richacl_prepare  -  allocate richacl being constructed
+ *
+ * Allocate a richacl which can hold @count entries but which is initially
+ * empty.
+ */
+struct richacl *richacl_prepare(struct richacl_alloc *alloc, unsigned int count)
+{
+	alloc->acl = richacl_alloc(count, GFP_KERNEL);
+	if (!alloc->acl)
+		return NULL;
+	alloc->acl->a_count = 0;
+	alloc->count = count;
+	return alloc->acl;
+}
+EXPORT_SYMBOL_GPL(richacl_prepare);
+
+/**
+ * richacl_delete_entry  -  delete an entry in an acl
+ * @alloc:	acl and number of allocated entries
+ * @ace:	an entry in @alloc->acl
+ *
+ * Updates @ace so that it points to the entry before the deleted entry
+ * on return. (When deleting the first entry, @ace will point to the
+ * (non-existent) entry before the first entry). This behavior is the
+ * expected behavior when deleting entries while forward iterating over
+ * an acl.
+ */
+void
+richacl_delete_entry(struct richacl_alloc *alloc, struct richace **ace)
+{
+	void *end = alloc->acl->a_entries + alloc->acl->a_count;
+
+	memmove(*ace, *ace + 1, end - (void *)(*ace + 1));
+	(*ace)--;
+	alloc->acl->a_count--;
+}
+EXPORT_SYMBOL_GPL(richacl_delete_entry);
+
+/**
+ * richacl_insert_entry  -  insert an entry in an acl
+ * @alloc:	acl and number of allocated entries
+ * @ace:	entry before which the new entry shall be inserted
+ *
+ * Insert a new entry in @alloc->acl at position @ace and zero-initialize
+ * it.  This may require reallocating @alloc->acl.
+ */
+int
+richacl_insert_entry(struct richacl_alloc *alloc, struct richace **ace)
+{
+	struct richacl *acl = alloc->acl;
+	unsigned int index = *ace - acl->a_entries;
+	size_t tail_size = (acl->a_count - index) * sizeof(struct richace);
+
+	if (alloc->count == acl->a_count) {
+		size_t new_size = sizeof(struct richacl) +
+			(acl->a_count + 1) * sizeof(struct richace);
+
+		acl = krealloc(acl, new_size, GFP_KERNEL);
+		if (!acl)
+			return -1;
+		*ace = acl->a_entries + index;
+		alloc->acl = acl;
+		alloc->count++;
+	}
+
+	memmove(*ace + 1, *ace, tail_size);
+	memset(*ace, 0, sizeof(**ace));
+	acl->a_count++;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(richacl_insert_entry);
+
+/**
+ * richacl_append_entry  -  append an entry to an acl
+ * @alloc:		acl and number of allocated entries
+ *
+ * This may require reallocating @alloc->acl.
+ */
+struct richace *richacl_append_entry(struct richacl_alloc *alloc)
+{
+	struct richacl *acl = alloc->acl;
+	struct richace *ace = acl->a_entries + acl->a_count;
+
+	if (alloc->count > alloc->acl->a_count) {
+		acl->a_count++;
+		return ace;
+	}
+	return richacl_insert_entry(alloc, &ace) ? NULL : ace;
+}
+EXPORT_SYMBOL_GPL(richacl_append_entry);
+
+/**
+ * richace_change_mask  -  set the mask of @ace to @mask
+ * @alloc:	acl and number of allocated entries
+ * @ace:	entry to modify
+ * @mask:	new mask for @ace
+ *
+ * If @ace is inheritable, a inherit-only ace is inserted before @ace which
+ * includes the inheritable permissions of @ace and the inheritance flags of
+ * @ace are cleared before changing the mask.
+ *
+ * If @mask is 0, the original ace is turned into an inherit-only entry if
+ * there are any inheritable permissions, and removed otherwise.
+ *
+ * The returned @ace points to the modified or inserted effective-only acl
+ * entry if that entry exists, to the entry that has become inheritable-only,
+ * or else to the previous entry in the acl.
+ */
+static int
+richace_change_mask(struct richacl_alloc *alloc, struct richace **ace,
+			   unsigned int mask)
+{
+	if (mask && (*ace)->e_mask == mask)
+		(*ace)->e_flags &= ~RICHACE_INHERIT_ONLY_ACE;
+	else if (mask & ~RICHACE_POSIX_ALWAYS_ALLOWED) {
+		if (richace_is_inheritable(*ace)) {
+			if (richacl_insert_entry(alloc, ace))
+				return -1;
+			richace_copy(*ace, *ace + 1);
+			(*ace)->e_flags |= RICHACE_INHERIT_ONLY_ACE;
+			(*ace)++;
+			(*ace)->e_flags &= ~RICHACE_INHERITANCE_FLAGS |
+					   RICHACE_INHERITED_ACE;
+		}
+		(*ace)->e_mask = mask;
+	} else {
+		if (richace_is_inheritable(*ace))
+			(*ace)->e_flags |= RICHACE_INHERIT_ONLY_ACE;
+		else
+			richacl_delete_entry(alloc, ace);
+	}
+	return 0;
+}
diff --git a/include/linux/richacl_compat.h b/include/linux/richacl_compat.h
new file mode 100644
index 0000000..a9ff630
--- /dev/null
+++ b/include/linux/richacl_compat.h
@@ -0,0 +1,40 @@
+/*
+ * 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_COMPAT_H
+#define __RICHACL_COMPAT_H
+
+#include <linux/richacl.h>
+
+/**
+ * struct richacl_alloc  -  remember how many entries are actually allocated
+ * @acl:	acl with a_count <= @count
+ * @count:	the actual number of entries allocated in @acl
+ *
+ * We pass around this structure while modifying an acl so that we do
+ * not have to reallocate when we remove existing entries followed by
+ * adding new entries.
+ */
+struct richacl_alloc {
+	struct richacl *acl;
+	unsigned int count;
+};
+
+struct richacl *richacl_prepare(struct richacl_alloc *, unsigned int);
+struct richace *richacl_append_entry(struct richacl_alloc *);
+int richacl_insert_entry(struct richacl_alloc *, struct richace **);
+void richacl_delete_entry(struct richacl_alloc *, struct richace **);
+
+#endif  /* __RICHACL_COMPAT_H */
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1248861 — [PATCH v11 22/48] xfs: Fix error path in xfs_get_acl

FromAndreas Gruenbacher <agruenba@redhat.com>
Date2015-10-16 17:30 +0200
Subject[PATCH v11 22/48] xfs: Fix error path in xfs_get_acl
Message-ID<qkf7b-1SN-7@gated-at.bofh.it>
In reply to#1248844
Error codes from xfs_attr_get other than -ENOATTR were not properly
reported.  Fix that.

In addition, the declaration of struct xfs_inode in xfs_acl.h isn't needed.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
 fs/xfs/xfs_acl.c | 1 +
 fs/xfs/xfs_acl.h | 1 -
 2 files changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
index 4b64167..e87fd3f 100644
--- a/fs/xfs/xfs_acl.c
+++ b/fs/xfs/xfs_acl.c
@@ -160,6 +160,7 @@ xfs_get_acl(struct inode *inode, int type)
 		 */
 		if (error == -ENOATTR)
 			goto out_update_cache;
+		acl = ERR_PTR(error);
 		goto out;
 	}
 
diff --git a/fs/xfs/xfs_acl.h b/fs/xfs/xfs_acl.h
index 3841b07..9ee0a0d 100644
--- a/fs/xfs/xfs_acl.h
+++ b/fs/xfs/xfs_acl.h
@@ -20,7 +20,6 @@
 
 struct inode;
 struct posix_acl;
-struct xfs_inode;
 
 #ifdef CONFIG_XFS_POSIX_ACL
 extern struct posix_acl *xfs_get_acl(struct inode *inode, int type);
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1248862 — [PATCH v11 46/48] nfs: Distinguish missing users and groups from nobody

FromAndreas Gruenbacher <agruenba@redhat.com>
Date2015-10-16 17:30 +0200
Subject[PATCH v11 46/48] nfs: Distinguish missing users and groups from nobody
Message-ID<qkf7c-1SN-9@gated-at.bofh.it>
In reply to#1248844
User and group names are mapped to IDs using the kernel keyring infrastructure.
When a name does not exist, it is mapped to the nobody user or group; there is
no way to tell the difference from the mapping result.

In ACLs, we need to make that distinction.  For that, use the new "xuid" and
"xgid" maps: they behave like the old "uid" and "gid" maps except that the IDs
of existing users and groups are prefixed by a "+" sign.

When the "xuid" or "xgid" maps are not supported, nfs falls back to the "uid"
and "gid" maps.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
 fs/nfs/nfs4idmap.c        | 57 ++++++++++++++++++++++++++++++++++++++---------
 fs/nfs/nfs4xdr.c          |  6 +++--
 include/linux/nfs_fs_sb.h |  1 +
 3 files changed, 52 insertions(+), 12 deletions(-)

diff --git a/fs/nfs/nfs4idmap.c b/fs/nfs/nfs4idmap.c
index 2e49022..34dd404 100644
--- a/fs/nfs/nfs4idmap.c
+++ b/fs/nfs/nfs4idmap.c
@@ -100,10 +100,12 @@ static bool nfs_fattr_map_owner_name(struct nfs_server *server, struct nfs_fattr
 {
 	struct nfs4_string *owner = fattr->owner_name;
 	kuid_t uid;
+	int ret;
 
 	if (!(fattr->valid & NFS_ATTR_FATTR_OWNER_NAME))
 		return false;
-	if (nfs_map_name_to_uid(server, owner->data, owner->len, &uid) == 0) {
+	ret = nfs_map_name_to_uid(server, owner->data, owner->len, &uid);
+	if (ret == 0 || ret == -ENOENT) {
 		fattr->uid = uid;
 		fattr->valid |= NFS_ATTR_FATTR_OWNER;
 	}
@@ -114,10 +116,12 @@ static bool nfs_fattr_map_group_name(struct nfs_server *server, struct nfs_fattr
 {
 	struct nfs4_string *group = fattr->group_name;
 	kgid_t gid;
+	int ret;
 
 	if (!(fattr->valid & NFS_ATTR_FATTR_GROUP_NAME))
 		return false;
-	if (nfs_map_group_to_gid(server, group->data, group->len, &gid) == 0) {
+	ret = nfs_map_group_to_gid(server, group->data, group->len, &gid);
+	if (ret == 0 || ret == -ENOENT) {
 		fattr->gid = gid;
 		fattr->valid |= NFS_ATTR_FATTR_GROUP;
 	}
@@ -351,20 +355,23 @@ static ssize_t nfs_idmap_lookup_name(__u32 id, const char *type, char *buf,
 }
 
 /* Name -> ID */
+/* Returns -ENOENT for unknown names (with @id set to the nobody id). */
 static int nfs_idmap_lookup_id(const char *name, size_t namelen, const char *type,
 			       __u32 *id, struct idmap *idmap)
 {
-	char id_str[NFS_UINT_MAXLEN];
+	char id_str[NFS_UINT_MAXLEN + 1];
 	long id_long;
 	ssize_t data_size;
 	int ret = 0;
 
-	data_size = nfs_idmap_get_key(name, namelen, type, id_str, NFS_UINT_MAXLEN, idmap);
+	data_size = nfs_idmap_get_key(name, namelen, type, id_str, sizeof(id_str), idmap);
 	if (data_size <= 0) {
 		ret = -EINVAL;
 	} else {
 		ret = kstrtol(id_str, 10, &id_long);
 		*id = (__u32)id_long;
+		if (!ret && *id_str != '+')
+			ret = -ENOENT;
 	}
 	return ret;
 }
@@ -719,9 +726,24 @@ int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_
 	__u32 id = -1;
 	int ret = 0;
 
-	if (!nfs_map_string_to_numeric(name, namelen, &id))
-		ret = nfs_idmap_lookup_id(name, namelen, "uid", &id, idmap);
-	if (ret == 0) {
+	if (!nfs_map_string_to_numeric(name, namelen, &id)) {
+		struct nfs_client *client = server->nfs_client;
+		const char *type;
+
+		for(;;) {
+			type = "xuid";
+			if (test_bit(NFS_CS_NOXUID, &client->cl_flags))
+				type = "uid";
+
+			ret = nfs_idmap_lookup_id(name, namelen, type, &id, idmap);
+			if (ret != -EINVAL || test_bit(NFS_CS_NOXUID, &client->cl_flags))
+				break;
+			printk(KERN_NOTICE "NFS: Falling back from nfsidmap "
+			       "xuid/xgid to uid/gid\n");
+			set_bit(NFS_CS_NOXUID, &client->cl_flags);
+		}
+	}
+	if (ret == 0 || ret == -ENOENT) {
 		*uid = make_kuid(&init_user_ns, id);
 		if (!uid_valid(*uid))
 			ret = -ERANGE;
@@ -736,9 +758,24 @@ int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size
 	__u32 id = -1;
 	int ret = 0;
 
-	if (!nfs_map_string_to_numeric(name, namelen, &id))
-		ret = nfs_idmap_lookup_id(name, namelen, "gid", &id, idmap);
-	if (ret == 0) {
+	if (!nfs_map_string_to_numeric(name, namelen, &id)) {
+		struct nfs_client *client = server->nfs_client;
+		const char *type;
+
+		for(;;) {
+			type = "xgid";
+			if (test_bit(NFS_CS_NOXUID, &client->cl_flags))
+				type = "gid";
+
+			ret = nfs_idmap_lookup_id(name, namelen, type, &id, idmap);
+			if (ret != -EINVAL || test_bit(NFS_CS_NOXUID, &client->cl_flags))
+				break;
+			printk(KERN_NOTICE "NFS: Falling back from nfsidmap "
+			       "xuid/xgid to uid/gid\n");
+			set_bit(NFS_CS_NOXUID, &client->cl_flags);
+		}
+	}
+	if (ret == 0 || ret == -ENOENT) {
 		*gid = make_kgid(&init_user_ns, id);
 		if (!gid_valid(*gid))
 			ret = -ERANGE;
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index eefed15..adeb894 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -3875,7 +3875,8 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap,
 				ret = NFS_ATTR_FATTR_OWNER_NAME;
 			}
 		} else if (len < XDR_MAX_NETOBJ) {
-			if (nfs_map_name_to_uid(server, (char *)p, len, uid) == 0)
+			ret = nfs_map_name_to_uid(server, (char *)p, len, uid);
+			if (ret == 0 || ret == -ENOENT)
 				ret = NFS_ATTR_FATTR_OWNER;
 			else
 				dprintk("%s: nfs_map_name_to_uid failed!\n",
@@ -3918,7 +3919,8 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap,
 				ret = NFS_ATTR_FATTR_GROUP_NAME;
 			}
 		} else if (len < XDR_MAX_NETOBJ) {
-			if (nfs_map_group_to_gid(server, (char *)p, len, gid) == 0)
+			ret = nfs_map_group_to_gid(server, (char *)p, len, gid);
+			if (ret == 0 || ret == -ENOENT)
 				ret = NFS_ATTR_FATTR_GROUP;
 			else
 				dprintk("%s: nfs_map_group_to_gid failed!\n",
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index 570a7df..c7d42b7 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -36,6 +36,7 @@ struct nfs_client {
 #define NFS_CS_RENEWD		3		/* - renewd started */
 #define NFS_CS_STOP_RENEW	4		/* no more state to renew */
 #define NFS_CS_CHECK_LEASE_TIME	5		/* need to check lease time */
+#define NFS_CS_NOXUID		6		/* don't use idmap xuid / xgid */
 	unsigned long		cl_flags;	/* behavior switches */
 #define NFS_CS_NORESVPORT	0		/* - use ephemeral src port */
 #define NFS_CS_DISCRTRY		1		/* - disconnect on RPC retry */
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1248864 — [PATCH v11 42/48] sunrpc: Allow to demand-allocate pages to encode into

FromAndreas Gruenbacher <agruenba@redhat.com>
Date2015-10-16 17:30 +0200
Subject[PATCH v11 42/48] sunrpc: Allow to demand-allocate pages to encode into
Message-ID<qkf7c-1SN-13@gated-at.bofh.it>
In reply to#1248844
When encoding large, variable-length objects such as acls into xdr_bufs,
it is easier to allocate buffer pages on demand rather than precomputing
the required buffer size.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
 net/sunrpc/xdr.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
index 4439ac4..63c1c36 100644
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -537,6 +537,15 @@ static __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr,
 	 */
 	xdr->scratch.iov_base = xdr->p;
 	xdr->scratch.iov_len = frag1bytes;
+
+	if (!*xdr->page_ptr) {
+		struct page *page = alloc_page(GFP_NOFS);
+
+		if (!page)
+			return NULL;
+		*xdr->page_ptr = page;
+	}
+
 	p = page_address(*xdr->page_ptr);
 	/*
 	 * Note this is where the next encode will start after we've
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1248865 — [PATCH v11 31/48] richacl: Apply the file masks to a richacl

FromAndreas Gruenbacher <agruenba@redhat.com>
Date2015-10-16 17:30 +0200
Subject[PATCH v11 31/48] richacl: Apply the file masks to a richacl
Message-ID<qkf7c-1SN-17@gated-at.bofh.it>
In reply to#1248844
Put all the pieces of the acl transformation puzzle together for
computing a richacl which has the file masks "applied" so that the
standard nfsv4 access check algorithm can be used on the richacl.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Reviewed-by: J. Bruce Fields <bfields@redhat.com>
---
 fs/richacl_compat.c     | 101 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/richacl.h |   3 ++
 2 files changed, 104 insertions(+)

diff --git a/fs/richacl_compat.c b/fs/richacl_compat.c
index 7e25343..c99274f 100644
--- a/fs/richacl_compat.c
+++ b/fs/richacl_compat.c
@@ -726,3 +726,104 @@ richacl_isolate_group_class(struct richacl_alloc *alloc, unsigned int deny)
 	}
 	return 0;
 }
+
+/**
+ * __richacl_apply_masks  -  apply the file masks to all aces
+ * @alloc:	acl and number of allocated entries
+ *
+ * Apply the owner mask to owner@ aces, the other mask to
+ * everyone@ aces, and the group mask to all other aces.
+ *
+ * The previous transformations have brought the acl into a
+ * form in which applying the masks will not lead to the
+ * accidental loss of permissions anymore.
+ */
+static int
+__richacl_apply_masks(struct richacl_alloc *alloc, kuid_t owner)
+{
+	struct richace *ace;
+
+	richacl_for_each_entry(ace, alloc->acl) {
+		unsigned int mask;
+
+		if (richace_is_inherit_only(ace) || !richace_is_allow(ace))
+			continue;
+		if (richace_is_owner(ace) ||
+		    (richace_is_unix_user(ace) && uid_eq(owner, ace->e_id.uid)))
+			mask = alloc->acl->a_owner_mask;
+		else if (richace_is_everyone(ace))
+			mask = alloc->acl->a_other_mask;
+		else
+			mask = alloc->acl->a_group_mask;
+		if (richace_change_mask(alloc, &ace, ace->e_mask & mask))
+			return -1;
+	}
+	return 0;
+}
+
+/**
+ * richacl_apply_masks  -  apply the masks to the acl
+ *
+ * Transform @acl so that the standard NFSv4 permission check algorithm (which
+ * is not aware of file masks) will compute the same access decisions as the
+ * richacl permission check algorithm (which looks at the acl and the file
+ * masks).
+ *
+ * This algorithm is split into several steps:
+ *
+ *   - Move everyone@ aces to the end of the acl.  This simplifies the other
+ *     transformations, and allows the everyone@ allow ace at the end of the
+ *     acl to eventually allow permissions to the other class only.
+ *
+ *   - Propagate everyone@ permissions up the acl.  This transformation makes
+ *     sure that the owner and group class aces won't lose any permissions when
+ *     we apply the other mask to the everyone@ allow ace at the end of the acl.
+ *
+ *   - Apply the file masks to all aces.
+ *
+ *   - Make sure everyone is granted the other mask permissions.  This step can
+ *     elevate elevate permissions for the owner and group classes, which is
+ *     corrected later.
+ *
+ *   - Make sure that the group class is not granted any permissions from
+ *     everyone@.
+ *
+ *   - Make sure the owner is granted the owner mask permissions.
+ *
+ *   - Make sure the owner is not granted any permissions beyond the owner
+ *     mask from group class aces or from everyone@.
+ *
+ * NOTE: Depending on the acl and file masks, this algorithm can increase the
+ * number of aces by almost a factor of three in the worst case. This may make
+ * the acl too large for some purposes.
+ */
+int
+richacl_apply_masks(struct richacl **acl, kuid_t owner)
+{
+	if ((*acl)->a_flags & RICHACL_MASKED) {
+		struct richacl_alloc alloc = {
+			.acl = richacl_clone(*acl, GFP_KERNEL),
+			.count = (*acl)->a_count,
+		};
+		unsigned int added = 0;
+
+		if (!alloc.acl)
+			return -ENOMEM;
+		if (richacl_move_everyone_aces_down(&alloc) ||
+		    richacl_propagate_everyone(&alloc) ||
+		    __richacl_apply_masks(&alloc, owner) ||
+		    richacl_set_other_permissions(&alloc, &added) ||
+		    richacl_isolate_group_class(&alloc, added) ||
+		    richacl_set_owner_permissions(&alloc) ||
+		    richacl_isolate_owner_class(&alloc)) {
+			richacl_put(alloc.acl);
+			return -ENOMEM;
+		}
+
+		alloc.acl->a_flags &= ~(RICHACL_WRITE_THROUGH | RICHACL_MASKED);
+		richacl_put(*acl);
+		*acl = alloc.acl;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(richacl_apply_masks);
diff --git a/include/linux/richacl.h b/include/linux/richacl.h
index 67843a6..3f3445b 100644
--- a/include/linux/richacl.h
+++ b/include/linux/richacl.h
@@ -247,4 +247,7 @@ extern int richacl_permission(struct inode *, const struct richacl *, int);
 extern int richacl_chmod(struct inode *, umode_t);
 extern struct richacl *richacl_create(umode_t *, struct inode *);
 
+/* richacl_compat.c */
+extern int richacl_apply_masks(struct richacl **, kuid_t);
+
 #endif /* __RICHACL_H */
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1248867 — [PATCH v11 29/48] richacl: Set the other permissions to the other mask

FromAndreas Gruenbacher <agruenba@redhat.com>
Date2015-10-16 17:30 +0200
Subject[PATCH v11 29/48] richacl: Set the other permissions to the other mask
Message-ID<qkf7c-1SN-23@gated-at.bofh.it>
In reply to#1248844
Change the acl so that everyone@ is granted the permissions set in the
other mask.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Reviewed-by: J. Bruce Fields <bfields@redhat.com>
---
 fs/richacl_compat.c | 41 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/fs/richacl_compat.c b/fs/richacl_compat.c
index 16deeb4..21ee31e 100644
--- a/fs/richacl_compat.c
+++ b/fs/richacl_compat.c
@@ -462,3 +462,44 @@ richacl_set_owner_permissions(struct richacl_alloc *alloc)
 	}
 	return 0;
 }
+
+/**
+ * richacl_set_other_permissions  -  set the other permissions to the other mask
+ * @alloc:	acl and number of allocated entries
+ * @added:	permissions added for everyone@
+ *
+ * Change the acl so that everyone@ is granted the permissions set in the other
+ * mask.  This leaves at most one efective everyone@ allow entry at the end of
+ * the acl.  If everyone@ end up being granted additional permissions, these
+ * permissions are returned in @added.
+ */
+static int
+richacl_set_other_permissions(struct richacl_alloc *alloc, unsigned int *added)
+{
+	struct richacl *acl = alloc->acl;
+	unsigned int x = RICHACE_POSIX_ALWAYS_ALLOWED;
+	unsigned int other_mask = acl->a_other_mask & ~x;
+	struct richace *ace;
+
+	if (!(other_mask &&
+	      (acl->a_flags & RICHACL_WRITE_THROUGH)))
+		return 0;
+
+	*added = other_mask;
+	ace = acl->a_entries + acl->a_count - 1;
+	if (acl->a_count == 0 ||
+	    !richace_is_everyone(ace) ||
+	    richace_is_inherit_only(ace)) {
+		ace++;
+		if (richacl_insert_entry(alloc, &ace))
+			return -1;
+		ace->e_type = RICHACE_ACCESS_ALLOWED_ACE_TYPE;
+		ace->e_flags = RICHACE_SPECIAL_WHO;
+		ace->e_mask = other_mask;
+		ace->e_id.special = RICHACE_EVERYONE_SPECIAL_ID;
+	} else {
+		*added &= ~ace->e_mask;
+		richace_change_mask(alloc, &ace, other_mask);
+	}
+	return 0;
+}
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1248868 — [PATCH v11 38/48] richacl: Add support for unmapped identifiers

FromAndreas Gruenbacher <agruenba@redhat.com>
Date2015-10-16 17:30 +0200
Subject[PATCH v11 38/48] richacl: Add support for unmapped identifiers
Message-ID<qkf7c-1SN-25@gated-at.bofh.it>
In reply to#1248844
Some remote file systems like nfs may return user or group identifiers
that cannot be mapped to local uids / gids.  Allow to represent such
unmapped identifiers in richacls.  (We still cannot represent unmapped
owners and owning groups, however.)

In the in-memory representation, the richacl is followed by a list of
NUL-terminated strings, with no padding.  Entries with an unmapped
identifier have the RICHACE_UNMAPPED_WHO flag set, and ace->e_id.offs
specifies the offset into this list.  Multiple entries can refer to the
same offset.

The xattr representation is similar, but ace->e_id is ignored, and the
list of unmapped identifier strings contains a string for each acl entry
whose RICHACE_UNMAPPED_WHO flag is set.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
 fs/richacl_base.c       | 139 ++++++++++++++++++++++++++++++++++++++++++++----
 fs/richacl_compat.c     |  18 +++----
 fs/richacl_inode.c      |   4 +-
 fs/richacl_xattr.c      |  69 ++++++++++++++++++++----
 include/linux/richacl.h |  32 +++++++++--
 5 files changed, 226 insertions(+), 36 deletions(-)

diff --git a/fs/richacl_base.c b/fs/richacl_base.c
index 3a97a82..f88d19b 100644
--- a/fs/richacl_base.c
+++ b/fs/richacl_base.c
@@ -23,22 +23,25 @@
 MODULE_LICENSE("GPL");
 
 /**
- * richacl_alloc  -  allocate a richacl
+ * __richacl_alloc  -  allocate a richacl
  * @count:	number of entries
+ * @unmapped_size:	size to reserve for unmapped identifiers
  */
 struct richacl *
-richacl_alloc(int count, gfp_t gfp)
+__richacl_alloc(unsigned int count, size_t unmapped_size, gfp_t gfp)
 {
-	size_t size = sizeof(struct richacl) + count * sizeof(struct richace);
+	size_t size = sizeof(struct richacl) + count * sizeof(struct richace) +
+		      unmapped_size;
 	struct richacl *acl = kzalloc(size, gfp);
 
 	if (acl) {
 		atomic_set(&acl->a_base.ba_refcount, 1);
 		acl->a_count = count;
+		acl->a_unmapped_size = unmapped_size;
 	}
 	return acl;
 }
-EXPORT_SYMBOL_GPL(richacl_alloc);
+EXPORT_SYMBOL_GPL(__richacl_alloc);
 
 /**
  * richacl_clone  -  create a copy of a richacl
@@ -47,7 +50,8 @@ 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);
+	size_t size = sizeof(struct richacl) + count * sizeof(struct richace) +
+		      acl->a_unmapped_size;
 	struct richacl *dup = kmalloc(size, gfp);
 
 	if (dup) {
@@ -59,6 +63,9 @@ richacl_clone(const struct richacl *acl, gfp_t gfp)
 
 /**
  * richace_copy  -  copy an acl entry
+ *
+ * If @from has an unmapped who value (from->e_flags & RICHACE_UNMAPPED_WHO),
+ * it can only be copied within the same acl!
  */
 void
 richace_copy(struct richace *to, const struct richace *from)
@@ -66,6 +73,82 @@ richace_copy(struct richace *to, const struct richace *from)
 	memcpy(to, from, sizeof(struct richace));
 }
 
+/**
+ * richacl_add_unmapped_identifier
+ * @pacl:	Pointer to an acl
+ * @pace:	acl entry within @acl
+ * @who:	unmapped identifier
+ * @len:	length of @who
+ * @gfp:	memory allocation flags
+ *
+ * Add an unmapped identifier to an acl, possibly reallocating the acl.
+ */
+int richacl_add_unmapped_identifier(struct richacl **pacl,
+				    struct richace **pace,
+				    const char *who,
+				    unsigned int len, gfp_t gfp)
+{
+	struct richacl *acl = *pacl;
+	size_t size = sizeof(struct richacl) +
+		      acl->a_count * sizeof(struct richace) +
+		      acl->a_unmapped_size + len + 1;
+	unsigned int index = *pace - acl->a_entries;
+
+	acl = krealloc(*pacl, size, gfp);
+	if (acl) {
+		char *unmapped = (char *)(acl->a_entries + acl->a_count);
+		struct richace *ace = acl->a_entries + index;
+
+		ace->e_flags |= RICHACE_UNMAPPED_WHO;
+		ace->e_flags &= ~RICHACE_SPECIAL_WHO;
+		ace->e_id.offs = acl->a_unmapped_size;
+		memcpy(unmapped + ace->e_id.offs, who, len);
+		unmapped[ace->e_id.offs + len] = 0;
+		acl->a_unmapped_size += len + 1;
+		*pace = ace;
+		*pacl = acl;
+		return 0;
+	}
+	return -1;
+}
+EXPORT_SYMBOL_GPL(richacl_add_unmapped_identifier);
+
+/**
+ * richace_unmapped_identifier  -  get unmapped identifier
+ * @acl:	acl containing @ace
+ * @ace:	acl entry
+ *
+ * Get the unmapped identifier of @ace as a NUL-terminated string, or NULL if
+ * @ace doesn't have an unmapped identifier.
+ */
+const char *richace_unmapped_identifier(const struct richace *ace,
+					const struct richacl *acl)
+{
+	const char *unmapped = (char *)(acl->a_entries + acl->a_count);
+
+	if (!(ace->e_flags & RICHACE_UNMAPPED_WHO))
+		return NULL;
+	return unmapped + ace->e_id.offs;
+}
+EXPORT_SYMBOL(richace_unmapped_identifier);
+
+/**
+ * richacl_has_unmapped_identifiers
+ *
+ * Check if an acl has unmapped identifiers.
+ */
+bool richacl_has_unmapped_identifiers(struct richacl *acl)
+{
+	struct richace *ace;
+
+	richacl_for_each_entry(ace, acl) {
+		if (ace->e_flags & RICHACE_UNMAPPED_WHO)
+			return true;
+	}
+	return false;
+}
+EXPORT_SYMBOL_GPL(richacl_has_unmapped_identifiers);
+
 /*
  * richacl_mask_to_mode  -  compute the file permission bits from mask
  * @mask:	%RICHACE_* permission mask
@@ -214,7 +297,7 @@ static unsigned int richacl_allowed_to_who(struct richacl *acl,
 	richacl_for_each_entry_reverse(ace, acl) {
 		if (richace_is_inherit_only(ace))
 			continue;
-		if (richace_is_same_identifier(ace, who) ||
+		if (richace_is_same_identifier(acl, ace, who) ||
 		    richace_is_everyone(ace)) {
 			if (richace_is_allow(ace))
 				allowed |= ace->e_mask;
@@ -505,45 +588,72 @@ richacl_inherit(const struct richacl *dir_acl, int isdir)
 	const struct richace *dir_ace;
 	struct richacl *acl = NULL;
 	struct richace *ace;
-	int count = 0;
+	unsigned int count = 0, unmapped_size = 0, offset = 0;
+	const char *dir_unmapped;
+	char *unmapped;
 
 	if (isdir) {
 		richacl_for_each_entry(dir_ace, dir_acl) {
 			if (!richace_is_inheritable(dir_ace))
 				continue;
+
 			count++;
+			dir_unmapped =
+				richace_unmapped_identifier(dir_ace, dir_acl);
+			if (dir_unmapped)
+				unmapped_size += strlen(dir_unmapped) + 1;
 		}
 		if (!count)
 			return NULL;
-		acl = richacl_alloc(count, GFP_KERNEL);
+		acl = __richacl_alloc(count, unmapped_size, GFP_KERNEL);
 		if (!acl)
 			return ERR_PTR(-ENOMEM);
 		ace = acl->a_entries;
+		unmapped = (char *)(acl->a_entries + acl->a_count);
 		richacl_for_each_entry(dir_ace, dir_acl) {
 			if (!richace_is_inheritable(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;
+
+			dir_unmapped =
+				richace_unmapped_identifier(dir_ace, dir_acl);
+			if (dir_unmapped) {
+				size_t sz = strlen(dir_unmapped) + 1;
+
+				ace->e_id.offs = offset;
+				memcpy(unmapped, dir_unmapped, sz);
+				unmapped += sz;
+				offset += sz;
+			}
 			ace++;
 		}
 	} else {
 		richacl_for_each_entry(dir_ace, dir_acl) {
 			if (!(dir_ace->e_flags & RICHACE_FILE_INHERIT_ACE))
 				continue;
+
 			count++;
+			dir_unmapped =
+				richace_unmapped_identifier(dir_ace, dir_acl);
+			if (dir_unmapped)
+				unmapped_size += strlen(dir_unmapped) + 1;
 		}
 		if (!count)
 			return NULL;
-		acl = richacl_alloc(count, GFP_KERNEL);
+		acl = __richacl_alloc(count, unmapped_size, GFP_KERNEL);
 		if (!acl)
 			return ERR_PTR(-ENOMEM);
 		ace = acl->a_entries;
+		unmapped = (char *)(acl->a_entries + acl->a_count);
 		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;
 			/*
@@ -551,6 +661,17 @@ richacl_inherit(const struct richacl *dir_acl, int isdir)
 			 * non-directories, so clear it.
 			 */
 			ace->e_mask &= ~RICHACE_DELETE_CHILD;
+
+			dir_unmapped =
+				richace_unmapped_identifier(dir_ace, dir_acl);
+			if (dir_unmapped) {
+				size_t sz = strlen(dir_unmapped) + 1;
+
+				ace->e_id.offs = offset;
+				memcpy(unmapped, dir_unmapped, sz);
+				unmapped += sz;
+				offset += sz;
+			}
 			ace++;
 		}
 	}
diff --git a/fs/richacl_compat.c b/fs/richacl_compat.c
index e513958..c5c670e 100644
--- a/fs/richacl_compat.c
+++ b/fs/richacl_compat.c
@@ -71,11 +71,13 @@ richacl_insert_entry(struct richacl_alloc *alloc, struct richace **ace)
 {
 	struct richacl *acl = alloc->acl;
 	unsigned int index = *ace - acl->a_entries;
-	size_t tail_size = (acl->a_count - index) * sizeof(struct richace);
+	size_t tail_size = (acl->a_count - index) * sizeof(struct richace) +
+			   acl->a_unmapped_size;
 
 	if (alloc->count == acl->a_count) {
 		size_t new_size = sizeof(struct richacl) +
-			(acl->a_count + 1) * sizeof(struct richace);
+			(acl->a_count + 1) * sizeof(struct richace) +
+			acl->a_unmapped_size;
 
 		acl = krealloc(acl, new_size, GFP_KERNEL);
 		if (!acl)
@@ -103,10 +105,6 @@ struct richace *richacl_append_entry(struct richacl_alloc *alloc)
 	struct richacl *acl = alloc->acl;
 	struct richace *ace = acl->a_entries + acl->a_count;
 
-	if (alloc->count > alloc->acl->a_count) {
-		acl->a_count++;
-		return ace;
-	}
 	return richacl_insert_entry(alloc, &ace) ? NULL : ace;
 }
 EXPORT_SYMBOL_GPL(richacl_append_entry);
@@ -261,12 +259,12 @@ __richacl_propagate_everyone(struct richacl_alloc *alloc, struct richace *who,
 		if (richace_is_inherit_only(ace))
 			continue;
 		if (richace_is_allow(ace)) {
-			if (richace_is_same_identifier(ace, who)) {
+			if (richace_is_same_identifier(acl, ace, who)) {
 				allow &= ~ace->e_mask;
 				allow_last = ace;
 			}
 		} else if (richace_is_deny(ace)) {
-			if (richace_is_same_identifier(ace, who))
+			if (richace_is_same_identifier(acl, ace, who))
 				allow &= ~ace->e_mask;
 			else if (allow & ace->e_mask)
 				allow_last = NULL;
@@ -613,7 +611,7 @@ __richacl_isolate_who(struct richacl_alloc *alloc, struct richace *who,
 	richacl_for_each_entry(ace, acl) {
 		if (richace_is_inherit_only(ace))
 			continue;
-		if (richace_is_same_identifier(ace, who))
+		if (richace_is_same_identifier(acl, ace, who))
 			deny &= ~ace->e_mask;
 	}
 	if (!deny)
@@ -629,7 +627,7 @@ __richacl_isolate_who(struct richacl_alloc *alloc, struct richace *who,
 		if (richace_is_inherit_only(ace))
 			continue;
 		if (richace_is_deny(ace)) {
-			if (richace_is_same_identifier(ace, who))
+			if (richace_is_same_identifier(acl, ace, who))
 				return richace_change_mask(alloc, &ace,
 							   ace->e_mask | deny);
 		} else if (richace_is_allow(ace) &&
diff --git a/fs/richacl_inode.c b/fs/richacl_inode.c
index b88a2f1..2f50389 100644
--- a/fs/richacl_inode.c
+++ b/fs/richacl_inode.c
@@ -161,8 +161,10 @@ richacl_permission(struct inode *inode, const struct richacl *acl,
 		} else if (richace_is_unix_group(ace)) {
 			if (!in_group_p(ace->e_id.gid))
 				continue;
-		} else
+		} else if (richace_is_everyone(ace))
 			goto entry_matches_everyone;
+		else
+			continue;
 
 		/*
 		 * Apply the group file mask to entries other than owner@ and
diff --git a/fs/richacl_xattr.c b/fs/richacl_xattr.c
index dc529dc..7ae5348 100644
--- a/fs/richacl_xattr.c
+++ b/fs/richacl_xattr.c
@@ -35,7 +35,8 @@ richacl_from_xattr(struct user_namespace *user_ns,
 	const struct richace_xattr *xattr_ace = (void *)(xattr_acl + 1);
 	struct richacl *acl;
 	struct richace *ace;
-	int count;
+	unsigned int count, offset;
+	char *unmapped;
 
 	if (size < sizeof(*xattr_acl) ||
 	    xattr_acl->a_version != RICHACL_XATTR_VERSION ||
@@ -45,10 +46,11 @@ richacl_from_xattr(struct user_namespace *user_ns,
 	count = le16_to_cpu(xattr_acl->a_count);
 	if (count > RICHACL_XATTR_MAX_COUNT)
 		return ERR_PTR(-EINVAL);
-	if (size != count * sizeof(*xattr_ace))
+	if (size < count * sizeof(*xattr_ace))
 		return ERR_PTR(-EINVAL);
+	size -= count * sizeof(*xattr_ace);
 
-	acl = richacl_alloc(count, GFP_NOFS);
+	acl = __richacl_alloc(count, size, GFP_NOFS);
 	if (!acl)
 		return ERR_PTR(-ENOMEM);
 
@@ -63,6 +65,16 @@ richacl_from_xattr(struct user_namespace *user_ns,
 	if (acl->a_other_mask & ~RICHACE_VALID_MASK)
 		goto fail_einval;
 
+	unmapped = (char *)(acl->a_entries + count);
+	if (size) {
+		char *xattr_unmapped = (char *)(xattr_ace + count);
+
+		if (xattr_unmapped[size - 1] != 0)
+			goto fail_einval;
+		memcpy(unmapped, xattr_unmapped, size);
+	}
+	offset = 0;
+
 	richacl_for_each_entry(ace, acl) {
 		ace->e_type  = le16_to_cpu(xattr_ace->e_type);
 		ace->e_flags = le16_to_cpu(xattr_ace->e_flags);
@@ -74,6 +86,15 @@ richacl_from_xattr(struct user_namespace *user_ns,
 			ace->e_id.special = le32_to_cpu(xattr_ace->e_id);
 			if (ace->e_id.special > RICHACE_EVERYONE_SPECIAL_ID)
 				goto fail_einval;
+		} else if (ace->e_flags & RICHACE_UNMAPPED_WHO) {
+			size_t sz;
+
+			if (offset == size)
+				goto fail_einval;
+			ace->e_id.offs = offset;
+			sz = strlen(unmapped) + 1;
+			unmapped += sz;
+			offset += sz;
 		} else if (ace->e_flags & RICHACE_IDENTIFIER_GROUP) {
 			u32 id = le32_to_cpu(xattr_ace->e_id);
 
@@ -90,10 +111,12 @@ richacl_from_xattr(struct user_namespace *user_ns,
 		if (ace->e_type > RICHACE_ACCESS_DENIED_ACE_TYPE ||
 		    (ace->e_mask & ~RICHACE_VALID_MASK))
 			goto fail_einval;
-
 		xattr_ace++;
 	}
 
+	if (offset != size)
+		goto fail_einval;
+
 	return acl;
 
 fail_einval:
@@ -109,8 +132,15 @@ size_t
 richacl_xattr_size(const struct richacl *acl)
 {
 	size_t size = sizeof(struct richacl_xattr);
+	const struct richace *ace;
 
 	size += sizeof(struct richace_xattr) * acl->a_count;
+	richacl_for_each_entry(ace, acl) {
+		const char *unmapped = richace_unmapped_identifier(ace, acl);
+
+		if (unmapped)
+			size += strlen(unmapped) + 1;
+	}
 	return size;
 }
 EXPORT_SYMBOL_GPL(richacl_xattr_size);
@@ -129,6 +159,7 @@ richacl_to_xattr(struct user_namespace *user_ns,
 	struct richace_xattr *xattr_ace;
 	const struct richace *ace;
 	size_t real_size;
+	char *xattr_unmapped;
 
 	real_size = richacl_xattr_size(acl);
 	if (!buffer)
@@ -145,18 +176,33 @@ richacl_to_xattr(struct user_namespace *user_ns,
 	xattr_acl->a_other_mask = cpu_to_le32(acl->a_other_mask);
 
 	xattr_ace = (void *)(xattr_acl + 1);
+	xattr_unmapped = (char *)(xattr_ace + acl->a_count);
 	richacl_for_each_entry(ace, acl) {
+		const char *who;
+
 		xattr_ace->e_type = cpu_to_le16(ace->e_type);
 		xattr_ace->e_flags = cpu_to_le16(ace->e_flags);
 		xattr_ace->e_mask = cpu_to_le32(ace->e_mask);
 		if (ace->e_flags & RICHACE_SPECIAL_WHO)
 			xattr_ace->e_id = cpu_to_le32(ace->e_id.special);
-		else if (ace->e_flags & RICHACE_IDENTIFIER_GROUP)
-			xattr_ace->e_id =
-				cpu_to_le32(from_kgid(user_ns, ace->e_id.gid));
-		else
-			xattr_ace->e_id =
-				cpu_to_le32(from_kuid(user_ns, ace->e_id.uid));
+		else {
+			who = richace_unmapped_identifier(ace, acl);
+			if (who) {
+				size_t sz = strlen(who) + 1;
+
+				xattr_ace->e_id = 0;
+				memcpy(xattr_unmapped, who, sz);
+				xattr_unmapped += sz;
+			} else if (ace->e_flags & RICHACE_IDENTIFIER_GROUP) {
+				u32 id = from_kgid(user_ns, ace->e_id.gid);
+
+				xattr_ace->e_id = cpu_to_le32(id);
+			} else {
+				u32 id = from_kuid(user_ns, ace->e_id.uid);
+
+				xattr_ace->e_id = cpu_to_le32(id);
+			}
+		}
 		xattr_ace++;
 	}
 	return real_size;
@@ -262,7 +308,8 @@ static void richacl_fix_xattr_userns(
 		return;
 	count = size / sizeof(*xattr_ace);
 	for (; count; count--, xattr_ace++) {
-		if (xattr_ace->e_flags & cpu_to_le16(RICHACE_SPECIAL_WHO))
+		if (xattr_ace->e_flags & cpu_to_le16(RICHACE_SPECIAL_WHO |
+						     RICHACE_UNMAPPED_WHO))
 			continue;
 		if (xattr_ace->e_flags &
 		    cpu_to_le16(RICHACE_IDENTIFIER_GROUP)) {
diff --git a/include/linux/richacl.h b/include/linux/richacl.h
index 6d2e5bd..a9751a7 100644
--- a/include/linux/richacl.h
+++ b/include/linux/richacl.h
@@ -27,6 +27,7 @@ struct richace {
 		kuid_t		uid;
 		kgid_t		gid;
 		unsigned int	special;
+		unsigned short	offs;  /* unmapped offset */
 	} e_id;
 };
 
@@ -37,6 +38,7 @@ struct richacl {
 	unsigned int	a_other_mask;
 	unsigned short	a_count;
 	unsigned short	a_flags;
+	unsigned short	a_unmapped_size;
 	struct richace	a_entries[0];
 };
 
@@ -54,6 +56,7 @@ struct richacl {
 	RICHACE_INHERIT_ONLY_ACE |				\
 	RICHACE_IDENTIFIER_GROUP |				\
 	RICHACE_INHERITED_ACE |					\
+	RICHACE_UNMAPPED_WHO |					\
 	RICHACE_SPECIAL_WHO)
 
 #define RICHACE_INHERITANCE_FLAGS (				\
@@ -224,14 +227,28 @@ richace_is_deny(const struct richace *ace)
  * richace_is_same_identifier  -  are both identifiers the same?
  */
 static inline bool
-richace_is_same_identifier(const struct richace *a, const struct richace *b)
+richace_is_same_identifier(const struct richacl *acl,
+			   const struct richace *ace1,
+			   const struct richace *ace2)
 {
-	return !((a->e_flags ^ b->e_flags) &
-		 (RICHACE_SPECIAL_WHO | RICHACE_IDENTIFIER_GROUP)) &&
-	       !memcmp(&a->e_id, &b->e_id, sizeof(a->e_id));
+	const char *unmapped = (char *)(acl->a_entries + acl->a_count);
+
+	return !((ace1->e_flags ^ ace2->e_flags) &
+		 (RICHACE_SPECIAL_WHO |
+		  RICHACE_IDENTIFIER_GROUP |
+		  RICHACE_UNMAPPED_WHO)) &&
+	       ((ace1->e_flags & RICHACE_UNMAPPED_WHO) ?
+		!strcmp(unmapped + ace1->e_id.offs,
+			unmapped + ace2->e_id.offs) :
+		!memcmp(&ace1->e_id, &ace2->e_id, sizeof(ace1->e_id)));
+}
+
+extern struct richacl *__richacl_alloc(unsigned int, size_t, gfp_t);
+static inline struct richacl *richacl_alloc(unsigned int count, gfp_t gfp)
+{
+	return __richacl_alloc(count, 0, gfp);
 }
 
-extern struct richacl *richacl_alloc(int, gfp_t);
 extern struct richacl *richacl_clone(const struct richacl *, gfp_t);
 extern void richace_copy(struct richace *, const struct richace *);
 extern int richacl_masks_to_mode(const struct richacl *);
@@ -241,6 +258,11 @@ extern void richacl_compute_max_masks(struct richacl *);
 extern struct richacl *__richacl_chmod(struct richacl *, umode_t);
 extern int richacl_equiv_mode(const struct richacl *, umode_t *);
 extern struct richacl *richacl_inherit(const struct richacl *, int);
+extern int richacl_add_unmapped_identifier(struct richacl **, struct richace **,
+					   const char *, unsigned int, gfp_t);
+extern const char *richace_unmapped_identifier(const struct richace *,
+					       const struct richacl *);
+extern bool richacl_has_unmapped_identifiers(struct richacl *);
 
 /* richacl_inode.c */
 extern int richacl_permission(struct inode *, const struct richacl *, int);
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1248870 — [PATCH v11 48/48] nfs: Add support for the v4.1 dacl attribute

FromAndreas Gruenbacher <agruenba@redhat.com>
Date2015-10-16 17:30 +0200
Subject[PATCH v11 48/48] nfs: Add support for the v4.1 dacl attribute
Message-ID<qkf7c-1SN-33@gated-at.bofh.it>
In reply to#1248844
The dacl attribute includes Automatic Inheritance flags not supported by
the acl attribute.  it is only supported in NFS version 4.1 and higher.
On systems where NFS version 4.0 is still the default, an additional
mount option is needed:

    mount -t nfs4 -o vers=4.1 [...]

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
 fs/nfs/nfs4proc.c       |  2 +-
 fs/nfs/nfs4xdr.c        | 54 ++++++++++++++++++++++++++++++++++++++++++-------
 include/linux/nfs_xdr.h |  2 +-
 3 files changed, 49 insertions(+), 9 deletions(-)

diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 7bb2dea..191369f 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -4556,7 +4556,7 @@ static struct richacl *__nfs4_get_acl_uncached(struct inode *inode)
 	struct nfs_server *server = NFS_SERVER(inode);
 	struct page *pages[DIV_ROUND_UP(NFS4ACL_SIZE_MAX, PAGE_SIZE)] = {};
 	struct nfs_getaclargs args = {
-		.fh = NFS_FH(inode),
+		.inode = inode,
 		.acl_pages = pages,
 		.acl_len = ARRAY_SIZE(pages) * PAGE_SIZE,
 	};
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 2f1d6be..a73f7c6 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -1661,9 +1661,16 @@ encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compoun
 	encode_nfs4_stateid(xdr, &zero_stateid);
 
 	/* Encode attribute bitmap. */
-	p = reserve_space(xdr, 2*4);
-	*p++ = cpu_to_be32(1);
-	*p = cpu_to_be32(FATTR4_WORD0_ACL);
+	if (arg->server->attr_bitmask[1] & FATTR4_WORD1_DACL) {
+		p = reserve_space(xdr, 3*4);
+		*p++ = cpu_to_be32(2);
+		*p++ = 0;
+		*p = cpu_to_be32(FATTR4_WORD1_DACL);
+	} else {
+		p = reserve_space(xdr, 2*4);
+		*p++ = cpu_to_be32(1);
+		*p = cpu_to_be32(FATTR4_WORD0_ACL);
+	}
 
 	attrlen_offset = xdr->buf->len;
 	xdr_reserve_space(xdr, 4);  /* to be backfilled later */
@@ -2498,9 +2505,12 @@ static void nfs4_xdr_enc_getacl(struct rpc_rqst *req, struct xdr_stream *xdr,
 
 	encode_compound_hdr(xdr, req, &hdr);
 	encode_sequence(xdr, &args->seq_args, &hdr);
-	encode_putfh(xdr, args->fh, &hdr);
+	encode_putfh(xdr, NFS_FH(args->inode), &hdr);
 	replen = hdr.replen + op_decode_hdr_maxsz + 1;
-	encode_getattr_two(xdr, FATTR4_WORD0_ACL, FATTR4_WORD1_MODE, &hdr);
+	if (NFS_SERVER(args->inode)->attr_bitmask[1] & FATTR4_WORD1_DACL)
+		encode_getattr_two(xdr, 0, FATTR4_WORD1_MODE | FATTR4_WORD1_DACL, &hdr);
+	else
+		encode_getattr_two(xdr, FATTR4_WORD0_ACL, FATTR4_WORD1_MODE, &hdr);
 
 	xdr_inline_pages(&req->rq_rcv_buf, replen << 2,
 		args->acl_pages, 0, args->acl_len);
@@ -5402,12 +5412,25 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
 
 	if (unlikely(bitmap[0] & (FATTR4_WORD0_ACL - 1U)))
 		return -EIO;
-	if (likely(bitmap[0] & FATTR4_WORD0_ACL)) {
+
+	if (bitmap[0] & FATTR4_WORD0_ACL) {
+		struct richace *ace;
+
+		if (bitmap[1] & FATTR4_WORD1_DACL)
+			return -EIO;
+
 		acl = decode_acl_entries(xdr, res->server);
 		if (IS_ERR(acl))
 			return PTR_ERR(acl);
+
+		status = -EIO;
+		richacl_for_each_entry(ace, acl) {
+			if (ace->e_flags & RICHACE_INHERITED_ACE)
+				goto out;
+		}
+
 		bitmap[0] &= ~FATTR4_WORD0_ACL;
-	} else
+	} else if (!(bitmap[1] & FATTR4_WORD1_DACL))
 		return -EOPNOTSUPP;
 
 	status = -EIO;
@@ -5417,6 +5440,23 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
 	status = decode_attr_mode(xdr, bitmap, &res->mode);
 	if (status < 0)
 		goto out;
+
+	if (bitmap[1] & FATTR4_WORD1_DACL) {
+		unsigned int flags;
+		__be32 *p;
+
+		p = xdr_inline_decode(xdr, 4);
+		if (unlikely(!p))
+			return -EIO;
+		flags = be32_to_cpup(p);
+
+		acl = decode_acl_entries(xdr, res->server);
+		if (IS_ERR(acl))
+			return PTR_ERR(acl);
+
+		acl->a_flags = flags;
+		bitmap[1] &= ~FATTR4_WORD1_DACL;
+	}
 	status = 0;
 
 out:
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 337c341..9c2a078 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -695,7 +695,7 @@ struct nfs_setaclres {
 
 struct nfs_getaclargs {
 	struct nfs4_sequence_args 	seq_args;
-	struct nfs_fh *			fh;
+	struct inode *			inode;
 	size_t				acl_len;
 	struct page **			acl_pages;
 };
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1248871 — [PATCH v11 24/48] xfs: Add richacl support

FromAndreas Gruenbacher <agruenba@redhat.com>
Date2015-10-16 17:30 +0200
Subject[PATCH v11 24/48] xfs: Add richacl support
Message-ID<qkf7d-1SN-35@gated-at.bofh.it>
In reply to#1248844
The richacl feature flag (mkfs.xfs -m richacl=1) determines whether an xfs
filesystem supports posix acls or richacls.  Richacls are stored in
"system.richacl" xattrs.

On the grounds that richacls add relatively little overhead compared to the
size of xfs itself, to keep the testing matrix small, and because xfs users
are highly likely to enable richacls anyway, richacl support cannot be
compiled out in xfs.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
 fs/xfs/Kconfig             |   1 +
 fs/xfs/Makefile            |   1 +
 fs/xfs/libxfs/xfs_format.h |  11 ++++-
 fs/xfs/xfs_iops.c          |  44 +++++++++++++++----
 fs/xfs/xfs_richacl.c       | 102 +++++++++++++++++++++++++++++++++++++++++++++
 fs/xfs/xfs_richacl.h       |  23 ++++++++++
 fs/xfs/xfs_super.c         |   6 ++-
 fs/xfs/xfs_super.h         |   4 ++
 fs/xfs/xfs_xattr.c         |   2 +
 9 files changed, 183 insertions(+), 11 deletions(-)
 create mode 100644 fs/xfs/xfs_richacl.c
 create mode 100644 fs/xfs/xfs_richacl.h

diff --git a/fs/xfs/Kconfig b/fs/xfs/Kconfig
index 5d47b4d..3fd00f8 100644
--- a/fs/xfs/Kconfig
+++ b/fs/xfs/Kconfig
@@ -4,6 +4,7 @@ config XFS_FS
 	depends on (64BIT || LBDAF)
 	select EXPORTFS
 	select LIBCRC32C
+	select FS_RICHACL
 	help
 	  XFS is a high performance journaling filesystem which originated
 	  on the SGI IRIX platform.  It is completely multi-threaded, can
diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
index a096841..1e6b984 100644
--- a/fs/xfs/Makefile
+++ b/fs/xfs/Makefile
@@ -84,6 +84,7 @@ xfs-y				+= xfs_aops.o \
 				   xfs_message.o \
 				   xfs_mount.o \
 				   xfs_mru_cache.o \
+				   xfs_richacl.o \
 				   xfs_super.o \
 				   xfs_symlink.o \
 				   xfs_sysfs.o \
diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index 9590a06..923247c 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -461,10 +461,13 @@ xfs_sb_has_ro_compat_feature(
 #define XFS_SB_FEAT_INCOMPAT_FTYPE	(1 << 0)	/* filetype in dirent */
 #define XFS_SB_FEAT_INCOMPAT_SPINODES	(1 << 1)	/* sparse inode chunks */
 #define XFS_SB_FEAT_INCOMPAT_META_UUID	(1 << 2)	/* metadata UUID */
+#define XFS_SB_FEAT_INCOMPAT_RICHACL	(1 << 3)	/* richacls */
+
 #define XFS_SB_FEAT_INCOMPAT_ALL \
 		(XFS_SB_FEAT_INCOMPAT_FTYPE|	\
 		 XFS_SB_FEAT_INCOMPAT_SPINODES|	\
-		 XFS_SB_FEAT_INCOMPAT_META_UUID)
+		 XFS_SB_FEAT_INCOMPAT_META_UUID| \
+		 XFS_SB_FEAT_INCOMPAT_RICHACL)
 
 #define XFS_SB_FEAT_INCOMPAT_UNKNOWN	~XFS_SB_FEAT_INCOMPAT_ALL
 static inline bool
@@ -530,6 +533,12 @@ static inline bool xfs_sb_version_hasmetauuid(struct xfs_sb *sbp)
 		(sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_META_UUID);
 }
 
+static inline bool xfs_sb_version_hasrichacl(struct xfs_sb *sbp)
+{
+	return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) &&
+		(sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_RICHACL);
+}
+
 /*
  * end of superblock version macros
  */
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index 8294132..9e4103b 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -27,6 +27,7 @@
 #include "xfs_bmap.h"
 #include "xfs_bmap_util.h"
 #include "xfs_acl.h"
+#include "xfs_richacl.h"
 #include "xfs_quota.h"
 #include "xfs_error.h"
 #include "xfs_attr.h"
@@ -42,6 +43,7 @@
 #include <linux/capability.h>
 #include <linux/xattr.h>
 #include <linux/posix_acl.h>
+#include <linux/richacl.h>
 #include <linux/security.h>
 #include <linux/fiemap.h>
 #include <linux/slab.h>
@@ -133,7 +135,8 @@ xfs_generic_create(
 {
 	struct inode	*inode;
 	struct xfs_inode *ip = NULL;
-	struct posix_acl *default_acl, *acl;
+	struct posix_acl *default_acl = NULL, *acl = NULL;
+	struct richacl *richacl = NULL;
 	struct xfs_name	name;
 	int		error;
 
@@ -149,9 +152,15 @@ xfs_generic_create(
 		rdev = 0;
 	}
 
-	error = posix_acl_create(dir, &mode, &default_acl, &acl);
-	if (error)
-		return error;
+	if (IS_RICHACL(dir)) {
+		richacl = richacl_create(&mode, dir);
+		if (IS_ERR(richacl))
+			return PTR_ERR(richacl);
+	} else {
+		error = posix_acl_create(dir, &mode, &default_acl, &acl);
+		if (error)
+			return error;
+	}
 
 	if (!tmpfile) {
 		xfs_dentry_to_name(&name, dentry, mode);
@@ -180,6 +189,11 @@ xfs_generic_create(
 			goto out_cleanup_inode;
 	}
 #endif
+	if (richacl) {
+		error = xfs_set_richacl(inode, richacl);
+		if (error)
+			goto out_cleanup_inode;
+	}
 
 	if (tmpfile)
 		d_tmpfile(dentry, inode);
@@ -189,10 +203,9 @@ xfs_generic_create(
 	xfs_finish_inode_setup(ip);
 
  out_free_acl:
-	if (default_acl)
-		posix_acl_release(default_acl);
-	if (acl)
-		posix_acl_release(acl);
+	posix_acl_release(default_acl);
+	posix_acl_release(acl);
+	richacl_put(richacl);
 	return error;
 
  out_cleanup_inode:
@@ -534,6 +547,13 @@ xfs_setattr_time(
 	}
 }
 
+static inline int
+xfs_acl_chmod(struct inode *inode, umode_t mode)
+{
+	if (IS_RICHACL(inode))
+		return richacl_chmod(inode, inode->i_mode);
+	return posix_acl_chmod(inode, inode->i_mode);
+}
 int
 xfs_setattr_nonsize(
 	struct xfs_inode	*ip,
@@ -722,7 +742,7 @@ xfs_setattr_nonsize(
 	 * 	     Posix ACL code seems to care about this issue either.
 	 */
 	if ((mask & ATTR_MODE) && !(flags & XFS_ATTR_NOACL)) {
-		error = posix_acl_chmod(inode, inode->i_mode);
+		error = xfs_acl_chmod(inode, inode->i_mode);
 		if (error)
 			return error;
 	}
@@ -1104,6 +1124,8 @@ xfs_vn_tmpfile(
 static const struct inode_operations xfs_inode_operations = {
 	.get_acl		= xfs_get_acl,
 	.set_acl		= xfs_set_acl,
+	.get_richacl		= xfs_get_richacl,
+	.set_richacl		= xfs_set_richacl,
 	.getattr		= xfs_vn_getattr,
 	.setattr		= xfs_vn_setattr,
 	.setxattr		= generic_setxattr,
@@ -1132,6 +1154,8 @@ static const struct inode_operations xfs_dir_inode_operations = {
 	.rename2		= xfs_vn_rename,
 	.get_acl		= xfs_get_acl,
 	.set_acl		= xfs_set_acl,
+	.get_richacl		= xfs_get_richacl,
+	.set_richacl		= xfs_set_richacl,
 	.getattr		= xfs_vn_getattr,
 	.setattr		= xfs_vn_setattr,
 	.setxattr		= generic_setxattr,
@@ -1160,6 +1184,8 @@ static const struct inode_operations xfs_dir_ci_inode_operations = {
 	.rename2		= xfs_vn_rename,
 	.get_acl		= xfs_get_acl,
 	.set_acl		= xfs_set_acl,
+	.get_richacl		= xfs_get_richacl,
+	.set_richacl		= xfs_set_richacl,
 	.getattr		= xfs_vn_getattr,
 	.setattr		= xfs_vn_setattr,
 	.setxattr		= generic_setxattr,
diff --git a/fs/xfs/xfs_richacl.c b/fs/xfs/xfs_richacl.c
new file mode 100644
index 0000000..73c2d24
--- /dev/null
+++ b/fs/xfs/xfs_richacl.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2015  Red Hat, Inc.
+ * Author: 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 "xfs.h"
+#include "xfs_format.h"
+#include "xfs_log_format.h"
+#include "xfs_inode.h"
+#include "xfs_attr.h"
+
+#include <linux/richacl_xattr.h>
+
+struct richacl *
+xfs_get_richacl(struct inode *inode)
+{
+	struct xfs_inode *ip = XFS_I(inode);
+	struct richacl *acl = NULL;
+	int size = XATTR_SIZE_MAX;
+	void *value;
+	int error;
+
+	value = kmem_zalloc_large(size, KM_SLEEP);
+	if (!value)
+		return ERR_PTR(-ENOMEM);
+
+	error = xfs_attr_get(ip, XATTR_NAME_RICHACL, value, &size, ATTR_ROOT);
+	if (error) {
+		/*
+		 * If the attribute doesn't exist make sure we have a negative
+		 * cache entry, for any other error assume it is transient and
+		 * leave the cache entry as ACL_NOT_CACHED.
+		 */
+		if (error != -ENOATTR)
+			acl = ERR_PTR(error);
+	} else
+		acl = richacl_from_xattr(&init_user_ns, value, size);
+
+	if (!IS_ERR(acl))
+		set_cached_richacl(inode, acl);
+	kfree(value);
+
+	return acl;
+}
+
+static int
+xfs_remove_richacl(struct inode *inode)
+{
+	struct xfs_inode *ip = XFS_I(inode);
+	int error;
+
+	error = xfs_attr_remove(ip, XATTR_NAME_RICHACL, ATTR_ROOT);
+	if (error == -ENOATTR)
+		error = 0;
+	if (!error)
+		set_cached_richacl(inode, NULL);
+	return error;
+}
+
+int
+xfs_set_richacl(struct inode *inode, struct richacl *acl)
+{
+	struct xfs_inode *ip = XFS_I(inode);
+	umode_t mode = inode->i_mode;
+	int error, size;
+	void *value;
+
+	if (!acl)
+		return xfs_remove_richacl(inode);
+
+	if (richacl_equiv_mode(acl, &mode) == 0) {
+		xfs_set_mode(inode, mode);
+		return xfs_remove_richacl(inode);
+	}
+
+	size = richacl_xattr_size(acl);
+	value = kmem_zalloc_large(size, KM_SLEEP);
+	if (!value)
+		return -ENOMEM;
+	richacl_to_xattr(&init_user_ns, acl, value, size);
+	error = xfs_attr_set(ip, XATTR_NAME_RICHACL, value, size,
+			     ATTR_ROOT);
+	kfree(value);
+	if (error)
+		return error;
+
+	mode &= ~S_IRWXUGO;
+	mode |= richacl_masks_to_mode(acl);
+	xfs_set_mode(inode, mode);
+	set_cached_richacl(inode, acl);
+
+	return 0;
+}
diff --git a/fs/xfs/xfs_richacl.h b/fs/xfs/xfs_richacl.h
new file mode 100644
index 0000000..431aa25
--- /dev/null
+++ b/fs/xfs/xfs_richacl.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C)  2015 Red Hat, Inc.
+ * Author: 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.
+ *
+ */
+
+#ifndef __FS_XFS_RICHACL_H
+#define __FS_XFS_RICHACL_H
+
+struct richacl;
+
+extern struct richacl *xfs_get_richacl(struct inode *);
+extern int xfs_set_richacl(struct inode *, struct richacl *);
+
+#endif  /* __FS_XFS_RICHACL_H */
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index 904f637..f82ce1a 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -1500,7 +1500,11 @@ xfs_fs_fill_super(
 	sb->s_maxbytes = xfs_max_file_offset(sb->s_blocksize_bits);
 	sb->s_max_links = XFS_MAXLINK;
 	sb->s_time_gran = 1;
-	set_posix_acl_flag(sb);
+
+	if (xfs_sb_version_hasrichacl(&mp->m_sb))
+		set_richacl_flag(sb);
+	else
+		set_posix_acl_flag(sb);
 
 	/* version 5 superblocks support inode version counters. */
 	if (XFS_SB_VERSION_NUM(&mp->m_sb) == XFS_SB_VERSION_5)
diff --git a/fs/xfs/xfs_super.h b/fs/xfs/xfs_super.h
index 499058f..7ae21d9 100644
--- a/fs/xfs/xfs_super.h
+++ b/fs/xfs/xfs_super.h
@@ -36,6 +36,9 @@ extern void xfs_qm_exit(void);
 # define set_posix_acl_flag(sb)	do { } while (0)
 #endif
 
+# define XFS_RICHACL_STRING	"Richacls, "
+# define set_richacl_flag(sb)	((sb)->s_flags |= MS_RICHACL)
+
 #define XFS_SECURITY_STRING	"security attributes, "
 
 #ifdef CONFIG_XFS_RT
@@ -52,6 +55,7 @@ extern void xfs_qm_exit(void);
 
 #define XFS_VERSION_STRING	"SGI XFS"
 #define XFS_BUILD_OPTIONS	XFS_ACL_STRING \
+				XFS_RICHACL_STRING \
 				XFS_SECURITY_STRING \
 				XFS_REALTIME_STRING \
 				XFS_DBG_STRING /* DBG must be last */
diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
index c0368151..62dc913 100644
--- a/fs/xfs/xfs_xattr.c
+++ b/fs/xfs/xfs_xattr.c
@@ -28,6 +28,7 @@
 #include "xfs_acl.h"
 
 #include <linux/posix_acl_xattr.h>
+#include <linux/richacl_xattr.h>
 #include <linux/xattr.h>
 
 
@@ -103,6 +104,7 @@ const struct xattr_handler *xfs_xattr_handlers[] = {
 	&posix_acl_access_xattr_handler,
 	&posix_acl_default_xattr_handler,
 #endif
+	&richacl_xattr_handler,
 	NULL
 };
 
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1248873 — [PATCH v11 45/48] nfs: Remove unused xdr page offsets in getacl/setacl arguments

FromAndreas Gruenbacher <agruenba@redhat.com>
Date2015-10-16 17:30 +0200
Subject[PATCH v11 45/48] nfs: Remove unused xdr page offsets in getacl/setacl arguments
Message-ID<qkf7d-1SN-39@gated-at.bofh.it>
In reply to#1248844
The arguments passed around for getacl and setacl xdr encoding, struct
nfs_setaclargs and struct nfs_getaclargs, both contain an array of
pages, an offset into the first page, and the length of the page data.
The offset is unused as it is always zero; remove it.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
 fs/nfs/nfs4proc.c       | 5 ++---
 fs/nfs/nfs4xdr.c        | 4 ++--
 include/linux/nfs_xdr.h | 2 --
 3 files changed, 4 insertions(+), 7 deletions(-)

diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 5133bb1..eec5c4c 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -4530,7 +4530,7 @@ static inline int nfs4_server_supports_acls(struct nfs_server *server)
 #define NFS4ACL_MAXPAGES DIV_ROUND_UP(XATTR_SIZE_MAX, PAGE_SIZE)
 
 static int buf_to_pages_noslab(const void *buf, size_t buflen,
-		struct page **pages, unsigned int *pgbase)
+		struct page **pages)
 {
 	struct page *newpage, **spages;
 	int rc = 0;
@@ -4674,7 +4674,6 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
 		goto out_free;
 
 	args.acl_len = npages * PAGE_SIZE;
-	args.acl_pgbase = 0;
 
 	dprintk("%s  buf %p buflen %zu npages %d args.acl_len %zu\n",
 		__func__, buf, buflen, npages, args.acl_len);
@@ -4766,7 +4765,7 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl
 		return -EOPNOTSUPP;
 	if (npages > ARRAY_SIZE(pages))
 		return -ERANGE;
-	i = buf_to_pages_noslab(buf, buflen, arg.acl_pages, &arg.acl_pgbase);
+	i = buf_to_pages_noslab(buf, buflen, arg.acl_pages);
 	if (i < 0)
 		return i;
 	nfs4_inode_return_delegation(inode);
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 6f6d921..eefed15 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -1659,7 +1659,7 @@ encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compoun
 	*p = cpu_to_be32(FATTR4_WORD0_ACL);
 	p = reserve_space(xdr, 4);
 	*p = cpu_to_be32(arg->acl_len);
-	xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len);
+	xdr_write_pages(xdr, arg->acl_pages, 0, arg->acl_len);
 }
 
 static void
@@ -2491,7 +2491,7 @@ static void nfs4_xdr_enc_getacl(struct rpc_rqst *req, struct xdr_stream *xdr,
 	encode_getattr_two(xdr, FATTR4_WORD0_ACL, 0, &hdr);
 
 	xdr_inline_pages(&req->rq_rcv_buf, replen << 2,
-		args->acl_pages, args->acl_pgbase, args->acl_len);
+		args->acl_pages, 0, args->acl_len);
 
 	encode_nops(&hdr);
 }
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 52faf7e..090ade4 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -685,7 +685,6 @@ struct nfs_setaclargs {
 	struct nfs4_sequence_args	seq_args;
 	struct nfs_fh *			fh;
 	size_t				acl_len;
-	unsigned int			acl_pgbase;
 	struct page **			acl_pages;
 };
 
@@ -697,7 +696,6 @@ struct nfs_getaclargs {
 	struct nfs4_sequence_args 	seq_args;
 	struct nfs_fh *			fh;
 	size_t				acl_len;
-	unsigned int			acl_pgbase;
 	struct page **			acl_pages;
 };
 
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


Page 1 of 3  [1] 2 3  Next page →

Back to top | Article view | linux.kernel


csiph-web