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


Groups > linux.kernel > #1244246 > unrolled thread

[PATCH v10 00/46] Richacls

Started byAndreas Gruenbacher <andreas.gruenbacher@gmail.com>
First post2015-10-12 01:00 +0200
Last post2015-10-12 01:50 +0200
Articles 20 on this page of 58 — 6 participants

Back to article view | Back to linux.kernel


Contents

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

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


#1244246 — [PATCH v10 00/46] Richacls

FromAndreas Gruenbacher <andreas.gruenbacher@gmail.com>
Date2015-10-12 01:00 +0200
Subject[PATCH v10 00/46] Richacls
Message-ID<qixKV-5z8-9@gated-at.bofh.it>
From: Andreas Gruenbacher <agruenba@redhat.com>

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
(https://lwn.net/Articles/659350/):

 * Support for xfs; this depends on a new incompatible feature
   flag.  The user-space changes can be found here:

     https://github.com/andreas-gruenbacher/xfsprogs.git

 * ext4: Update ctime when setting a mode-equivalent richacl.

 * The richacl_inherit_inode and richacl_create helpers now take a
   umode_t argument instead of an inode (xfs uses richacl_create
   before creating an inode).  Some other minor changes.


The complete patch queue is available here:

  git://git.kernel.org/pub/scm/linux/kernel/git/agruen/linux-richacl.git \
  	richacl-2015-10-12


The richacl user-space utilitites and test suite are available here:

  https://github.com/andreas-gruenbacher/richacl/


Some more information is avaliable here:

  http://www.bestbits.at/richacl/


We still have two open issues in nfs, but those only affect nfs.


Thanks,
Andreas


Andreas Gruenbacher (44):
  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
  ext4: 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: Add richacl support
  nfs: Add support for the v4.1 dacl attribute
  richacl: uapi header split

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                                |   7 +-
 fs/ext4/inode.c                                 |  10 +-
 fs/ext4/namei.c                                 |   5 +
 fs/ext4/richacl.c                               | 133 ++++
 fs/ext4/richacl.h                               |  42 ++
 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/nfs4proc.c                               | 701 +++++++++++++-----
 fs/nfs/nfs4xdr.c                                | 257 ++++++-
 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                               | 482 +++++++------
 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                                  |  11 +
 fs/xfs/Makefile                                 |   1 +
 fs/xfs/libxfs/xfs_format.h                      |  16 +-
 fs/xfs/xfs_acl.c                                |  37 +-
 fs/xfs/xfs_acl.h                                |   1 -
 fs/xfs/xfs_inode.c                              |  18 +
 fs/xfs/xfs_inode.h                              |   2 +
 fs/xfs/xfs_iops.c                               |  42 +-
 fs/xfs/xfs_richacl.c                            |  97 +++
 fs/xfs/xfs_richacl.h                            |  34 +
 fs/xfs/xfs_super.c                              |  14 +-
 fs/xfs/xfs_super.h                              |   9 +-
 fs/xfs/xfs_xattr.c                              |   4 +
 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                       |   2 +
 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                   |  49 ++
 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              |  43 ++
 include/uapi/linux/xattr.h                      |   2 +
 net/sunrpc/xdr.c                                |  34 +
 72 files changed, 4916 insertions(+), 761 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]


#1244247 — [PATCH v10 37/46] nfsd: Add support for the MAY_CREATE_{FILE,DIR} permissions

FromAndreas Gruenbacher <andreas.gruenbacher@gmail.com>
Date2015-10-12 01:10 +0200
Subject[PATCH v10 37/46] nfsd: Add support for the MAY_CREATE_{FILE,DIR} permissions
Message-ID<qixUB-61y-1@gated-at.bofh.it>
In reply to#1244246
From: Andreas Gruenbacher <agruenba@redhat.com>

For local file systems, the vfs performs the necessary permission checks
for operations like creating files and directories.  NFSd duplicates
several of those checks.  The vfs checks have been extended to check for
additional permissions like MAY_CREATE_FILE and MY_CREATE_DIR; the nfsd
checks currently lack those extensions.

Ideally, all duplicate checks should be removed; for now, just fix the
duplicate checks instead though.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Acked-by: J. Bruce Fields <bfields@redhat.com>
---
 fs/nfsd/nfs4proc.c |  5 +++--
 fs/nfsd/nfsfh.c    |  8 ++++----
 fs/nfsd/vfs.c      | 28 ++++++++++++++++++++--------
 fs/nfsd/vfs.h      | 17 +++++++++--------
 4 files changed, 36 insertions(+), 22 deletions(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index a053e78..8d476ff 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -599,14 +599,15 @@ static __be32
 nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	     struct nfsd4_create *create)
 {
+	int access = create->cr_type == NF4DIR ?
+		NFSD_MAY_CREATE_DIR : NFSD_MAY_CREATE_FILE;
 	struct svc_fh resfh;
 	__be32 status;
 	dev_t rdev;
 
 	fh_init(&resfh, NFS4_FHSIZE);
 
-	status = fh_verify(rqstp, &cstate->current_fh, S_IFDIR,
-			   NFSD_MAY_CREATE);
+	status = fh_verify(rqstp, &cstate->current_fh, S_IFDIR, access);
 	if (status)
 		return status;
 
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 350041a..7159316 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -319,10 +319,10 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
 	/*
 	 * We still have to do all these permission checks, even when
 	 * fh_dentry is already set:
-	 * 	- fh_verify may be called multiple times with different
-	 * 	  "access" arguments (e.g. nfsd_proc_create calls
-	 * 	  fh_verify(...,NFSD_MAY_EXEC) first, then later (in
-	 * 	  nfsd_create) calls fh_verify(...,NFSD_MAY_CREATE).
+	 *	- fh_verify may be called multiple times with different
+	 *	  "access" arguments (e.g. nfsd_proc_create calls
+	 *	  fh_verify(...,NFSD_MAY_EXEC) first, then later (in
+	 *	  nfsd_create) calls fh_verify(...,NFSD_MAY_CREATE_FILE).
 	 *	- in the NFSv4 case, the filehandle may have been filled
 	 *	  in by fh_compose, and given a dentry, but further
 	 *	  compound operations performed with that filehandle
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 45c0497..fb35775 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -1128,6 +1128,8 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
 	__be32		err;
 	__be32		err2;
 	int		host_err;
+	int access = (type == S_IFDIR) ?
+		NFSD_MAY_CREATE_DIR : NFSD_MAY_CREATE_FILE;
 
 	err = nfserr_perm;
 	if (!flen)
@@ -1136,7 +1138,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
 	if (isdotent(fname, flen))
 		goto out;
 
-	err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE);
+	err = fh_verify(rqstp, fhp, S_IFDIR, access);
 	if (err)
 		goto out;
 
@@ -1301,7 +1303,7 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
 
 	/* If file doesn't exist, check for permissions to create one */
 	if (d_really_is_negative(dchild)) {
-		err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE);
+		err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE_FILE);
 		if (err)
 			goto out;
 	}
@@ -1485,7 +1487,7 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
 	if (isdotent(fname, flen))
 		goto out;
 
-	err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE);
+	err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE_FILE);
 	if (err)
 		goto out;
 
@@ -1532,7 +1534,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
 	__be32		err;
 	int		host_err;
 
-	err = fh_verify(rqstp, ffhp, S_IFDIR, NFSD_MAY_CREATE);
+	err = fh_verify(rqstp, ffhp, S_IFDIR, NFSD_MAY_CREATE_FILE);
 	if (err)
 		goto out;
 	err = fh_verify(rqstp, tfhp, 0, NFSD_MAY_NOP);
@@ -1604,11 +1606,12 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
 	struct inode	*fdir, *tdir;
 	__be32		err;
 	int		host_err;
+	int		access;
 
 	err = fh_verify(rqstp, ffhp, S_IFDIR, NFSD_MAY_REMOVE);
 	if (err)
 		goto out;
-	err = fh_verify(rqstp, tfhp, S_IFDIR, NFSD_MAY_CREATE);
+	err = fh_verify(rqstp, tfhp, S_IFDIR, NFSD_MAY_NOP);
 	if (err)
 		goto out;
 
@@ -1647,6 +1650,13 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
 	if (odentry == trap)
 		goto out_dput_old;
 
+	host_err = 0;
+	access = S_ISDIR(d_inode(odentry)->i_mode) ?
+		NFSD_MAY_CREATE_DIR : NFSD_MAY_CREATE_FILE;
+	err = fh_verify(rqstp, tfhp, S_IFDIR, access);
+	if (err)
+		goto out_dput_old;
+
 	ndentry = lookup_one_len(tname, tdentry, tlen);
 	host_err = PTR_ERR(ndentry);
 	if (IS_ERR(ndentry))
@@ -1672,7 +1682,8 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
  out_dput_old:
 	dput(odentry);
  out_nfserr:
-	err = nfserrno(host_err);
+	if (host_err)
+		err = nfserrno(host_err);
 	/*
 	 * We cannot rely on fh_unlock on the two filehandles,
 	 * as that would do the wrong thing if the two directories
@@ -2005,8 +2016,9 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
 	    uid_eq(inode->i_uid, current_fsuid()))
 		return 0;
 
-	/* This assumes  NFSD_MAY_{READ,WRITE,EXEC} == MAY_{READ,WRITE,EXEC} */
-	err = inode_permission(inode, acc & (MAY_READ|MAY_WRITE|MAY_EXEC));
+	/* This assumes NFSD_MAY_{READ,WRITE,EXEC} == MAY_{READ,WRITE,EXEC}. */
+	err = inode_permission(inode, acc & (MAY_READ|MAY_WRITE|MAY_EXEC|
+					     MAY_CREATE_DIR|MAY_CREATE_FILE));
 
 	/* Allow read access to binaries even when mode 111 */
 	if (err == -EACCES && S_ISREG(inode->i_mode) &&
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
index fee2451..c849ef2 100644
--- a/fs/nfsd/vfs.h
+++ b/fs/nfsd/vfs.h
@@ -19,18 +19,19 @@
 #define NFSD_MAY_TRUNC			0x010
 #define NFSD_MAY_LOCK			0x020
 #define NFSD_MAY_MASK			0x03f
+#define NFSD_MAY_CREATE_FILE		0x103 /* == MAY_{EXEC|WRITE|CREATE_FILE} */
+#define NFSD_MAY_CREATE_DIR		0x203 /* == MAY_{EXEC|WRITE|CREATE_DIR} */
 
 /* extra hints to permission and open routines: */
-#define NFSD_MAY_OWNER_OVERRIDE		0x040
-#define NFSD_MAY_LOCAL_ACCESS		0x080 /* for device special files */
-#define NFSD_MAY_BYPASS_GSS_ON_ROOT	0x100
-#define NFSD_MAY_NOT_BREAK_LEASE	0x200
-#define NFSD_MAY_BYPASS_GSS		0x400
-#define NFSD_MAY_READ_IF_EXEC		0x800
+#define NFSD_MAY_OWNER_OVERRIDE		0x04000
+#define NFSD_MAY_LOCAL_ACCESS		0x08000 /* for device special files */
+#define NFSD_MAY_BYPASS_GSS_ON_ROOT	0x10000
+#define NFSD_MAY_NOT_BREAK_LEASE	0x20000
+#define NFSD_MAY_BYPASS_GSS		0x40000
+#define NFSD_MAY_READ_IF_EXEC		0x80000
 
-#define NFSD_MAY_64BIT_COOKIE		0x1000 /* 64 bit readdir cookies for >= NFSv3 */
+#define NFSD_MAY_64BIT_COOKIE		0x100000 /* 64 bit readdir cookies for >= NFSv3 */
 
-#define NFSD_MAY_CREATE		(NFSD_MAY_EXEC|NFSD_MAY_WRITE)
 #define NFSD_MAY_REMOVE		(NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC)
 
 /*
-- 
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]


#1244248 — [PATCH v10 35/46] nfsd: Add richacl support

FromAndreas Gruenbacher <andreas.gruenbacher@gmail.com>
Date2015-10-12 01:10 +0200
Subject[PATCH v10 35/46] nfsd: Add richacl support
Message-ID<qixUB-61y-5@gated-at.bofh.it>
In reply to#1244246
From: Andreas Gruenbacher <agruenba@redhat.com>

On file systems with richacls enabled, get and set richacls directly
instead of converting from / to posix acls.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Acked-by: J. Bruce Fields <bfields@redhat.com>
---
 fs/nfsd/acl.h      |   3 +-
 fs/nfsd/nfs4acl.c  | 124 ++++++++++++++++++++++++++++++++++++++---------------
 fs/nfsd/nfs4proc.c |   2 +-
 fs/nfsd/nfs4xdr.c  |  34 +++++++++++----
 4 files changed, 117 insertions(+), 46 deletions(-)

diff --git a/fs/nfsd/acl.h b/fs/nfsd/acl.h
index 1c5deb5..d73c664 100644
--- a/fs/nfsd/acl.h
+++ b/fs/nfsd/acl.h
@@ -53,8 +53,7 @@ __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);
 
-int nfsd4_get_acl(struct svc_rqst *rqstp, struct dentry *dentry,
-		  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,
 		     struct richacl *acl);
 
diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c
index 6d3bb72..f017a76 100644
--- a/fs/nfsd/nfs4acl.c
+++ b/fs/nfsd/nfs4acl.c
@@ -40,6 +40,8 @@
 #include <linux/nfs_fs.h>
 #include <linux/richacl_compat.h>
 #include <linux/nfs4acl.h>
+#include <linux/xattr.h>
+#include <linux/richacl_xattr.h>
 
 #include "nfsfh.h"
 #include "nfsd.h"
@@ -129,32 +131,28 @@ static short ace2type(struct richace *);
 static void _posix_to_richacl_one(struct posix_acl *, struct richacl_alloc *,
 				unsigned int);
 
-int
-nfsd4_get_acl(struct svc_rqst *rqstp, struct dentry *dentry,
-	      struct richacl **acl)
+static struct richacl *
+nfsd4_get_posix_acl(struct svc_rqst *rqstp, struct dentry *dentry)
 {
 	struct inode *inode = d_inode(dentry);
-	int error = 0;
 	struct posix_acl *pacl = NULL, *dpacl = NULL;
 	struct richacl_alloc alloc;
 	unsigned int flags = 0;
 	int count;
 
 	pacl = get_acl(inode, ACL_TYPE_ACCESS);
-	if (!pacl)
-		pacl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
-
-	if (IS_ERR(pacl))
-		return PTR_ERR(pacl);
+	if (IS_ERR_OR_NULL(pacl))
+		return (void *)pacl;
 
-	/* allocate for worst case: one (deny, allow) pair each: */
+	/* Allocate for worst case: one (deny, allow) pair each.  The resulting
+	   acl will be released shortly and won't be cached. */
 	count = 2 * pacl->a_count;
 
 	if (S_ISDIR(inode->i_mode)) {
 		flags = FLAG_DIRECTORY;
 		dpacl = get_acl(inode, ACL_TYPE_DEFAULT);
 		if (IS_ERR(dpacl)) {
-			error = PTR_ERR(dpacl);
+			alloc.acl = (void *)dpacl;
 			goto rel_pacl;
 		}
 
@@ -163,7 +161,7 @@ nfsd4_get_acl(struct svc_rqst *rqstp, struct dentry *dentry,
 	}
 
 	if (!richacl_prepare(&alloc, count)) {
-		error = -ENOMEM;
+		alloc.acl = ERR_PTR(-ENOMEM);
 		goto out;
 	}
 
@@ -172,13 +170,37 @@ nfsd4_get_acl(struct svc_rqst *rqstp, struct dentry *dentry,
 	if (dpacl)
 		_posix_to_richacl_one(dpacl, &alloc, flags | FLAG_DEFAULT_ACL);
 
-	*acl = alloc.acl;
-
 out:
 	posix_acl_release(dpacl);
 rel_pacl:
 	posix_acl_release(pacl);
-	return error;
+	return alloc.acl;
+}
+
+struct richacl *
+nfsd4_get_acl(struct svc_rqst *rqstp, struct dentry *dentry)
+{
+	struct inode *inode = d_inode(dentry);
+	struct richacl *acl;
+	int error;
+
+	if (IS_RICHACL(inode))
+		acl = get_richacl(inode);
+	else
+		acl = nfsd4_get_posix_acl(rqstp, dentry);
+	if (IS_ERR(acl))
+		return acl;
+	else if (acl == NULL) {
+		acl = richacl_from_mode(inode->i_mode);
+		if (acl == NULL)
+			acl = ERR_PTR(-ENOMEM);
+	}
+	error = richacl_apply_masks(&acl, inode->i_uid);
+	if (error) {
+		richacl_put(acl);
+		acl = ERR_PTR(error);
+	}
+	return acl;
 }
 
 struct posix_acl_summary {
@@ -744,56 +766,88 @@ out_estate:
 	return ret;
 }
 
-__be32
-nfsd4_set_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, struct richacl *acl)
+static int
+nfsd4_set_posix_acl(struct svc_rqst *rqstp, struct dentry *dentry,
+		    struct richacl *acl)
 {
-	__be32 error;
 	int host_error;
-	struct dentry *dentry;
-	struct inode *inode;
+	struct inode *inode = d_inode(dentry);
 	struct posix_acl *pacl = NULL, *dpacl = NULL;
 	unsigned int flags = 0;
 
-	/* Get inode */
-	error = fh_verify(rqstp, fhp, 0, NFSD_MAY_SATTR);
-	if (error)
-		return error;
-
-	dentry = fhp->fh_dentry;
-	inode = d_inode(dentry);
-
 	if (!inode->i_op->set_acl || !IS_POSIXACL(inode))
-		return nfserr_attrnotsupp;
+		return -EOPNOTSUPP;
 
 	if (S_ISDIR(inode->i_mode))
 		flags = FLAG_DIRECTORY;
 
 	host_error = nfs4_richacl_to_posix(acl, &pacl, &dpacl, flags);
 	if (host_error == -EINVAL)
-		return nfserr_attrnotsupp;
+		return -EOPNOTSUPP;
 	if (host_error < 0)
-		goto out_nfserr;
+		return host_error;
 
 	host_error = inode->i_op->set_acl(inode, pacl, ACL_TYPE_ACCESS);
 	if (host_error < 0)
 		goto out_release;
 
-	if (S_ISDIR(inode->i_mode)) {
+	if (S_ISDIR(inode->i_mode))
 		host_error = inode->i_op->set_acl(inode, dpacl,
 						  ACL_TYPE_DEFAULT);
-	}
 
 out_release:
 	posix_acl_release(pacl);
 	posix_acl_release(dpacl);
-out_nfserr:
+	return host_error;
+}
+
+static int
+nfsd4_set_richacl(struct svc_rqst *rqstp, struct dentry *dentry,
+		  struct richacl *acl)
+{
+	int host_error;
+	struct inode *inode = d_inode(dentry);
+	size_t size = richacl_xattr_size(acl);
+	char *buffer;
+
+	if (!inode->i_op->setxattr || !IS_RICHACL(inode))
+		return -EOPNOTSUPP;
+
+	richacl_compute_max_masks(acl);
+
+	buffer = kmalloc(size, GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+	richacl_to_xattr(&init_user_ns, acl, buffer, size);
+	host_error = inode->i_op->setxattr(dentry, XATTR_NAME_RICHACL,
+					   buffer, size, 0);
+	kfree(buffer);
+	return host_error;
+}
+
+__be32
+nfsd4_set_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, struct richacl *acl)
+{
+	struct dentry *dentry;
+	int host_error;
+	__be32 error;
+
+	error = fh_verify(rqstp, fhp, 0, NFSD_MAY_SATTR);
+	if (error)
+		return error;
+	dentry = fhp->fh_dentry;
+
+	if (IS_RICHACL(d_inode(dentry)))
+		host_error = nfsd4_set_richacl(rqstp, dentry, acl);
+	else
+		host_error = nfsd4_set_posix_acl(rqstp, dentry, acl);
+
 	if (host_error == -EOPNOTSUPP)
 		return nfserr_attrnotsupp;
 	else
 		return nfserrno(host_error);
 }
 
-
 static short
 ace2type(struct richace *ace)
 {
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 2430235..1bcfda2 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -110,7 +110,7 @@ check_attr_support(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	 * in current environment or not.
 	 */
 	if (bmval[0] & FATTR4_WORD0_ACL) {
-		if (!IS_POSIXACL(d_inode(dentry)))
+		if (!IS_ACL(d_inode(dentry)))
 			return nfserr_attrnotsupp;
 	}
 
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 8603f40..682a7d8 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -340,11 +340,24 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
 
 		richacl_for_each_entry(ace, *acl) {
 			READ_BUF(16); len += 16;
-			ace->e_type = be32_to_cpup(p++);
-			ace->e_flags = be32_to_cpup(p++);
-			ace->e_mask = be32_to_cpup(p++);
-			if (ace->e_flags & RICHACE_SPECIAL_WHO)
+
+			dummy32 = be32_to_cpup(p++);
+			if (dummy32 > RICHACE_ACCESS_DENIED_ACE_TYPE)
+				return nfserr_inval;
+			ace->e_type = dummy32;
+
+			dummy32 = be32_to_cpup(p++);
+			if (dummy32 & (~RICHACE_VALID_FLAGS |
+				       RICHACE_INHERITED_ACE |
+				       RICHACE_SPECIAL_WHO))
 				return nfserr_inval;
+			ace->e_flags = dummy32;
+
+			dummy32 = be32_to_cpup(p++);
+			if (dummy32 & ~NFS4_ACE_MASK_ALL)
+				return nfserr_inval;
+			ace->e_mask = dummy32;
+
 			dummy32 = be32_to_cpup(p++);
 			READ_BUF(dummy32);
 			len += XDR_QUADLEN(dummy32) << 2;
@@ -2330,7 +2343,11 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
 		fhp = tempfh;
 	}
 	if (bmval0 & FATTR4_WORD0_ACL) {
-		err = nfsd4_get_acl(rqstp, dentry, &acl);
+		acl = nfsd4_get_acl(rqstp, dentry);
+		if (IS_ERR(acl)) {
+			err = PTR_ERR(acl);
+			acl = NULL;
+		}
 		if (err == -EOPNOTSUPP)
 			bmval0 &= ~FATTR4_WORD0_ACL;
 		else if (err == -EINVAL) {
@@ -2370,7 +2387,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
 		u32 word1 = nfsd_suppattrs1(minorversion);
 		u32 word2 = nfsd_suppattrs2(minorversion);
 
-		if (!IS_POSIXACL(dentry->d_inode))
+		if (!IS_ACL(d_inode(dentry)))
 			word0 &= ~FATTR4_WORD0_ACL;
 		if (!contextsupport)
 			word2 &= ~FATTR4_WORD2_SECURITY_LABEL;
@@ -2505,7 +2522,8 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
 			if (!p)
 				goto out_resource;
 			*p++ = cpu_to_be32(ace->e_type);
-			*p++ = cpu_to_be32(ace->e_flags & ~RICHACE_SPECIAL_WHO);
+			*p++ = cpu_to_be32(ace->e_flags &
+				~(RICHACE_SPECIAL_WHO | RICHACE_INHERITED_ACE));
 			*p++ = cpu_to_be32(ace->e_mask & NFS4_ACE_MASK_ALL);
 			status = nfsd4_encode_ace_who(xdr, rqstp, ace);
 			if (status)
@@ -2517,7 +2535,7 @@ out_acl:
 		p = xdr_reserve_space(xdr, 4);
 		if (!p)
 			goto out_resource;
-		*p++ = cpu_to_be32(IS_POSIXACL(dentry->d_inode) ?
+		*p++ = cpu_to_be32(IS_ACL(d_inode(dentry)) ?
 			ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL : 0);
 	}
 	if (bmval0 & FATTR4_WORD0_CANSETTIME) {
-- 
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]


#1244251 — [PATCH v10 27/46] richacl: Propagate everyone@ permissions to other aces

FromAndreas Gruenbacher <andreas.gruenbacher@gmail.com>
Date2015-10-12 01:10 +0200
Subject[PATCH v10 27/46] richacl: Propagate everyone@ permissions to other aces
Message-ID<qixUC-61y-13@gated-at.bofh.it>
In reply to#1244246
From: Andreas Gruenbacher <agruenba@redhat.com>

The trailing everyone@ allow ace can grant permissions to all file
classes including the owner and group class.  Before we can apply the
other mask to this entry to turn it into an "other class" entry, we need
to ensure that members of the owner or group class will not lose any
permissions from that ace.

Conceptually, we do this by inserting additional <who>:<allow>::allow
entries before the trailing everyone@ allow ace with the same
permissions as the trailing everyone@ allow ace for owner@, group@, and
all explicitly mentioned users and groups.  (In practice, we will rarely
need to insert any additional aces in this step.)

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

diff --git a/fs/richacl_compat.c b/fs/richacl_compat.c
index 4f0acf5..7d007d7 100644
--- a/fs/richacl_compat.c
+++ b/fs/richacl_compat.c
@@ -218,3 +218,201 @@ richacl_move_everyone_aces_down(struct richacl_alloc *alloc)
 	}
 	return 0;
 }
+
+/**
+ * __richacl_propagate_everyone  -  propagate everyone@ permissions up for @who
+ * @alloc:	acl and number of allocated entries
+ * @who:	identifier to propagate permissions for
+ * @allow:	permissions to propagate up
+ *
+ * Propagate the permissions in @allow up from the end of the acl to the start
+ * for the specified principal @who.
+ *
+ * The simplest possible approach to achieve this would be to insert a
+ * "<who>:<allow>::allow" ace before the final everyone@ allow ace.  Since this
+ * would often result in aces which are not needed or which could be merged
+ * with an existing ace, we make the following optimizations:
+ *
+ *   - We go through the acl and determine which permissions are already
+ *     allowed or denied to @who, and we remove those permissions from
+ *     @allow.
+ *
+ *   - If the acl contains an allow ace for @who and no aces after this entry
+ *     deny permissions in @allow, we add the permissions in @allow to this
+ *     ace.  (Propagating permissions across a deny ace which can match the
+ *     process can elevate permissions.)
+ *
+ * This transformation does not alter the permissions that the acl grants.
+ */
+static int
+__richacl_propagate_everyone(struct richacl_alloc *alloc, struct richace *who,
+			     unsigned int allow)
+{
+	struct richace *allow_last = NULL, *ace;
+	struct richacl *acl = alloc->acl;
+
+	/*
+	 * Remove the permissions from allow that are already determined for
+	 * this who value, and figure out if there is an allow entry for
+	 * this who value that is "reachable" from the trailing everyone@
+	 * allow ace.
+	 */
+	richacl_for_each_entry(ace, acl) {
+		if (richace_is_inherit_only(ace))
+			continue;
+		if (richace_is_allow(ace)) {
+			if (richace_is_same_identifier(ace, who)) {
+				allow &= ~ace->e_mask;
+				allow_last = ace;
+			}
+		} else if (richace_is_deny(ace)) {
+			if (richace_is_same_identifier(ace, who))
+				allow &= ~ace->e_mask;
+			else if (allow & ace->e_mask)
+				allow_last = NULL;
+		}
+	}
+	ace--;
+
+	/*
+	 * If for group class entries, all the remaining permissions will
+	 * remain granted by the trailing everyone@ allow ace, no additional
+	 * entry is needed.
+	 */
+	if (!richace_is_owner(who) &&
+	    richace_is_everyone(ace) &&
+	    !(allow & ~(ace->e_mask & acl->a_other_mask)))
+		allow = 0;
+
+	if (allow) {
+		if (allow_last)
+			return richace_change_mask(alloc, &allow_last,
+						   allow_last->e_mask | allow);
+		else {
+			struct richace who_copy;
+
+			richace_copy(&who_copy, who);
+			if (richacl_insert_entry(alloc, &ace))
+				return -1;
+			richace_copy(ace, &who_copy);
+			ace->e_type = RICHACE_ACCESS_ALLOWED_ACE_TYPE;
+			ace->e_flags &= ~RICHACE_INHERITANCE_FLAGS;
+			ace->e_mask = allow;
+		}
+	}
+	return 0;
+}
+
+/**
+ * richacl_propagate_everyone  -  propagate everyone@ permissions up the acl
+ * @alloc:	acl and number of allocated entries
+ *
+ * Make sure that group@ and all other users and groups mentioned in the acl
+ * will not lose any permissions when finally applying the other mask to the
+ * everyone@ allow ace at the end of the acl.  We modify the permissions of
+ * existing entries or add new entries before the final everyone@ allow ace to
+ * achieve that.
+ *
+ * For example, the following acl implicitly grants everyone rwpx access:
+ *
+ *    joe:r::allow
+ *    everyone@:rwpx::allow
+ *
+ * When applying mode 0660 to this acl, group@ would lose rwp access, and joe
+ * would lose wp access even though the mode does not exclude those
+ * permissions.  After propagating the everyone@ permissions, the result for
+ * applying mode 0660 becomes:
+ *
+ *    owner@:rwp::allow
+ *    joe:rwp::allow
+ *    group@:rwp::allow
+ *
+ * Deny aces complicate the matter.  For example, the following acl grants
+ * everyone but joe write access:
+ *
+ *    joe:wp::deny
+ *    everyone@:rwpx::allow
+ *
+ * When applying mode 0660 to this acl, group@ would lose rwp access, and joe
+ * would lose r access.  After propagating the everyone@ permissions, the
+ * result for applying mode 0660 becomes:
+ *
+ *    owner@:rwp::allow
+ *    joe:w::deny
+ *    group@:rwp::allow
+ *    joe:r::allow
+ */
+static int
+richacl_propagate_everyone(struct richacl_alloc *alloc)
+{
+	struct richace who = { .e_flags = RICHACE_SPECIAL_WHO };
+	struct richacl *acl = alloc->acl;
+	struct richace *ace;
+	unsigned int owner_allow, group_allow;
+
+	if (!acl->a_count)
+		return 0;
+	ace = acl->a_entries + acl->a_count - 1;
+	if (richace_is_inherit_only(ace) || !richace_is_everyone(ace))
+		return 0;
+
+	/*
+	 * Permissions the owner and group class are granted through the
+	 * trailing everyone@ allow ace.
+	 */
+	owner_allow = ace->e_mask & acl->a_owner_mask;
+	group_allow = ace->e_mask & acl->a_group_mask;
+
+	/*
+	 * If the group or other masks hide permissions which the owner should
+	 * be allowed, we need to propagate those permissions up.  Otherwise,
+	 * those permissions may be lost when applying the other mask to the
+	 * trailing everyone@ allow ace, or when isolating the group class from
+	 * the other class through additional deny aces.
+	 */
+	if (owner_allow & ~(acl->a_group_mask & acl->a_other_mask)) {
+		/* Propagate everyone@ permissions through to owner@. */
+		who.e_id.special = RICHACE_OWNER_SPECIAL_ID;
+		if (__richacl_propagate_everyone(alloc, &who, owner_allow))
+			return -1;
+		acl = alloc->acl;
+	}
+
+	/*
+	 * If the other mask hides permissions which the group class should be
+	 * allowed, we need to propagate those permissions up to the owning
+	 * group and to all other members in the group class.
+	 */
+	if (group_allow & ~acl->a_other_mask) {
+		int n;
+
+		/* Propagate everyone@ permissions through to group@. */
+		who.e_id.special = RICHACE_GROUP_SPECIAL_ID;
+		if (__richacl_propagate_everyone(alloc, &who, group_allow))
+			return -1;
+		acl = alloc->acl;
+
+		/*
+		 * Start from the entry before the trailing everyone@ allow
+		 * entry. We will not hit everyone@ entries in the loop.
+		 */
+		for (n = acl->a_count - 2; n != -1; n--) {
+			ace = acl->a_entries + n;
+
+			if (richace_is_inherit_only(ace) ||
+			    richace_is_owner(ace) ||
+			    richace_is_group(ace))
+				continue;
+
+			/*
+			 * Any inserted entry will end up below the current
+			 * entry.
+			 */
+			if (__richacl_propagate_everyone(alloc, ace,
+							 group_allow))
+				return -1;
+			acl = alloc->acl;
+		}
+	}
+	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]


#1244254 — [PATCH v10 17/46] richacl: xattr mapping functions

FromAndreas Gruenbacher <andreas.gruenbacher@gmail.com>
Date2015-10-12 01:10 +0200
Subject[PATCH v10 17/46] richacl: xattr mapping functions
Message-ID<qixUC-61y-19@gated-at.bofh.it>
In reply to#1244246
From: Andreas Gruenbacher <agruenba@redhat.com>

Map between "system.richacl" xattrs and the in-kernel representation.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
 fs/Makefile                   |   2 +-
 fs/richacl_xattr.c            | 220 ++++++++++++++++++++++++++++++++++++++++++
 fs/xattr.c                    |  34 +++++--
 include/linux/richacl_xattr.h |  62 ++++++++++++
 include/uapi/linux/xattr.h    |   2 +
 5 files changed, 313 insertions(+), 7 deletions(-)
 create mode 100644 fs/richacl_xattr.c
 create mode 100644 include/linux/richacl_xattr.h

diff --git a/fs/Makefile b/fs/Makefile
index ec665fd..35e640d 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -49,7 +49,7 @@ 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-y			:= richacl_base.o richacl_inode.o richacl_xattr.o
 
 obj-y				+= quota/
 
diff --git a/fs/richacl_xattr.c b/fs/richacl_xattr.c
new file mode 100644
index 0000000..cd9979d
--- /dev/null
+++ b/fs/richacl_xattr.c
@@ -0,0 +1,220 @@
+/*
+ * 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/fs.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/richacl_xattr.h>
+
+MODULE_LICENSE("GPL");
+
+/**
+ * richacl_from_xattr  -  convert a richacl xattr into the in-memory representation
+ */
+struct richacl *
+richacl_from_xattr(struct user_namespace *user_ns,
+		   const void *value, size_t size)
+{
+	const struct richacl_xattr *xattr_acl = value;
+	const struct richace_xattr *xattr_ace = (void *)(xattr_acl + 1);
+	struct richacl *acl;
+	struct richace *ace;
+	int count;
+
+	if (size < sizeof(*xattr_acl) ||
+	    xattr_acl->a_version != RICHACL_XATTR_VERSION ||
+	    (xattr_acl->a_flags & ~RICHACL_VALID_FLAGS))
+		return ERR_PTR(-EINVAL);
+	size -= sizeof(*xattr_acl);
+	count = le16_to_cpu(xattr_acl->a_count);
+	if (count > RICHACL_XATTR_MAX_COUNT)
+		return ERR_PTR(-EINVAL);
+	if (size != count * sizeof(*xattr_ace))
+		return ERR_PTR(-EINVAL);
+
+	acl = richacl_alloc(count, GFP_NOFS);
+	if (!acl)
+		return ERR_PTR(-ENOMEM);
+
+	acl->a_flags = xattr_acl->a_flags;
+	acl->a_owner_mask = le32_to_cpu(xattr_acl->a_owner_mask);
+	if (acl->a_owner_mask & ~RICHACE_VALID_MASK)
+		goto fail_einval;
+	acl->a_group_mask = le32_to_cpu(xattr_acl->a_group_mask);
+	if (acl->a_group_mask & ~RICHACE_VALID_MASK)
+		goto fail_einval;
+	acl->a_other_mask = le32_to_cpu(xattr_acl->a_other_mask);
+	if (acl->a_other_mask & ~RICHACE_VALID_MASK)
+		goto fail_einval;
+
+	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);
+		ace->e_mask  = le32_to_cpu(xattr_ace->e_mask);
+
+		if (ace->e_flags & ~RICHACE_VALID_FLAGS)
+			goto fail_einval;
+		if (ace->e_flags & RICHACE_SPECIAL_WHO) {
+			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_IDENTIFIER_GROUP) {
+			u32 id = le32_to_cpu(xattr_ace->e_id);
+
+			ace->e_id.gid = make_kgid(user_ns, id);
+			if (!gid_valid(ace->e_id.gid))
+				goto fail_einval;
+		} else {
+			u32 id = le32_to_cpu(xattr_ace->e_id);
+
+			ace->e_id.uid = make_kuid(user_ns, id);
+			if (!uid_valid(ace->e_id.uid))
+				goto fail_einval;
+		}
+		if (ace->e_type > RICHACE_ACCESS_DENIED_ACE_TYPE ||
+		    (ace->e_mask & ~RICHACE_VALID_MASK))
+			goto fail_einval;
+
+		xattr_ace++;
+	}
+
+	return acl;
+
+fail_einval:
+	richacl_put(acl);
+	return ERR_PTR(-EINVAL);
+}
+EXPORT_SYMBOL_GPL(richacl_from_xattr);
+
+/**
+ * richacl_xattr_size  -  compute the size of the xattr representation of @acl
+ */
+size_t
+richacl_xattr_size(const struct richacl *acl)
+{
+	size_t size = sizeof(struct richacl_xattr);
+
+	size += sizeof(struct richace_xattr) * acl->a_count;
+	return size;
+}
+EXPORT_SYMBOL_GPL(richacl_xattr_size);
+
+/**
+ * richacl_to_xattr  -  convert @acl into its xattr representation
+ * @acl:	the richacl to convert
+ * @buffer:	buffer for the result
+ * @size:	size of @buffer
+ */
+int
+richacl_to_xattr(struct user_namespace *user_ns,
+		 const struct richacl *acl, void *buffer, size_t size)
+{
+	struct richacl_xattr *xattr_acl = buffer;
+	struct richace_xattr *xattr_ace;
+	const struct richace *ace;
+	size_t real_size;
+
+	real_size = richacl_xattr_size(acl);
+	if (!buffer)
+		return real_size;
+	if (real_size > size)
+		return -ERANGE;
+
+	xattr_acl->a_version = RICHACL_XATTR_VERSION;
+	xattr_acl->a_flags = acl->a_flags;
+	xattr_acl->a_count = cpu_to_le16(acl->a_count);
+
+	xattr_acl->a_owner_mask = cpu_to_le32(acl->a_owner_mask);
+	xattr_acl->a_group_mask = cpu_to_le32(acl->a_group_mask);
+	xattr_acl->a_other_mask = cpu_to_le32(acl->a_other_mask);
+
+	xattr_ace = (void *)(xattr_acl + 1);
+	richacl_for_each_entry(ace, acl) {
+		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));
+		xattr_ace++;
+	}
+	return real_size;
+}
+EXPORT_SYMBOL_GPL(richacl_to_xattr);
+
+/*
+ * Fix up the uids and gids in richacl extended attributes in place.
+ */
+static void richacl_fix_xattr_userns(
+	struct user_namespace *to, struct user_namespace *from,
+	void *value, size_t size)
+{
+	struct richacl_xattr *xattr_acl = value;
+	struct richace_xattr *xattr_ace =
+		(struct richace_xattr *)(xattr_acl + 1);
+	unsigned int count;
+
+	if (!value)
+		return;
+	if (size < sizeof(*xattr_acl))
+		return;
+	if (xattr_acl->a_version != cpu_to_le32(RICHACL_XATTR_VERSION))
+		return;
+	size -= sizeof(*xattr_acl);
+	if (size % sizeof(*xattr_ace))
+		return;
+	count = size / sizeof(*xattr_ace);
+	for (; count; count--, xattr_ace++) {
+		if (xattr_ace->e_flags & cpu_to_le16(RICHACE_SPECIAL_WHO))
+			continue;
+		if (xattr_ace->e_flags &
+		    cpu_to_le16(RICHACE_IDENTIFIER_GROUP)) {
+			u32 id = le32_to_cpu(xattr_ace->e_id);
+			kgid_t gid = make_kgid(from, id);
+
+			xattr_ace->e_id = cpu_to_le32(from_kgid(to, gid));
+		} else {
+			u32 id = le32_to_cpu(xattr_ace->e_id);
+			kuid_t uid = make_kuid(from, id);
+
+			xattr_ace->e_id = cpu_to_le32(from_kuid(to, uid));
+		}
+	}
+}
+
+void richacl_fix_xattr_from_user(void *value, size_t size)
+{
+	struct user_namespace *user_ns = current_user_ns();
+
+	if (user_ns == &init_user_ns)
+		return;
+	richacl_fix_xattr_userns(&init_user_ns, user_ns, value, size);
+}
+
+void richacl_fix_xattr_to_user(void *value, size_t size)
+{
+	struct user_namespace *user_ns = current_user_ns();
+
+	if (user_ns == &init_user_ns)
+		return;
+	richacl_fix_xattr_userns(user_ns, &init_user_ns, value, size);
+}
diff --git a/fs/xattr.c b/fs/xattr.c
index 072fee1..f2313c6 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -21,6 +21,7 @@
 #include <linux/audit.h>
 #include <linux/vmalloc.h>
 #include <linux/posix_acl_xattr.h>
+#include <linux/richacl_xattr.h>
 
 #include <asm/uaccess.h>
 
@@ -314,6 +315,18 @@ out:
 }
 EXPORT_SYMBOL_GPL(vfs_removexattr);
 
+static void
+fix_xattr_from_user(const char *kname, void *kvalue, size_t size)
+{
+	if (strncmp(kname, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
+		return;
+	kname += XATTR_SYSTEM_PREFIX_LEN;
+	if (!strcmp(kname, XATTR_POSIX_ACL_ACCESS) ||
+	    !strcmp(kname, XATTR_POSIX_ACL_DEFAULT))
+		posix_acl_fix_xattr_from_user(kvalue, size);
+	else if (!strcmp(kname, XATTR_RICHACL))
+		richacl_fix_xattr_from_user(kvalue, size);
+}
 
 /*
  * Extended attribute SET operations
@@ -350,9 +363,7 @@ setxattr(struct dentry *d, const char __user *name, const void __user *value,
 			error = -EFAULT;
 			goto out;
 		}
-		if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
-		    (strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
-			posix_acl_fix_xattr_from_user(kvalue, size);
+		fix_xattr_from_user(kname, kvalue, size);
 	}
 
 	error = vfs_setxattr(d, kname, kvalue, size, flags);
@@ -419,6 +430,19 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name,
 	return error;
 }
 
+static void
+fix_xattr_to_user(const char *kname, void *kvalue, size_t size)
+{
+	if (strncmp(kname, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
+		return;
+	kname += XATTR_SYSTEM_PREFIX_LEN;
+	if (!strcmp(kname, XATTR_POSIX_ACL_ACCESS) ||
+	    !strcmp(kname, XATTR_POSIX_ACL_DEFAULT))
+		posix_acl_fix_xattr_to_user(kvalue, size);
+	else if (!strcmp(kname, XATTR_RICHACL))
+		richacl_fix_xattr_to_user(kvalue, size);
+}
+
 /*
  * Extended attribute GET operations
  */
@@ -451,9 +475,7 @@ getxattr(struct dentry *d, const char __user *name, void __user *value,
 
 	error = vfs_getxattr(d, kname, kvalue, size);
 	if (error > 0) {
-		if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
-		    (strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
-			posix_acl_fix_xattr_to_user(kvalue, size);
+		fix_xattr_to_user(kname, kvalue, size);
 		if (size && copy_to_user(value, kvalue, error))
 			error = -EFAULT;
 	} else if (error == -ERANGE && size >= XATTR_SIZE_MAX) {
diff --git a/include/linux/richacl_xattr.h b/include/linux/richacl_xattr.h
new file mode 100644
index 0000000..f84cc21
--- /dev/null
+++ b/include/linux/richacl_xattr.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 __RICHACL_XATTR_H
+#define __RICHACL_XATTR_H
+
+#include <linux/richacl.h>
+
+struct richace_xattr {
+	__le16		e_type;
+	__le16		e_flags;
+	__le32		e_mask;
+	__le32		e_id;
+};
+
+struct richacl_xattr {
+	unsigned char	a_version;
+	unsigned char	a_flags;
+	__le16		a_count;
+	__le32		a_owner_mask;
+	__le32		a_group_mask;
+	__le32		a_other_mask;
+};
+
+#define RICHACL_XATTR_VERSION	0
+#define RICHACL_XATTR_MAX_COUNT \
+	((XATTR_SIZE_MAX - sizeof(struct richacl_xattr)) / \
+	 sizeof(struct richace_xattr))
+
+extern struct richacl *richacl_from_xattr(struct user_namespace *, const void *,
+					  size_t);
+extern size_t richacl_xattr_size(const struct richacl *);
+extern int richacl_to_xattr(struct user_namespace *, const struct richacl *,
+			    void *, size_t);
+
+#ifdef CONFIG_FS_RICHACL
+extern void richacl_fix_xattr_from_user(void *, size_t);
+extern void richacl_fix_xattr_to_user(void *, size_t);
+#else
+static inline void richacl_fix_xattr_from_user(void *value, size_t size)
+{
+}
+
+static inline void richacl_fix_xattr_to_user(void *value, size_t size)
+{
+}
+#endif
+
+#endif /* __RICHACL_XATTR_H */
diff --git a/include/uapi/linux/xattr.h b/include/uapi/linux/xattr.h
index 1590c49..1996903 100644
--- a/include/uapi/linux/xattr.h
+++ b/include/uapi/linux/xattr.h
@@ -73,5 +73,7 @@
 #define XATTR_POSIX_ACL_DEFAULT  "posix_acl_default"
 #define XATTR_NAME_POSIX_ACL_DEFAULT XATTR_SYSTEM_PREFIX XATTR_POSIX_ACL_DEFAULT
 
+#define XATTR_RICHACL "richacl"
+#define XATTR_NAME_RICHACL XATTR_SYSTEM_PREFIX XATTR_RICHACL
 
 #endif /* _UAPI_LINUX_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] | [prev] | [next] | [standalone]


#1244255 — [PATCH v10 23/46] xfs: Make xfs_set_mode non-static

FromAndreas Gruenbacher <andreas.gruenbacher@gmail.com>
Date2015-10-12 01:10 +0200
Subject[PATCH v10 23/46] xfs: Make xfs_set_mode non-static
Message-ID<qixUC-61y-21@gated-at.bofh.it>
In reply to#1244246
From: Andreas Gruenbacher <agruenba@redhat.com>

Make xfs_set_mode non-static and move it from xfs_acl.c into xfs_inode.c.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
 fs/xfs/xfs_acl.c   | 18 ------------------
 fs/xfs/xfs_inode.c | 18 ++++++++++++++++++
 fs/xfs/xfs_inode.h |  2 ++
 3 files changed, 20 insertions(+), 18 deletions(-)

diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
index 0f4ee92..8929466 100644
--- a/fs/xfs/xfs_acl.c
+++ b/fs/xfs/xfs_acl.c
@@ -226,24 +226,6 @@ __xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
 }
 
 static int
-xfs_set_mode(struct inode *inode, umode_t mode)
-{
-	int error = 0;
-
-	if (mode != inode->i_mode) {
-		struct iattr iattr;
-
-		iattr.ia_valid = ATTR_MODE | ATTR_CTIME;
-		iattr.ia_mode = mode;
-		iattr.ia_ctime = current_fs_time(inode->i_sb);
-
-		error = xfs_setattr_nonsize(XFS_I(inode), &iattr, XFS_ATTR_NOACL);
-	}
-
-	return error;
-}
-
-static int
 xfs_acl_exists(struct inode *inode, unsigned char *name)
 {
 	int len = XFS_ACL_MAX_SIZE(XFS_M(inode->i_sb));
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index dc40a6d..69148fa 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -3587,3 +3587,21 @@ xfs_iflush_int(
 corrupt_out:
 	return -EFSCORRUPTED;
 }
+
+int
+xfs_set_mode(struct inode *inode, umode_t mode)
+{
+	int error = 0;
+
+	if (mode != inode->i_mode) {
+		struct iattr iattr;
+
+		iattr.ia_valid = ATTR_MODE | ATTR_CTIME;
+		iattr.ia_mode = mode;
+		iattr.ia_ctime = current_fs_time(inode->i_sb);
+
+		error = xfs_setattr_nonsize(XFS_I(inode), &iattr, XFS_ATTR_NOACL);
+	}
+
+	return error;
+}
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index ca9e119..7b22db0 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -424,6 +424,8 @@ int		xfs_dir_ialloc(struct xfs_trans **, struct xfs_inode *, umode_t,
 int		xfs_droplink(struct xfs_trans *, struct xfs_inode *);
 int		xfs_bumplink(struct xfs_trans *, struct xfs_inode *);
 
+int		xfs_set_mode(struct inode *, umode_t);
+
 /* from xfs_file.c */
 enum xfs_prealloc_flags {
 	XFS_PREALLOC_SET	= (1 << 1),
-- 
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]


#1244307 — Re: [PATCH v10 23/46] xfs: Make xfs_set_mode non-static

FromDave Chinner <david@fromorbit.com>
Date2015-10-12 01:50 +0200
SubjectRe: [PATCH v10 23/46] xfs: Make xfs_set_mode non-static
Message-ID<qiyxj-6KJ-3@gated-at.bofh.it>
In reply to#1244255
On Mon, Oct 12, 2015 at 12:58:34AM +0200, Andreas Gruenbacher wrote:
> From: Andreas Gruenbacher <agruenba@redhat.com>
> 
> Make xfs_set_mode non-static and move it from xfs_acl.c into xfs_inode.c.
> 
> Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
.....
> +++ b/fs/xfs/xfs_inode.c
> @@ -3587,3 +3587,21 @@ xfs_iflush_int(
>  corrupt_out:
>  	return -EFSCORRUPTED;
>  }
> +
> +int
> +xfs_set_mode(struct inode *inode, umode_t mode)
> +{
> +	int error = 0;
> +
> +	if (mode != inode->i_mode) {
> +		struct iattr iattr;
> +
> +		iattr.ia_valid = ATTR_MODE | ATTR_CTIME;
> +		iattr.ia_mode = mode;
> +		iattr.ia_ctime = current_fs_time(inode->i_sb);
> +
> +		error = xfs_setattr_nonsize(XFS_I(inode), &iattr, XFS_ATTR_NOACL);
> +	}
> +
> +	return error;
> +}

Now needs a comment to explain that this function has a special
"called only from ACL modification" context associated with it.

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com
--
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]


#1244256 — [PATCH v10 43/46] nfs: Remove unused xdr page offsets in getacl/setacl arguments

FromAndreas Gruenbacher <andreas.gruenbacher@gmail.com>
Date2015-10-12 01:10 +0200
Subject[PATCH v10 43/46] nfs: Remove unused xdr page offsets in getacl/setacl arguments
Message-ID<qixUC-61y-23@gated-at.bofh.it>
In reply to#1244246
From: Andreas Gruenbacher <agruenba@redhat.com>

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]


#1244257 — [PATCH v10 24/46] xfs: Add richacl support

FromAndreas Gruenbacher <andreas.gruenbacher@gmail.com>
Date2015-10-12 01:10 +0200
Subject[PATCH v10 24/46] xfs: Add richacl support
Message-ID<qixUC-61y-25@gated-at.bofh.it>
In reply to#1244246
From: Andreas Gruenbacher <agruenba@redhat.com>

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.

If richacls are not compiled into the kernel, mounting richacl filesystems
will fail.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
 fs/ext4/richacl.h          |  1 -
 fs/xfs/Kconfig             | 11 ++++++
 fs/xfs/Makefile            |  1 +
 fs/xfs/libxfs/xfs_format.h | 16 +++++++-
 fs/xfs/xfs_iops.c          | 42 +++++++++++++++-----
 fs/xfs/xfs_richacl.c       | 97 ++++++++++++++++++++++++++++++++++++++++++++++
 fs/xfs/xfs_richacl.h       | 34 ++++++++++++++++
 fs/xfs/xfs_super.c         | 14 ++++++-
 fs/xfs/xfs_super.h         |  9 ++++-
 fs/xfs/xfs_xattr.c         |  4 ++
 10 files changed, 215 insertions(+), 14 deletions(-)
 create mode 100644 fs/xfs/xfs_richacl.c
 create mode 100644 fs/xfs/xfs_richacl.h

diff --git a/fs/ext4/richacl.h b/fs/ext4/richacl.h
index fc7826f..f26fbdd 100644
--- a/fs/ext4/richacl.h
+++ b/fs/ext4/richacl.h
@@ -24,7 +24,6 @@
 
 extern struct richacl *ext4_get_richacl(struct inode *);
 extern int ext4_set_richacl(struct inode *, struct richacl *);
-
 extern int ext4_init_richacl(handle_t *, struct inode *, struct inode *);
 
 #else  /* CONFIG_EXT4_FS_RICHACL */
diff --git a/fs/xfs/Kconfig b/fs/xfs/Kconfig
index 5d47b4d..05dd312 100644
--- a/fs/xfs/Kconfig
+++ b/fs/xfs/Kconfig
@@ -52,6 +52,17 @@ config XFS_POSIX_ACL
 
 	  If you don't know what Access Control Lists are, say N.
 
+config XFS_RICHACL
+        bool "XFS Rich Access Control Lists (EXPERIMENTAL)"
+        depends on XFS_FS
+        select FS_RICHACL
+        help
+          Richacls are an implementation of NFSv4 ACLs, extended by file masks
+          to cleanly integrate into the POSIX file permission model.  To learn
+	  more about them, see http://www.bestbits.at/richacl/.
+
+          If you don't know what Richacls are, say N.
+
 config XFS_RT
 	bool "XFS Realtime subvolume support"
 	depends on XFS_FS
diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
index a096841..7df9ae3 100644
--- a/fs/xfs/Makefile
+++ b/fs/xfs/Makefile
@@ -118,6 +118,7 @@ xfs-$(CONFIG_XFS_QUOTA)		+= xfs_dquot.o \
 xfs-$(CONFIG_XFS_RT)		+= xfs_rtalloc.o
 
 xfs-$(CONFIG_XFS_POSIX_ACL)	+= xfs_acl.o
+xfs-$(CONFIG_XFS_RICHACL)	+= xfs_richacl.o
 xfs-$(CONFIG_PROC_FS)		+= xfs_stats.o
 xfs-$(CONFIG_SYSCTL)		+= xfs_sysctl.o
 xfs-$(CONFIG_COMPAT)		+= xfs_ioctl32.o
diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index 9590a06..8c6da45 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -461,10 +461,18 @@ 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 */
+
+#ifdef CONFIG_XFS_RICHACL
+#define XFS_SB_FEAT_INCOMPAT_RICHACL	(1 << 3)	/* richacls */
+#else
+#define XFS_SB_FEAT_INCOMPAT_RICHACL	0
+#endif
+
 #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 +538,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..e37bdf87 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 (XFS_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,13 @@ xfs_generic_create(
 			goto out_cleanup_inode;
 	}
 #endif
+#ifdef CONFIG_XFS_RICHACL
+	if (richacl) {
+		error = xfs_set_richacl(inode, richacl);
+		if (error)
+			goto out_cleanup_inode;
+	}
+#endif
 
 	if (tmpfile)
 		d_tmpfile(dentry, inode);
@@ -189,10 +205,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:
@@ -722,7 +737,10 @@ 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);
+		if (XFS_IS_RICHACL(inode))
+			error = richacl_chmod(inode, inode->i_mode);
+		else
+			error = posix_acl_chmod(inode, inode->i_mode);
 		if (error)
 			return error;
 	}
@@ -1104,6 +1122,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 +1152,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 +1182,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..af74e92
--- /dev/null
+++ b/fs/xfs/xfs_richacl.c
@@ -0,0 +1,97 @@
+/*
+ * 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;
+	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.
+		 */
+		acl = (error == -ENOATTR) ? NULL : 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;
+}
+
+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;
+
+	if (acl) {
+		/* 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);
+			acl = NULL;
+		}
+	}
+	if (acl) {
+		void *value;
+		int 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) {
+			mode &= ~S_IRWXUGO;
+			mode |= richacl_masks_to_mode(acl);
+			xfs_set_mode(inode, mode);
+		}
+	} else {
+		error = xfs_attr_remove(ip, XATTR_NAME_RICHACL, ATTR_ROOT);
+		if (error == -ENOATTR)
+			error = 0;
+	}
+	if (!error)
+		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..78ad314
--- /dev/null
+++ b/fs/xfs/xfs_richacl.h
@@ -0,0 +1,34 @@
+/*
+ * 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
+
+#include <linux/richacl.h>
+
+#ifdef CONFIG_XFS_RICHACL
+
+#define XFS_IS_RICHACL(inode) IS_RICHACL(inode)
+
+extern struct richacl *xfs_get_richacl(struct inode *);
+extern int xfs_set_richacl(struct inode *, struct richacl *);
+
+#else  /* CONFIG_XFS_RICHACL */
+
+#define XFS_IS_RICHACL(inode) (0)
+#define xfs_get_richacl NULL
+#define xfs_set_richacl NULL
+
+#endif  /* CONFIG_XFS_RICHACL */
+#endif  /* __FS_XFS_RICHACL_H */
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index 904f637..74eeb0e 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -1500,7 +1500,19 @@ 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)) {
+#ifdef CONFIG_XFS_RICHACL
+		sb->s_flags |= MS_RICHACL;
+#else
+		error = -EOPNOTSUPP;
+		goto out_free_sb;
+#endif
+	} else {
+#ifdef CONFIG_XFS_POSIX_ACL
+		sb->s_flags |= MS_POSIXACL;
+#endif
+	}
 
 	/* 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..072fd57 100644
--- a/fs/xfs/xfs_super.h
+++ b/fs/xfs/xfs_super.h
@@ -30,10 +30,14 @@ extern void xfs_qm_exit(void);
 
 #ifdef CONFIG_XFS_POSIX_ACL
 # define XFS_ACL_STRING		"ACLs, "
-# define set_posix_acl_flag(sb)	((sb)->s_flags |= MS_POSIXACL)
 #else
 # define XFS_ACL_STRING
-# define set_posix_acl_flag(sb)	do { } while (0)
+#endif
+
+#ifdef CONFIG_XFS_RICHACL
+# define XFS_RICHACL_STRING	"Richacls, "
+#else
+# define XFS_RICHACL_STRING
 #endif
 
 #define XFS_SECURITY_STRING	"security attributes, "
@@ -52,6 +56,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..238b39f 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,9 @@ const struct xattr_handler *xfs_xattr_handlers[] = {
 	&posix_acl_access_xattr_handler,
 	&posix_acl_default_xattr_handler,
 #endif
+#ifdef CONFIG_XFS_RICHACL
+	&richacl_xattr_handler,
+#endif
 	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]


#1244312 — Re: [PATCH v10 24/46] xfs: Add richacl support

FromDave Chinner <david@fromorbit.com>
Date2015-10-12 02:20 +0200
SubjectRe: [PATCH v10 24/46] xfs: Add richacl support
Message-ID<qiz0l-7xX-7@gated-at.bofh.it>
In reply to#1244257
On Mon, Oct 12, 2015 at 12:58:35AM +0200, Andreas Gruenbacher wrote:
> From: Andreas Gruenbacher <agruenba@redhat.com>
> 
> 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.
> 
> If richacls are not compiled into the kernel, mounting richacl filesystems
> will fail.
> 
> Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
> ---
>  fs/ext4/richacl.h          |  1 -
>  fs/xfs/Kconfig             | 11 ++++++
>  fs/xfs/Makefile            |  1 +
>  fs/xfs/libxfs/xfs_format.h | 16 +++++++-
>  fs/xfs/xfs_iops.c          | 42 +++++++++++++++-----
>  fs/xfs/xfs_richacl.c       | 97 ++++++++++++++++++++++++++++++++++++++++++++++
>  fs/xfs/xfs_richacl.h       | 34 ++++++++++++++++
>  fs/xfs/xfs_super.c         | 14 ++++++-
>  fs/xfs/xfs_super.h         |  9 ++++-
>  fs/xfs/xfs_xattr.c         |  4 ++
>  10 files changed, 215 insertions(+), 14 deletions(-)
>  create mode 100644 fs/xfs/xfs_richacl.c
>  create mode 100644 fs/xfs/xfs_richacl.h
> 
> diff --git a/fs/ext4/richacl.h b/fs/ext4/richacl.h
> index fc7826f..f26fbdd 100644
> --- a/fs/ext4/richacl.h
> +++ b/fs/ext4/richacl.h
> @@ -24,7 +24,6 @@
>  
>  extern struct richacl *ext4_get_richacl(struct inode *);
>  extern int ext4_set_richacl(struct inode *, struct richacl *);
> -
>  extern int ext4_init_richacl(handle_t *, struct inode *, struct inode *);
>  
>  #else  /* CONFIG_EXT4_FS_RICHACL */

stray hunk.

> diff --git a/fs/xfs/Kconfig b/fs/xfs/Kconfig
> index 5d47b4d..05dd312 100644
> --- a/fs/xfs/Kconfig
> +++ b/fs/xfs/Kconfig
> @@ -52,6 +52,17 @@ config XFS_POSIX_ACL
>  
>  	  If you don't know what Access Control Lists are, say N.
>  
> +config XFS_RICHACL
> +        bool "XFS Rich Access Control Lists (EXPERIMENTAL)"
> +        depends on XFS_FS
> +        select FS_RICHACL
> +        help
> +          Richacls are an implementation of NFSv4 ACLs, extended by file masks
> +          to cleanly integrate into the POSIX file permission model.  To learn
> +	  more about them, see http://www.bestbits.at/richacl/.
> +
> +          If you don't know what Richacls are, say N.
> +

So now we have multiple compile time ACL configs that we have to
test. Personally, I see no reason for making either posix or rich
acls compile time dependent. How about we just change CONFIG_FS_XFS
to have "select FS_POSIX_ACL" and "select FS_RICHACL"
unconditionally, and then we can get rid of all the conditional
code?

> diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
> index 9590a06..8c6da45 100644
> --- a/fs/xfs/libxfs/xfs_format.h
> +++ b/fs/xfs/libxfs/xfs_format.h
> @@ -461,10 +461,18 @@ 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 */
> +
> +#ifdef CONFIG_XFS_RICHACL
> +#define XFS_SB_FEAT_INCOMPAT_RICHACL	(1 << 3)	/* richacls */
> +#else
> +#define XFS_SB_FEAT_INCOMPAT_RICHACL	0
> +#endif
> +

Regardless of whether we build in richacl support, this is wrong.
Feature bits are on-disk format definitions, so it will always have
this value whether or not the kernel supports the feature.

> @@ -722,7 +737,10 @@ 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);
> +		if (XFS_IS_RICHACL(inode))
> +			error = richacl_chmod(inode, inode->i_mode);
> +		else
> +			error = posix_acl_chmod(inode, inode->i_mode);
>  		if (error)
>  			return error;
>  	}

This sort of thing could do with a helper like:

static inline int
xfs_acl_chmod(struct inode *inode, int mode)
{
	if (IS_RICHACL(inode))
		return richacl_chmod(inode, mode);
	return posix_acl_chmod(inode, mode);
}

> +#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)
> +{

...

If we always build in ACL support, this can all go in xfs_acl.c.

> +	struct xfs_inode *ip = XFS_I(inode);
> +	struct richacl *acl;
> +	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.
> +		 */
> +		acl = (error == -ENOATTR) ? NULL : ERR_PTR(error);

I rather dislike ternaries in code like this - it's hard to read the
logic. Initalise acl to NULL, and then this simply becomes:

		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;
> +}
> +
> +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;
> +
> +	if (acl) {
> +		/* 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);
> +			acl = NULL;
> +		}

Comment needed here - why does this now seem to accidentally fall
through to removing the ACL?  Also, why is this in the XFS specific
code when it's generic richacl functionality that is being checked?

Also, I really dislike the API where passing a NULL acl means to
"set this acl" actually means "remove the existing ACL". Why no
->remove_acl method called from the generic code?


> +#ifndef __FS_XFS_RICHACL_H
> +#define __FS_XFS_RICHACL_H
> +
> +#include <linux/richacl.h>
> +
> +#ifdef CONFIG_XFS_RICHACL
> +
> +#define XFS_IS_RICHACL(inode) IS_RICHACL(inode)

No. Just use IS_RICHACL() everywhere, and whatever build
conditional that uses.

> --- a/fs/xfs/xfs_super.c
> +++ b/fs/xfs/xfs_super.c
> @@ -1500,7 +1500,19 @@ 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)) {
> +#ifdef CONFIG_XFS_RICHACL
> +		sb->s_flags |= MS_RICHACL;
> +#else
> +		error = -EOPNOTSUPP;
> +		goto out_free_sb;
> +#endif
> +	} else {
> +#ifdef CONFIG_XFS_POSIX_ACL
> +		sb->s_flags |= MS_POSIXACL;
> +#endif

The whole point of having set_posix_acl_flag() is that it keeps
the ifdef hackery out of the code. If we are going to keep build
time config options for these, then please keep the wrappers to hide
this mess...

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com
--
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]


#1244337 — Re: [PATCH v10 24/46] xfs: Add richacl support

FromAndreas Grünbacher <andreas.gruenbacher@gmail.com>
Date2015-10-12 04:00 +0200
SubjectRe: [PATCH v10 24/46] xfs: Add richacl support
Message-ID<qiAz8-1bO-13@gated-at.bofh.it>
In reply to#1244312
2015-10-12 2:10 GMT+02:00 Dave Chinner <david@fromorbit.com>:
> On Mon, Oct 12, 2015 at 12:58:35AM +0200, Andreas Gruenbacher wrote:
>> diff --git a/fs/ext4/richacl.h b/fs/ext4/richacl.h
>> index fc7826f..f26fbdd 100644
>> --- a/fs/ext4/richacl.h
>> +++ b/fs/ext4/richacl.h
>> @@ -24,7 +24,6 @@
>>
>>  extern struct richacl *ext4_get_richacl(struct inode *);
>>  extern int ext4_set_richacl(struct inode *, struct richacl *);
>> -
>>  extern int ext4_init_richacl(handle_t *, struct inode *, struct inode *);
>>
>>  #else  /* CONFIG_EXT4_FS_RICHACL */
>
> stray hunk.

Oops, thanks.

>> diff --git a/fs/xfs/Kconfig b/fs/xfs/Kconfig
>> index 5d47b4d..05dd312 100644
>> --- a/fs/xfs/Kconfig
>> +++ b/fs/xfs/Kconfig
>> @@ -52,6 +52,17 @@ config XFS_POSIX_ACL
>>
>>         If you don't know what Access Control Lists are, say N.
>>
>> +config XFS_RICHACL
>> +        bool "XFS Rich Access Control Lists (EXPERIMENTAL)"
>> +        depends on XFS_FS
>> +        select FS_RICHACL
>> +        help
>> +          Richacls are an implementation of NFSv4 ACLs, extended by file masks
>> +          to cleanly integrate into the POSIX file permission model.  To learn
>> +       more about them, see http://www.bestbits.at/richacl/.
>> +
>> +          If you don't know what Richacls are, say N.
>> +
>
> So now we have multiple compile time ACL configs that we have to
> test. Personally, I see no reason for making either posix or rich
> acls compile time dependent. How about we just change CONFIG_FS_XFS
> to have "select FS_POSIX_ACL" and "select FS_RICHACL"
> unconditionally, and then we can get rid of all the conditional
> code?

I'm sure neither kind of ACLs makes sense on many tiny systems, it
should be possible to disable them. XFS may not make sense on those
kinds of systems either, that is not my call to make though.

>> diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
>> index 9590a06..8c6da45 100644
>> --- a/fs/xfs/libxfs/xfs_format.h
>> +++ b/fs/xfs/libxfs/xfs_format.h
>> @@ -461,10 +461,18 @@ 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 */
>> +
>> +#ifdef CONFIG_XFS_RICHACL
>> +#define XFS_SB_FEAT_INCOMPAT_RICHACL (1 << 3)        /* richacls */
>> +#else
>> +#define XFS_SB_FEAT_INCOMPAT_RICHACL 0
>> +#endif
>> +
>
> Regardless of whether we build in richacl support, this is wrong.
> Feature bits are on-disk format definitions, so it will always have
> this value whether or not the kernel supports the feature.

This is so that xfs_mount_validate_sb() will complain when mounting a
richacl filesystem on a kernel which doesn't have richacl suport
compiled in. The same effect can be had with extra code there of
course.

>> @@ -722,7 +737,10 @@ 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);
>> +             if (XFS_IS_RICHACL(inode))
>> +                     error = richacl_chmod(inode, inode->i_mode);
>> +             else
>> +                     error = posix_acl_chmod(inode, inode->i_mode);
>>               if (error)
>>                       return error;
>>       }
>
> This sort of thing could do with a helper like:
>
> static inline int
> xfs_acl_chmod(struct inode *inode, int mode)
> {
>         if (IS_RICHACL(inode))
>                 return richacl_chmod(inode, mode);
>         return posix_acl_chmod(inode, mode);
> }

Alright.

>> +#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)
>> +{
>
> ...
>
> If we always build in ACL support, this can all go in xfs_acl.c.
>
>> +     struct xfs_inode *ip = XFS_I(inode);
>> +     struct richacl *acl;
>> +     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.
>> +              */
>> +             acl = (error == -ENOATTR) ? NULL : ERR_PTR(error);
>
> I rather dislike ternaries in code like this - it's hard to read the
> logic. Initalise acl to NULL, and then this simply becomes:
>
>                 if (error != -ENOATTR)
>                         acl = ERR_PTR(error);

As you prefer.

>> +     } else
>> +             acl = richacl_from_xattr(&init_user_ns, value, size);
>> +
>> +     if (!IS_ERR(acl))
>> +             set_cached_richacl(inode, acl);
>> +     kfree(value);
>> +
>> +     return acl;
>> +}
>> +
>> +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;
>> +
>> +     if (acl) {
>> +             /* 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);
>> +                     acl = NULL;
>> +             }
>
> Comment needed here - why does this now seem to accidentally fall
> through to removing the ACL?

Setting an ACL that is equivalent to a file mode is the same as
removing any existing ACLs and doing a chmod to that equivalent file
mode. It's the sams as with POSIX ACLs, and the code is the same as
well. I'll add a comment though.

> Also, why is this in the XFS specific
> code when it's generic richacl functionality that is being checked?

This turns into two non-atomic operations if we move it into generic code.

> Also, I really dislike the API where passing a NULL acl means to
> "set this acl" actually means "remove the existing ACL". Why no
> ->remove_acl method called from the generic code?

It's not uncommon, it saves inode operations and wiring-up code.

>> +#ifndef __FS_XFS_RICHACL_H
>> +#define __FS_XFS_RICHACL_H
>> +
>> +#include <linux/richacl.h>
>> +
>> +#ifdef CONFIG_XFS_RICHACL
>> +
>> +#define XFS_IS_RICHACL(inode) IS_RICHACL(inode)
>
> No. Just use IS_RICHACL() everywhere, and whatever build
> conditional that uses.

Okay.

>> --- a/fs/xfs/xfs_super.c
>> +++ b/fs/xfs/xfs_super.c
>> @@ -1500,7 +1500,19 @@ 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)) {
>> +#ifdef CONFIG_XFS_RICHACL
>> +             sb->s_flags |= MS_RICHACL;
>> +#else
>> +             error = -EOPNOTSUPP;
>> +             goto out_free_sb;
>> +#endif
>> +     } else {
>> +#ifdef CONFIG_XFS_POSIX_ACL
>> +             sb->s_flags |= MS_POSIXACL;
>> +#endif
>
> The whole point of having set_posix_acl_flag() is that it keeps
> the ifdef hackery out of the code. If we are going to keep build
> time config options for these, then please keep the wrappers to hide
> this mess...

That can indeed go away since xfs_mount_validate_sb() checks the mount
flags already.

Thanks,
Andreas
--
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]


#1244372 — Re: [PATCH v10 24/46] xfs: Add richacl support

FromDave Chinner <david@fromorbit.com>
Date2015-10-12 06:10 +0200
SubjectRe: [PATCH v10 24/46] xfs: Add richacl support
Message-ID<qiCAV-4pg-3@gated-at.bofh.it>
In reply to#1244337
On Mon, Oct 12, 2015 at 03:51:15AM +0200, Andreas Grünbacher wrote:
> 2015-10-12 2:10 GMT+02:00 Dave Chinner <david@fromorbit.com>:
> > On Mon, Oct 12, 2015 at 12:58:35AM +0200, Andreas Gruenbacher wrote:
> >> diff --git a/fs/xfs/Kconfig b/fs/xfs/Kconfig
> >> index 5d47b4d..05dd312 100644
> >> --- a/fs/xfs/Kconfig
> >> +++ b/fs/xfs/Kconfig
> >> @@ -52,6 +52,17 @@ config XFS_POSIX_ACL
> >>
> >>         If you don't know what Access Control Lists are, say N.
> >>
> >> +config XFS_RICHACL
> >> +        bool "XFS Rich Access Control Lists (EXPERIMENTAL)"
> >> +        depends on XFS_FS
> >> +        select FS_RICHACL
> >> +        help
> >> +          Richacls are an implementation of NFSv4 ACLs, extended by file masks
> >> +          to cleanly integrate into the POSIX file permission model.  To learn
> >> +       more about them, see http://www.bestbits.at/richacl/.
> >> +
> >> +          If you don't know what Richacls are, say N.
> >> +
> >
> > So now we have multiple compile time ACL configs that we have to
> > test. Personally, I see no reason for making either posix or rich
> > acls compile time dependent. How about we just change CONFIG_FS_XFS
> > to have "select FS_POSIX_ACL" and "select FS_RICHACL"
> > unconditionally, and then we can get rid of all the conditional
> > code?
> 
> I'm sure neither kind of ACLs makes sense on many tiny systems, it
> should be possible to disable them. XFS may not make sense on those
> kinds of systems either, that is not my call to make though.

Well, the smallest systems that use XFS are typically 1-2 disk NAS
boxes, and I can see them wanting richacls. As it is, the xfs kernel
module is almost 1MB of object code, so it you have a small embedded
box you don't want XFS. Almost all distros turn on ACL support I'm
not sure that it makes sense to have these config options in XFS
anymore....

> >> diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
> >> index 9590a06..8c6da45 100644
> >> --- a/fs/xfs/libxfs/xfs_format.h
> >> +++ b/fs/xfs/libxfs/xfs_format.h
> >> @@ -461,10 +461,18 @@ 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 */
> >> +
> >> +#ifdef CONFIG_XFS_RICHACL
> >> +#define XFS_SB_FEAT_INCOMPAT_RICHACL (1 << 3)        /* richacls */
> >> +#else
> >> +#define XFS_SB_FEAT_INCOMPAT_RICHACL 0
> >> +#endif
> >> +
> >
> > Regardless of whether we build in richacl support, this is wrong.
> > Feature bits are on-disk format definitions, so it will always have
> > this value whether or not the kernel supports the feature.
> 
> This is so that xfs_mount_validate_sb() will complain when mounting a
> richacl filesystem on a kernel which doesn't have richacl suport
> compiled in. The same effect can be had with extra code there of
> course.

If the kernel doesn't know about a feature, then it will report
"unknown feature". However, as of this patch set, the kernel will
know about the richacl feature, and so the correct error message
is to say "Rich ACLs not supported by this kernel".

Also, from a disk format perspective, this is a this is a read-only
compat feature, as kernels that don't have richacl support are still
able to mount and walk the filesystem without errors occurring. It's
only when allowing modifications are made that problems will arise,
so why did you make it an incompat feature?

> >> +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;
> >> +
> >> +     if (acl) {
> >> +             /* 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);
> >> +                     acl = NULL;
> >> +             }
> >
> > Comment needed here - why does this now seem to accidentally fall
> > through to removing the ACL?
> 
> Setting an ACL that is equivalent to a file mode is the same as
> removing any existing ACLs and doing a chmod to that equivalent file
> mode. It's the sams as with POSIX ACLs, and the code is the same as
> well. I'll add a comment though.
> 
> > Also, why is this in the XFS specific
> > code when it's generic richacl functionality that is being checked?
> 
> This turns into two non-atomic operations if we move it into generic code.

I don't follow you - this isn't an atomic operation to begin with...

> > Also, I really dislike the API where passing a NULL acl means to
> > "set this acl" actually means "remove the existing ACL". Why no
> > ->remove_acl method called from the generic code?
> 
> It's not uncommon, it saves inode operations and wiring-up code.

I know it's common. All it does is put extra branches in the
filesystem code to do this, because remove is a different operation
to set. The API sucks, and we're not limited on inode operations,
and the operator overloading makes the filesystem code unnecessarily
complex as it has to detect when to branch out ot remove or not...

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com
--
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]


#1244399 — Re: [PATCH v10 24/46] xfs: Add richacl support

FromAndreas Gruenbacher <agruenba@redhat.com>
Date2015-10-12 08:00 +0200
SubjectRe: [PATCH v10 24/46] xfs: Add richacl support
Message-ID<qiEjp-6Ib-19@gated-at.bofh.it>
In reply to#1244372
On Mon, Oct 12, 2015 at 6:05 AM, Dave Chinner <david@fromorbit.com> wrote:
> On Mon, Oct 12, 2015 at 03:51:15AM +0200, Andreas Grünbacher wrote:
>> 2015-10-12 2:10 GMT+02:00 Dave Chinner <david@fromorbit.com>:
>> > On Mon, Oct 12, 2015 at 12:58:35AM +0200, Andreas Gruenbacher wrote:
>> >> diff --git a/fs/xfs/Kconfig b/fs/xfs/Kconfig
>> >> index 5d47b4d..05dd312 100644
>> >> --- a/fs/xfs/Kconfig
>> >> +++ b/fs/xfs/Kconfig
>> >> @@ -52,6 +52,17 @@ config XFS_POSIX_ACL
>> >>
>> >>         If you don't know what Access Control Lists are, say N.
>> >>
>> >> +config XFS_RICHACL
>> >> +        bool "XFS Rich Access Control Lists (EXPERIMENTAL)"
>> >> +        depends on XFS_FS
>> >> +        select FS_RICHACL
>> >> +        help
>> >> +          Richacls are an implementation of NFSv4 ACLs, extended by file masks
>> >> +          to cleanly integrate into the POSIX file permission model.  To learn
>> >> +       more about them, see http://www.bestbits.at/richacl/.
>> >> +
>> >> +          If you don't know what Richacls are, say N.
>> >> +
>> >
>> > So now we have multiple compile time ACL configs that we have to
>> > test. Personally, I see no reason for making either posix or rich
>> > acls compile time dependent. How about we just change CONFIG_FS_XFS
>> > to have "select FS_POSIX_ACL" and "select FS_RICHACL"
>> > unconditionally, and then we can get rid of all the conditional
>> > code?
>>
>> I'm sure neither kind of ACLs makes sense on many tiny systems, it
>> should be possible to disable them. XFS may not make sense on those
>> kinds of systems either, that is not my call to make though.
>
> Well, the smallest systems that use XFS are typically 1-2 disk NAS
> boxes, and I can see them wanting richacls. As it is, the xfs kernel
> module is almost 1MB of object code, so it you have a small embedded
> box you don't want XFS. Almost all distros turn on ACL support I'm
> not sure that it makes sense to have these config options in XFS
> anymore....

You have me convinced about removing CONFIG_XFS_RICHACL.

>> >> diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
>> >> index 9590a06..8c6da45 100644
>> >> --- a/fs/xfs/libxfs/xfs_format.h
>> >> +++ b/fs/xfs/libxfs/xfs_format.h
>> >> @@ -461,10 +461,18 @@ 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 */
>> >> +
>> >> +#ifdef CONFIG_XFS_RICHACL
>> >> +#define XFS_SB_FEAT_INCOMPAT_RICHACL (1 << 3)        /* richacls */
>> >> +#else
>> >> +#define XFS_SB_FEAT_INCOMPAT_RICHACL 0
>> >> +#endif
>> >> +
>> >
>> > Regardless of whether we build in richacl support, this is wrong.
>> > Feature bits are on-disk format definitions, so it will always have
>> > this value whether or not the kernel supports the feature.
>>
>> This is so that xfs_mount_validate_sb() will complain when mounting a
>> richacl filesystem on a kernel which doesn't have richacl suport
>> compiled in. The same effect can be had with extra code there of
>> course.
>
> If the kernel doesn't know about a feature, then it will report
> "unknown feature". However, as of this patch set, the kernel will
> know about the richacl feature, and so the correct error message
> is to say "Rich ACLs not supported by this kernel".
>
> Also, from a disk format perspective, this is a this is a read-only
> compat feature, as kernels that don't have richacl support are still
> able to mount and walk the filesystem without errors occurring. It's
> only when allowing modifications are made that problems will arise,
> so why did you make it an incompat feature?

As a read-only compat flag, kernels that cannot enforce richacls would
still be able to mount richacl file systems read-only. That's a
problem when acls are used to forbid read/execute access.

>> >> +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;
>> >> +
>> >> +     if (acl) {
>> >> +             /* 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);
>> >> +                     acl = NULL;
>> >> +             }
>> >
>> > Comment needed here - why does this now seem to accidentally fall
>> > through to removing the ACL?
>>
>> Setting an ACL that is equivalent to a file mode is the same as
>> removing any existing ACLs and doing a chmod to that equivalent file
>> mode. It's the sams as with POSIX ACLs, and the code is the same as
>> well. I'll add a comment though.
>>
>> > Also, why is this in the XFS specific
>> > code when it's generic richacl functionality that is being checked?
>>
>> This turns into two non-atomic operations if we move it into generic code.
>
> I don't follow you - this isn't an atomic operation to begin with...

Right, I shouldn't have used the term atomic. It's one inode operation
under i_mutex, and the filesystem can pack it into one transaction.

Thanks,
Andreas
--
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]


#1246071 — Re: [PATCH v10 24/46] xfs: Add richacl support

FromAustin S Hemmelgarn <ahferroin7@gmail.com>
Date2015-10-13 21:30 +0200
SubjectRe: [PATCH v10 24/46] xfs: Add richacl support
Message-ID<qjdqO-7D7-25@gated-at.bofh.it>
In reply to#1244399

[Multipart message — attachments visible in raw view] — view raw

On 2015-10-12 01:57, Andreas Gruenbacher wrote:
> On Mon, Oct 12, 2015 at 6:05 AM, Dave Chinner <david@fromorbit.com> wrote:
>> On Mon, Oct 12, 2015 at 03:51:15AM +0200, Andreas Grünbacher wrote:
>>> 2015-10-12 2:10 GMT+02:00 Dave Chinner <david@fromorbit.com>:
>>>> On Mon, Oct 12, 2015 at 12:58:35AM +0200, Andreas Gruenbacher wrote:
>>>>> diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
>>>>> index 9590a06..8c6da45 100644
>>>>> --- a/fs/xfs/libxfs/xfs_format.h
>>>>> +++ b/fs/xfs/libxfs/xfs_format.h
>>>>> @@ -461,10 +461,18 @@ 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 */
>>>>> +
>>>>> +#ifdef CONFIG_XFS_RICHACL
>>>>> +#define XFS_SB_FEAT_INCOMPAT_RICHACL (1 << 3)        /* richacls */
>>>>> +#else
>>>>> +#define XFS_SB_FEAT_INCOMPAT_RICHACL 0
>>>>> +#endif
>>>>> +
>>>>
>>>> Regardless of whether we build in richacl support, this is wrong.
>>>> Feature bits are on-disk format definitions, so it will always have
>>>> this value whether or not the kernel supports the feature.
>>>
>>> This is so that xfs_mount_validate_sb() will complain when mounting a
>>> richacl filesystem on a kernel which doesn't have richacl suport
>>> compiled in. The same effect can be had with extra code there of
>>> course.
>>
>> If the kernel doesn't know about a feature, then it will report
>> "unknown feature". However, as of this patch set, the kernel will
>> know about the richacl feature, and so the correct error message
>> is to say "Rich ACLs not supported by this kernel".
>>
>> Also, from a disk format perspective, this is a this is a read-only
>> compat feature, as kernels that don't have richacl support are still
>> able to mount and walk the filesystem without errors occurring. It's
>> only when allowing modifications are made that problems will arise,
>> so why did you make it an incompat feature?
>
> As a read-only compat flag, kernels that cannot enforce richacls would
> still be able to mount richacl file systems read-only. That's a
> problem when acls are used to forbid read/execute access.
It's also an irrelevant problem, anyone with a minimal knowledge of the 
filesystem's on-disk layout can unset the feature bit by hand and force 
it to be mounted anyway, thus bypassing the ACL's (this is the case for 
any filesystem, not just XFS).  If someone has access to the hardware, 
they have access to the data stored on it, period, irrespective of what 
the data says about how it should be accessed.

The 3 most common cases for trying to mount a filesystem with this on a 
kernel that doesn't support it are:
a. Someone is trying to recover data on their own system using something 
like SystemRescueCD.
b. Someone is trying to recover data from a non-functional system that 
they own or have been authorized to access for this purpose by 
connecting the disk to another system.
c. Someone is trying to bisect a kernel bug or track down what config 
option is causing them issues.
All three of these cases _need_ to keep working properly without needing 
to manually twiddle with compat bits, otherwise it _will_ cause a lot of 
people to advocate not using richacls.

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


#1245717 — Re: [PATCH v10 24/46] xfs: Add richacl support

FromAndreas Gruenbacher <agruenba@redhat.com>
Date2015-10-13 15:40 +0200
SubjectRe: [PATCH v10 24/46] xfs: Add richacl support
Message-ID<qj7Y6-819-17@gated-at.bofh.it>
In reply to#1244372
On Mon, Oct 12, 2015 at 6:05 AM, Dave Chinner <david@fromorbit.com> wrote:
> On Mon, Oct 12, 2015 at 03:51:15AM +0200, Andreas Grünbacher wrote:
>> 2015-10-12 2:10 GMT+02:00 Dave Chinner <david@fromorbit.com>:
>> > Also, I really dislike the API where passing a NULL acl means to
>> > "set this acl" actually means "remove the existing ACL". Why no
>> > ->remove_acl method called from the generic code?
>>
>> It's not uncommon, it saves inode operations and wiring-up code.
>
> I know it's common. All it does is put extra branches in the
> filesystem code to do this, because remove is a different operation
> to set. The API sucks, and we're not limited on inode operations,
> and the operator overloading makes the filesystem code unnecessarily
> complex as it has to detect when to branch out ot remove or not...

I've tried it out. The filesystem code could be simplified (see the
richacl-wip [*] branch until the next posting). Adding a
remove_richacl inode operation on top of that really doesn't help.

Thanks,
Andreas

[*] git://git.kernel.org/pub/scm/linux/kernel/git/agruen/linux-richacl.git
richacl-wip
--
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]


#1244259 — [PATCH v10 28/46] richacl: Set the owner permissions to the owner mask

FromAndreas Gruenbacher <andreas.gruenbacher@gmail.com>
Date2015-10-12 01:10 +0200
Subject[PATCH v10 28/46] richacl: Set the owner permissions to the owner mask
Message-ID<qixUD-61y-33@gated-at.bofh.it>
In reply to#1244246
From: Andreas Gruenbacher <agruenba@redhat.com>

In the write-through case, change the acl so that owner@ is granted the
permissions set in the owner mask (to match what the permission check
algorithm grants the owner).

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

diff --git a/fs/richacl_compat.c b/fs/richacl_compat.c
index 7d007d7..16deeb4 100644
--- a/fs/richacl_compat.c
+++ b/fs/richacl_compat.c
@@ -416,3 +416,49 @@ richacl_propagate_everyone(struct richacl_alloc *alloc)
 	}
 	return 0;
 }
+
+/**
+ * richacl_set_owner_permissions  -  set the owner permissions to the owner mask
+ *
+ * In the write-through case, change the acl so that owner@ is granted the
+ * permissions set in the owner mask (to match what the permission check
+ * algorithm grants the owner).  This leaves at most one efective owner@ allow
+ * entry at the beginning of the acl.
+ */
+static int
+richacl_set_owner_permissions(struct richacl_alloc *alloc)
+{
+	unsigned int x = RICHACE_POSIX_ALWAYS_ALLOWED;
+	unsigned int owner_mask = alloc->acl->a_owner_mask & ~x;
+	unsigned int denied = 0;
+	struct richace *ace;
+
+	if (!((alloc->acl->a_flags & RICHACL_WRITE_THROUGH)))
+		return 0;
+
+	richacl_for_each_entry(ace, alloc->acl) {
+		if (richace_is_owner(ace)) {
+			if (richace_is_allow(ace) && !(owner_mask & denied)) {
+				richace_change_mask(alloc, &ace, owner_mask);
+				owner_mask = 0;
+			} else
+				richace_change_mask(alloc, &ace, 0);
+		} else {
+			if (richace_is_deny(ace))
+				denied |= ace->e_mask;
+		}
+	}
+
+	if (owner_mask & (denied |
+			  ~alloc->acl->a_other_mask |
+			  ~alloc->acl->a_group_mask)) {
+		ace = alloc->acl->a_entries;
+		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 = owner_mask;
+		ace->e_id.special = RICHACE_OWNER_SPECIAL_ID;
+	}
+	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]


#1244260 — [PATCH v10 30/46] richacl: Isolate the owner and group classes

FromAndreas Gruenbacher <andreas.gruenbacher@gmail.com>
Date2015-10-12 01:10 +0200
Subject[PATCH v10 30/46] richacl: Isolate the owner and group classes
Message-ID<qixUC-61y-29@gated-at.bofh.it>
In reply to#1244246
From: Andreas Gruenbacher <agruenba@redhat.com>

When applying the file masks to an acl, we need to ensure that no
process gets more permissions than allowed by its file mask.

This may require inserting an owner@ deny ace to ensure this if the
owner mask contains fewer permissions than the group or other mask.  For
example, when applying mode 0446 to the following acl:

   everyone@:rw::allow

A deny ace needs to be inserted so that the owner won't get elevated
write access:

   owner@:w::deny
   everyone@:rw::allow

Likewise, we may need to insert group class deny aces if the group mask
contains fewer permissions than the other mask.  For example, when
applying mode 0646 to the following acl:

   owner@:rw::allow
   everyone@:rw::allow

A deny ace needs to be inserted so that the owning group won't get
elevated write access:

   owner@:rw::allow
   group@:w::deny
   everyone@:rw::allow

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

diff --git a/fs/richacl_compat.c b/fs/richacl_compat.c
index 21ee31e..7e25343 100644
--- a/fs/richacl_compat.c
+++ b/fs/richacl_compat.c
@@ -503,3 +503,226 @@ richacl_set_other_permissions(struct richacl_alloc *alloc, unsigned int *added)
 	}
 	return 0;
 }
+
+/**
+ * richacl_max_allowed  -  maximum permissions that anybody is allowed
+ */
+static unsigned int
+richacl_max_allowed(struct richacl *acl)
+{
+	struct richace *ace;
+	unsigned int allowed = 0;
+
+	richacl_for_each_entry_reverse(ace, acl) {
+		if (richace_is_inherit_only(ace))
+			continue;
+		if (richace_is_allow(ace))
+			allowed |= ace->e_mask;
+		else if (richace_is_deny(ace)) {
+			if (richace_is_everyone(ace))
+				allowed &= ~ace->e_mask;
+		}
+	}
+	return allowed;
+}
+
+/**
+ * richacl_isolate_owner_class  -  limit the owner class to the owner file mask
+ * @alloc:	acl and number of allocated entries
+ *
+ * POSIX requires that after a chmod, the owner class is granted no more
+ * permissions than the owner file permission bits.  For richacls, this
+ * means that the owner class must not be granted any permissions that the
+ * owner mask does not include.
+ *
+ * When we apply file masks to an acl which grant more permissions to the group
+ * or other class than to the owner class, we may end up in a situation where
+ * the owner is granted additional permissions from other aces.  For example,
+ * given this acl:
+ *
+ *    everyone@:rwx::allow
+ *
+ * when file masks corresponding to mode 0406 are applied, after
+ * richacl_propagate_everyone() and __richacl_apply_masks(), we end up with:
+ *
+ *    owner@:r::allow
+ *    everyone@:rw::allow
+ *
+ * This acl still grants the owner rw access through the everyone@ allow ace.
+ * To fix this, we must deny the owner w access:
+ *
+ *    owner@:w::deny
+ *    owner@:r::allow
+ *    everyone@:rw::allow
+ */
+static int
+richacl_isolate_owner_class(struct richacl_alloc *alloc)
+{
+	struct richacl *acl = alloc->acl;
+	struct richace *ace;
+	unsigned int deny;
+
+	deny = richacl_max_allowed(acl) & ~acl->a_owner_mask;
+	if (!deny)
+		return 0;
+
+	/*
+	 * Figure out if we can update an existig OWNER@ DENY entry.
+	 */
+	richacl_for_each_entry(ace, acl) {
+		if (richace_is_inherit_only(ace))
+			continue;
+		if (richace_is_allow(ace))
+			break;
+		if (richace_is_owner(ace))
+			return richace_change_mask(alloc, &ace,
+						   ace->e_mask | deny);
+	}
+
+	/* Insert an owner@ deny entry at the front. */
+	ace = acl->a_entries;
+	if (richacl_insert_entry(alloc, &ace))
+		return -1;
+	ace->e_type = RICHACE_ACCESS_DENIED_ACE_TYPE;
+	ace->e_flags = RICHACE_SPECIAL_WHO;
+	ace->e_mask = deny;
+	ace->e_id.special = RICHACE_OWNER_SPECIAL_ID;
+	return 0;
+}
+
+/**
+ * __richacl_isolate_who  -  isolate entry from everyone@ allow entry
+ * @alloc:	acl and number of allocated entries
+ * @who:	identifier to isolate
+ * @deny:	permissions this identifier should not be allowed
+ *
+ * See richacl_isolate_group_class().
+ */
+static int
+__richacl_isolate_who(struct richacl_alloc *alloc, struct richace *who,
+		      unsigned int deny)
+{
+	struct richacl *acl = alloc->acl;
+	struct richace *ace, who_copy;
+	int n;
+
+	/*
+	 * Compute the permissions already defined for @who.  There are no
+	 * everyone@ deny aces left in the acl at this stage.
+	 */
+	richacl_for_each_entry(ace, acl) {
+		if (richace_is_inherit_only(ace))
+			continue;
+		if (richace_is_same_identifier(ace, who))
+			deny &= ~ace->e_mask;
+	}
+	if (!deny)
+		return 0;
+
+	/*
+	 * Figure out if we can update an existig deny entry.  Start from the
+	 * entry before the trailing everyone@ allow entry. We will not hit
+	 * everyone@ entries in the loop.
+	 */
+	for (n = acl->a_count - 2; n != -1; n--) {
+		ace = acl->a_entries + n;
+		if (richace_is_inherit_only(ace))
+			continue;
+		if (richace_is_deny(ace)) {
+			if (richace_is_same_identifier(ace, who))
+				return richace_change_mask(alloc, &ace,
+							   ace->e_mask | deny);
+		} else if (richace_is_allow(ace) &&
+			   (ace->e_mask & deny))
+			break;
+	}
+
+	/*
+	 * Insert a new entry before the trailing everyone@ deny entry.
+	 */
+	richace_copy(&who_copy, who);
+	ace = acl->a_entries + acl->a_count - 1;
+	if (richacl_insert_entry(alloc, &ace))
+		return -1;
+	richace_copy(ace, &who_copy);
+	ace->e_type = RICHACE_ACCESS_DENIED_ACE_TYPE;
+	ace->e_flags &= ~RICHACE_INHERITANCE_FLAGS;
+	ace->e_mask = deny;
+	return 0;
+}
+
+/**
+ * richacl_isolate_group_class  -  limit the group class to the group file mask
+ * @alloc:	acl and number of allocated entries
+ * @deny:	additional permissions to deny
+ *
+ * POSIX requires that after a chmod, the group class is granted no more
+ * permissions than the group file permission bits.  For richacls, this
+ * means that the group class must not be granted any permissions that the
+ * group mask does not include.
+ *
+ * When we apply file masks to an acl which grant more permissions to the other
+ * class than to the group class, we may end up in a situation where processes
+ * in the group class are granted additional permission from other aces.  For
+ * example, given this acl:
+ *
+ *    joe:rwx::allow
+ *    everyone@:rwx::allow
+ *
+ * when file masks corresponding to mode 0646 are applied, after
+ * richacl_propagate_everyone() and __richacl_apply_masks(), we end up with:
+ *
+ *    joe:r::allow
+ *    owner@:rw::allow
+ *    group@:r::allow
+ *    everyone@:rw::allow
+ *
+ * This acl still grants joe and group@ rw access through the everyone@ allow
+ * ace.  To fix this, we must deny w access to group class aces before the
+ * everyone@ allow ace at the end of the acl:
+ *
+ *    joe:r::allow
+ *    owner@:rw::allow
+ *    group@:r::allow
+ *    joe:w::deny
+ *    group@:w::deny
+ *    everyone@:rw::allow
+ */
+static int
+richacl_isolate_group_class(struct richacl_alloc *alloc, unsigned int deny)
+{
+	struct richace who = {
+		.e_flags = RICHACE_SPECIAL_WHO,
+		.e_id.special = RICHACE_GROUP_SPECIAL_ID,
+	};
+	struct richace *ace;
+
+	if (!alloc->acl->a_count)
+		return 0;
+	ace = alloc->acl->a_entries + alloc->acl->a_count - 1;
+	if (richace_is_inherit_only(ace) || !richace_is_everyone(ace))
+		return 0;
+	deny |= ace->e_mask & ~alloc->acl->a_group_mask;
+
+	if (deny) {
+		unsigned int n;
+
+		if (__richacl_isolate_who(alloc, &who, deny))
+			return -1;
+		/*
+		 * Start from the entry before the trailing everyone@ allow
+		 * entry.  We will not hit everyone@ entries in the loop.
+		 */
+		for (n = alloc->acl->a_count - 2; n != -1; n--) {
+			ace = alloc->acl->a_entries + n;
+
+			if (richace_is_inherit_only(ace) ||
+			    richace_is_owner(ace) ||
+			    richace_is_group(ace))
+				continue;
+			if (__richacl_isolate_who(alloc, ace, deny))
+				return -1;
+		}
+	}
+	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]


#1244261 — [PATCH v10 19/46] vfs: Add richacl permission checking

FromAndreas Gruenbacher <andreas.gruenbacher@gmail.com>
Date2015-10-12 01:10 +0200
Subject[PATCH v10 19/46] vfs: Add richacl permission checking
Message-ID<qixUC-61y-31@gated-at.bofh.it>
In reply to#1244246
From: Andreas Gruenbacher <agruenba@redhat.com>

Hook the richacl permission checking function into the vfs.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
 fs/namei.c     | 51 +++++++++++++++++++++++++++++++++++++++++++++++++--
 fs/posix_acl.c |  6 +++---
 2 files changed, 52 insertions(+), 5 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index 2eab19e..3822b5e 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -35,6 +35,7 @@
 #include <linux/fs_struct.h>
 #include <linux/posix_acl.h>
 #include <linux/hash.h>
+#include <linux/richacl.h>
 #include <asm/uaccess.h>
 
 #include "internal.h"
@@ -255,7 +256,40 @@ void putname(struct filename *name)
 		__putname(name);
 }
 
-static int check_acl(struct inode *inode, int mask)
+static int check_richacl(struct inode *inode, int mask)
+{
+#ifdef CONFIG_FS_RICHACL
+	struct richacl *acl;
+
+	if (mask & MAY_NOT_BLOCK) {
+		acl = get_cached_richacl_rcu(inode);
+		if (!acl)
+			goto no_acl;
+		/* no ->get_richacl() calls in RCU mode... */
+		if (acl == ACL_NOT_CACHED)
+			return -ECHILD;
+		return richacl_permission(inode, acl, mask & ~MAY_NOT_BLOCK);
+	}
+
+	acl = get_richacl(inode);
+	if (IS_ERR(acl))
+		return PTR_ERR(acl);
+	if (acl) {
+		int error = richacl_permission(inode, acl, mask);
+		richacl_put(acl);
+		return error;
+	}
+no_acl:
+#endif
+	if (mask & (MAY_DELETE_SELF | MAY_TAKE_OWNERSHIP |
+		    MAY_CHMOD | MAY_SET_TIMES)) {
+		/* File permission bits cannot grant this. */
+		return -EACCES;
+	}
+	return -EAGAIN;
+}
+
+static int check_posix_acl(struct inode *inode, int mask)
 {
 #ifdef CONFIG_FS_POSIX_ACL
 	struct posix_acl *acl;
@@ -290,11 +324,24 @@ static int acl_permission_check(struct inode *inode, int mask)
 {
 	unsigned int mode = inode->i_mode;
 
+	/*
+	 * With POSIX ACLs, the (mode & S_IRWXU) bits exactly match the owner
+	 * permissions, and we can skip checking posix acls for the owner.
+	 * With richacls, the owner may be granted fewer permissions than the
+	 * mode bits seem to suggest (for example, append but not write), and
+	 * we always need to check the richacl.
+	 */
+
+	if (IS_RICHACL(inode)) {
+		int error = check_richacl(inode, mask);
+		if (error != -EAGAIN)
+			return error;
+	}
 	if (likely(uid_eq(current_fsuid(), inode->i_uid)))
 		mode >>= 6;
 	else {
 		if (IS_POSIXACL(inode) && (mode & S_IRWXG)) {
-			int error = check_acl(inode, mask);
+			int error = check_posix_acl(inode, mask);
 			if (error != -EAGAIN)
 				return error;
 		}
diff --git a/fs/posix_acl.c b/fs/posix_acl.c
index 1d766a5..3459bd5 100644
--- a/fs/posix_acl.c
+++ b/fs/posix_acl.c
@@ -100,13 +100,13 @@ struct posix_acl *get_acl(struct inode *inode, int type)
 {
 	struct posix_acl *acl;
 
+	if (!IS_POSIXACL(inode))
+		return NULL;
+
 	acl = get_cached_acl(inode, type);
 	if (acl != ACL_NOT_CACHED)
 		return acl;
 
-	if (!IS_POSIXACL(inode))
-		return NULL;
-
 	/*
 	 * A filesystem can force a ACL callback by just never filling the
 	 * ACL cache. But normally you'd fill the cache either at 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]


#1244262 — [PATCH v10 26/46] richacl: Move everyone@ aces down the acl

FromAndreas Gruenbacher <andreas.gruenbacher@gmail.com>
Date2015-10-12 01:10 +0200
Subject[PATCH v10 26/46] richacl: Move everyone@ aces down the acl
Message-ID<qixUD-61y-35@gated-at.bofh.it>
In reply to#1244246
From: Andreas Gruenbacher <agruenba@redhat.com>

The POSIX standard puts processes which are not the owner or a member in
the owning group or which match any ace other then everyone@ on the
other file class.  We only know if a process is in the other class after
processing the entire acl.

Move all everyone@ aces in the acl down in the acl so that at most a
single everyone@ allow ace remains at the end.  Permissions which are
not explicitly allowed are implicitly denied, so an everyone@ deny ace
is unneeded.

The everyone@ aces can be moved down the acl without changing the
permissions that the acl grants.  This transformation simplifies the
following algorithms, and eventually allows us to turn the final
everyone@ allow ace into an entry for the other class.

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

diff --git a/fs/richacl_compat.c b/fs/richacl_compat.c
index 341e429..4f0acf5 100644
--- a/fs/richacl_compat.c
+++ b/fs/richacl_compat.c
@@ -153,3 +153,68 @@ richace_change_mask(struct richacl_alloc *alloc, struct richace **ace,
 	}
 	return 0;
 }
+
+/**
+ * richacl_move_everyone_aces_down  -  move everyone@ aces to the end of the acl
+ * @alloc:	acl and number of allocated entries
+ *
+ * Move all everyone aces to the end of the acl so that only a single everyone@
+ * allow ace remains at the end, and update the mask fields of all aces on the
+ * way.  The last ace of the resulting acl will be an everyone@ allow ace only
+ * if @acl grants any permissions to @everyone.  No @everyone deny aces will
+ * remain.
+ *
+ * This transformation does not alter the permissions that the acl grants.
+ * Having at most one everyone@ allow ace at the end of the acl helps us in the
+ * following algorithms.
+ */
+static int
+richacl_move_everyone_aces_down(struct richacl_alloc *alloc)
+{
+	struct richace *ace;
+	unsigned int allowed = 0, denied = 0;
+
+	richacl_for_each_entry(ace, alloc->acl) {
+		if (richace_is_inherit_only(ace))
+			continue;
+		if (richace_is_everyone(ace)) {
+			if (richace_is_allow(ace))
+				allowed |= (ace->e_mask & ~denied);
+			else if (richace_is_deny(ace))
+				denied |= (ace->e_mask & ~allowed);
+			else
+				continue;
+			if (richace_change_mask(alloc, &ace, 0))
+				return -1;
+		} else {
+			if (richace_is_allow(ace)) {
+				if (richace_change_mask(alloc, &ace, allowed |
+						(ace->e_mask & ~denied)))
+					return -1;
+			} else if (richace_is_deny(ace)) {
+				if (richace_change_mask(alloc, &ace, denied |
+						(ace->e_mask & ~allowed)))
+					return -1;
+			}
+		}
+	}
+	if (allowed & ~RICHACE_POSIX_ALWAYS_ALLOWED) {
+		struct richace *last_ace = ace - 1;
+
+		if (alloc->acl->a_entries &&
+		    richace_is_everyone(last_ace) &&
+		    richace_is_allow(last_ace) &&
+		    richace_is_inherit_only(last_ace) &&
+		    last_ace->e_mask == allowed)
+			last_ace->e_flags &= ~RICHACE_INHERIT_ONLY_ACE;
+		else {
+			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 = allowed;
+			ace->e_id.special = RICHACE_EVERYONE_SPECIAL_ID;
+		}
+	}
+	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]


#1244263 — [PATCH v10 18/46] richacl: Add richacl xattr handler

FromAndreas Gruenbacher <andreas.gruenbacher@gmail.com>
Date2015-10-12 01:10 +0200
Subject[PATCH v10 18/46] richacl: Add richacl xattr handler
Message-ID<qixUD-61y-37@gated-at.bofh.it>
In reply to#1244246
From: Andreas Gruenbacher <agruenba@redhat.com>

Add richacl xattr handler implementing the xattr operations based on the
get_richacl and set_richacl inode operations.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
 fs/richacl_xattr.c            | 78 +++++++++++++++++++++++++++++++++++++++++++
 include/linux/richacl_xattr.h |  2 ++
 2 files changed, 80 insertions(+)

diff --git a/fs/richacl_xattr.c b/fs/richacl_xattr.c
index cd9979d..dc529dc 100644
--- a/fs/richacl_xattr.c
+++ b/fs/richacl_xattr.c
@@ -18,7 +18,9 @@
 #include <linux/fs.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/xattr.h>
 #include <linux/richacl_xattr.h>
+#include <uapi/linux/xattr.h>
 
 MODULE_LICENSE("GPL");
 
@@ -161,6 +163,82 @@ richacl_to_xattr(struct user_namespace *user_ns,
 }
 EXPORT_SYMBOL_GPL(richacl_to_xattr);
 
+static size_t
+richacl_xattr_list(struct dentry *dentry, char *list, size_t list_len,
+		   const char *name, size_t name_len, int handler_flags)
+{
+	const size_t size = sizeof(XATTR_NAME_RICHACL);
+
+	if (!IS_RICHACL(d_backing_inode(dentry)))
+		return 0;
+	if (list && size <= list_len)
+		memcpy(list, XATTR_NAME_RICHACL, size);
+	return size;
+}
+
+static int
+richacl_xattr_get(struct dentry *dentry, const char *name, void *buffer,
+		  size_t buffer_size, int handler_flags)
+{
+	struct inode *inode = d_backing_inode(dentry);
+	struct richacl *acl;
+	int error;
+
+	if (strcmp(name, "") != 0)
+		return -EINVAL;
+	if (!IS_RICHACL(inode))
+		return EOPNOTSUPP;
+	if (S_ISLNK(inode->i_mode))
+		return -EOPNOTSUPP;
+	acl = get_richacl(inode);
+	if (IS_ERR(acl))
+		return PTR_ERR(acl);
+	if (acl == NULL)
+		return -ENODATA;
+	error = richacl_to_xattr(&init_user_ns, acl, buffer, buffer_size);
+	richacl_put(acl);
+	return error;
+}
+
+static int
+richacl_xattr_set(struct dentry *dentry, const char *name,
+		  const void *value, size_t size, int flags, int handler_flags)
+{
+	struct inode *inode = d_backing_inode(dentry);
+	struct richacl *acl = NULL;
+	int ret;
+
+	if (strcmp(name, "") != 0)
+		return -EINVAL;
+	if (!IS_RICHACL(inode))
+		return -EOPNOTSUPP;
+	if (!inode->i_op->set_richacl)
+		return -EOPNOTSUPP;
+
+	if (!uid_eq(current_fsuid(), inode->i_uid) &&
+	    inode_permission(inode, MAY_CHMOD) &&
+	    !capable(CAP_FOWNER))
+		return -EPERM;
+
+	if (value) {
+		acl = richacl_from_xattr(&init_user_ns, value, size);
+		if (IS_ERR(acl))
+			return PTR_ERR(acl);
+	}
+
+	ret = inode->i_op->set_richacl(inode, acl);
+	richacl_put(acl);
+	return ret;
+}
+
+struct xattr_handler richacl_xattr_handler = {
+	.prefix = XATTR_NAME_RICHACL,
+	.list = richacl_xattr_list,
+	.get = richacl_xattr_get,
+	.set = richacl_xattr_set,
+};
+EXPORT_SYMBOL(richacl_xattr_handler);
+
 /*
  * Fix up the uids and gids in richacl extended attributes in place.
  */
diff --git a/include/linux/richacl_xattr.h b/include/linux/richacl_xattr.h
index f84cc21..dac4e32 100644
--- a/include/linux/richacl_xattr.h
+++ b/include/linux/richacl_xattr.h
@@ -59,4 +59,6 @@ static inline void richacl_fix_xattr_to_user(void *value, size_t size)
 }
 #endif
 
+extern struct xattr_handler richacl_xattr_handler;
+
 #endif /* __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] | [prev] | [next] | [standalone]


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

Back to top | Article view | linux.kernel


csiph-web