Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1261574 > unrolled thread
| Started by | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| First post | 2015-11-03 16:20 +0100 |
| Last post | 2015-11-03 17:20 +0100 |
| Articles | 20 on this page of 68 — 3 participants |
Back to article view | Back to linux.kernel
[PATCH v13 00/51] Richacls Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:20 +0100
[PATCH v13 08/51] richacl: Compute maximum file masks from an acl Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:20 +0100
[PATCH v13 10/51] vfs: Cache base_acl objects in inodes Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:20 +0100
Re: [PATCH v13 10/51] vfs: Cache base_acl objects in inodes Andreas Dilger <adilger@dilger.ca> - 2015-11-03 23:40 +0100
Re: [PATCH v13 10/51] vfs: Cache base_acl objects in inodes Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-04 23:00 +0100
[PATCH v13 07/51] richacl: Permission mapping functions Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:20 +0100
[PATCH v13 02/51] vfs: Add MAY_CREATE_FILE and MAY_CREATE_DIR permission flags Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:20 +0100
Re: [PATCH v13 02/51] vfs: Add MAY_CREATE_FILE and MAY_CREATE_DIR permission flags Andreas Dilger <adilger@dilger.ca> - 2015-11-04 03:40 +0100
Re: [PATCH v13 02/51] vfs: Add MAY_CREATE_FILE and MAY_CREATE_DIR permission flags Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-04 04:10 +0100
[PATCH v13 11/51] vfs: Add get_richacl and set_richacl inode operations Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:20 +0100
[PATCH v13 04/51] vfs: Make the inode passed to inode_change_ok non-const Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:20 +0100
[PATCH v13 12/51] vfs: Cache richacl in struct inode Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:20 +0100
Re: [PATCH v13 12/51] vfs: Cache richacl in struct inode Andreas Dilger <adilger@dilger.ca> - 2015-11-04 03:10 +0100
Re: [PATCH v13 12/51] vfs: Cache richacl in struct inode Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-04 23:20 +0100
[PATCH v13 05/51] vfs: Add permission flags for setting file attributes Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:20 +0100
[PATCH v13 06/51] richacl: In-memory representation and helper functions Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:20 +0100
[PATCH v13 29/51] richacl: Move everyone@ aces down the acl Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 50/51] nfs: Add richacl support Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 30/51] richacl: Propagate everyone@ permissions to other aces Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 40/51] nfsd: Add support for the MAY_CREATE_{FILE,DIR} permissions Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 43/51] ext4: Don't allow unmapped identifiers in richacls Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
Re: [PATCH v13 43/51] ext4: Don't allow unmapped identifiers in richacls Andreas Dilger <adilger@dilger.ca> - 2015-11-04 03:30 +0100
[PATCH v13 26/51] xfs: Plug memory leak in xfs_attrmulti_attr_set Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 45/51] sunrpc: Allow to demand-allocate pages to encode into Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
Re: [PATCH v13 45/51] sunrpc: Allow to demand-allocate pages to encode into Trond Myklebust <trond.myklebust@primarydata.com> - 2015-11-03 17:30 +0100
Re: [PATCH v13 45/51] sunrpc: Allow to demand-allocate pages to encode into Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-05 12:10 +0100
Re: [PATCH v13 45/51] sunrpc: Allow to demand-allocate pages to encode into Trond Myklebust <trond.myklebust@primarydata.com> - 2015-11-05 17:00 +0100
Re: [PATCH v13 45/51] sunrpc: Allow to demand-allocate pages to encode into Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-08 23:20 +0100
[PATCH v13 48/51] nfs: Remove unused xdr page offsets in getacl/setacl arguments Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 51/51] nfs: Add support for the v4.1 dacl attribute Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 39/51] nfsd: Add support for the v4.1 dacl attribute Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 32/51] richacl: Set the other permissions to the other mask Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 33/51] richacl: Isolate the owner and group classes Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 28/51] richacl: acl editing helper functions Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 47/51] nfs: Fix GETATTR bitmap verification Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
Re: [PATCH v13 47/51] nfs: Fix GETATTR bitmap verification Trond Myklebust <trond.myklebust@primarydata.com> - 2015-11-03 17:40 +0100
[PATCH v13 42/51] nfsd: Add support for unmapped richace identifiers Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 19/51] vfs: Add richacl permission checking Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 25/51] xfs: Add richacl support Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 44/51] xfs: Don't allow unmapped identifiers in richacls Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 46/51] sunrpc: Add xdr_init_encode_pages Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 49/51] nfs: Distinguish missing users and groups from nobody Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 41/51] richacl: Add support for unmapped identifiers Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 38/51] nfsd: Add richacl support Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 36/51] nfsd: Keep list of acls to dispose of in compoundargs Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 37/51] nfsd: Use richacls as internal acl representation Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:40 +0100
[PATCH v13 35/51] richacl: Create richacl from mode values Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:40 +0100
[PATCH v13 31/51] richacl: Set the owner permissions to the owner mask Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:50 +0100
[PATCH v13 34/51] richacl: Apply the file masks to a richacl Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:50 +0100
[PATCH v13 27/51] xfs: Fix richacl access by ioctl Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:50 +0100
[PATCH v13 16/51] richacl: Automatic Inheritance Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 17:00 +0100
[PATCH v13 15/51] richacl: Create-time inheritance Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 17:00 +0100
[PATCH v13 24/51] xfs: Change how listxattr generates synthetic attributes Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 17:00 +0100
[PATCH v13 21/51] ext4: Add richacl feature flag Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 17:00 +0100
Re: [PATCH v13 21/51] ext4: Add richacl feature flag Andreas Dilger <adilger@dilger.ca> - 2015-11-04 03:20 +0100
Re: [PATCH v13 21/51] ext4: Add richacl feature flag Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-04 03:30 +0100
Re: [PATCH v13 21/51] ext4: Add richacl feature flag Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-04 03:50 +0100
[PATCH v13 14/51] richacl: Check if an acl is equivalent to a file mode Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 17:00 +0100
[PATCH v13 20/51] ext4: Add richacl support Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 17:00 +0100
Re: [PATCH v13 20/51] ext4: Add richacl support Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-04 03:20 +0100
Re: [PATCH v13 20/51] ext4: Add richacl support Andreas Dilger <adilger@dilger.ca> - 2015-11-04 03:20 +0100
[PATCH v13 18/51] richacl: Add richacl xattr handler Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 17:00 +0100
[PATCH v13 22/51] xfs: Fix error path in xfs_get_acl Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 17:00 +0100
[PATCH v13 23/51] xfs: Make xfs_set_mode non-static Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 17:00 +0100
[PATCH v13 13/51] richacl: Update the file masks in chmod() Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 17:00 +0100
[PATCH v13 09/51] richacl: Permission check algorithm Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 17:10 +0100
[PATCH v13 17/51] richacl: xattr mapping functions Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 17:10 +0100
[PATCH v13 03/51] vfs: Add MAY_DELETE_SELF and MAY_DELETE_CHILD permission flags Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 17:20 +0100
Page 2 of 4 — ← Prev page 1 [2] 3 4 Next page →
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-03 16:30 +0100 |
| Subject | [PATCH v13 43/51] ext4: Don't allow unmapped identifiers in richacls |
| Message-ID | <qqLH4-4sG-17@gated-at.bofh.it> |
| In reply to | #1261574 |
Don't allow acls which contain unmapped identifiers: they are meaningful
for remote file systems only.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
fs/ext4/richacl.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/fs/ext4/richacl.c b/fs/ext4/richacl.c
index 906d048..2115385 100644
--- a/fs/ext4/richacl.c
+++ b/fs/ext4/richacl.c
@@ -74,6 +74,10 @@ __ext4_set_richacl(handle_t *handle, struct inode *inode, struct richacl *acl)
int retval, size;
void *value;
+ /* Don't allow acls with unmapped identifiers. */
+ if (richacl_has_unmapped_identifiers(acl))
+ return -EINVAL;
+
if (richacl_equiv_mode(acl, &mode) == 0) {
inode->i_ctime = ext4_current_time(inode);
inode->i_mode = mode;
--
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]
| From | Andreas Dilger <adilger@dilger.ca> |
|---|---|
| Date | 2015-11-04 03:30 +0100 |
| Subject | Re: [PATCH v13 43/51] ext4: Don't allow unmapped identifiers in richacls |
| Message-ID | <qqVZM-2HI-7@gated-at.bofh.it> |
| In reply to | #1261597 |
[Multipart message — attachments visible in raw view] — view raw
> On Nov 3, 2015, at 8:17 AM, Andreas Gruenbacher <agruenba@redhat.com> wrote:
>
> Don't allow acls which contain unmapped identifiers: they are meaningful
> for remote file systems only.
Looks fine.
Reviewed-by: Andreas Dilger <adilger@dilger.ca>
> Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
> ---
> fs/ext4/richacl.c | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/fs/ext4/richacl.c b/fs/ext4/richacl.c
> index 906d048..2115385 100644
> --- a/fs/ext4/richacl.c
> +++ b/fs/ext4/richacl.c
> @@ -74,6 +74,10 @@ __ext4_set_richacl(handle_t *handle, struct inode *inode, struct richacl *acl)
> int retval, size;
> void *value;
>
> + /* Don't allow acls with unmapped identifiers. */
> + if (richacl_has_unmapped_identifiers(acl))
> + return -EINVAL;
> +
> if (richacl_equiv_mode(acl, &mode) == 0) {
> inode->i_ctime = ext4_current_time(inode);
> inode->i_mode = mode;
> --
> 2.5.0
>
Cheers, Andreas
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-03 16:30 +0100 |
| Subject | [PATCH v13 26/51] xfs: Plug memory leak in xfs_attrmulti_attr_set |
| Message-ID | <qqLH4-4sG-21@gated-at.bofh.it> |
| In reply to | #1261574 |
When setting attributes via XFS_IOC_ATTRMULTI_BY_HANDLE, the user-space
buffer is copied into a new kernel-space buffer via memdup_user; that
buffer then isn't freed.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
---
fs/xfs/xfs_ioctl.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index ea7d85a..e939c20 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -482,6 +482,7 @@ xfs_attrmulti_attr_set(
__uint32_t flags)
{
unsigned char *kbuf;
+ int error;
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
return -EPERM;
@@ -492,7 +493,9 @@ xfs_attrmulti_attr_set(
if (IS_ERR(kbuf))
return PTR_ERR(kbuf);
- return xfs_attr_set(XFS_I(inode), name, kbuf, len, flags);
+ error = xfs_attr_set(XFS_I(inode), name, kbuf, len, flags);
+ kfree(kbuf);
+ return error;
}
int
--
2.5.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-03 16:30 +0100 |
| Subject | [PATCH v13 45/51] sunrpc: Allow to demand-allocate pages to encode into |
| Message-ID | <qqLH4-4sG-19@gated-at.bofh.it> |
| In reply to | #1261574 |
When encoding large, variable-length objects such as acls into xdr_bufs,
it is easier to allocate buffer pages on demand rather than precomputing
the required buffer size.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
net/sunrpc/xdr.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
index 4439ac4..63c1c36 100644
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -537,6 +537,15 @@ static __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr,
*/
xdr->scratch.iov_base = xdr->p;
xdr->scratch.iov_len = frag1bytes;
+
+ if (!*xdr->page_ptr) {
+ struct page *page = alloc_page(GFP_NOFS);
+
+ if (!page)
+ return NULL;
+ *xdr->page_ptr = page;
+ }
+
p = page_address(*xdr->page_ptr);
/*
* Note this is where the next encode will start after we've
--
2.5.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Trond Myklebust <trond.myklebust@primarydata.com> |
|---|---|
| Date | 2015-11-03 17:30 +0100 |
| Subject | Re: [PATCH v13 45/51] sunrpc: Allow to demand-allocate pages to encode into |
| Message-ID | <qqMDa-5cu-49@gated-at.bofh.it> |
| In reply to | #1261599 |
On Tue, Nov 3, 2015 at 10:17 AM, Andreas Gruenbacher <agruenba@redhat.com> wrote: > When encoding large, variable-length objects such as acls into xdr_bufs, > it is easier to allocate buffer pages on demand rather than precomputing > the required buffer size. > NACK. We're not doing allocations from inside the XDR encoders. This can and should be done before calling into the SUNRPC layer. Trond -- 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]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-05 12:10 +0100 |
| Subject | Re: [PATCH v13 45/51] sunrpc: Allow to demand-allocate pages to encode into |
| Message-ID | <qrqAy-5Nb-25@gated-at.bofh.it> |
| In reply to | #1261699 |
Trond, On Tue, Nov 3, 2015 at 5:25 PM, Trond Myklebust <trond.myklebust@primarydata.com> wrote: > On Tue, Nov 3, 2015 at 10:17 AM, Andreas Gruenbacher > <agruenba@redhat.com> wrote: >> When encoding large, variable-length objects such as acls into xdr_bufs, >> it is easier to allocate buffer pages on demand rather than precomputing >> the required buffer size. > > NACK. We're not doing allocations from inside the XDR encoders. This > can and should be done before calling into the SUNRPC layer. an XDR-encoded ACL can be up to 64k (16 pages) in size. In practice, large ACLs like that will almost never occur and almost all ACLs will fit into a single page though. The XDR-encoded ACL contains strings for the user and group names which need to be looked up when the idmapper is used. Those lookups are somewhat expensive; in addition, the lookup results can change over time. When precomputing the size, allocating space, and then encoding the ACL, we could run out of space when encoding. So we could always allocate the maximum 16 pages, encode the acl, and free the unused pages. This would be rather wasteful though. Given how simple it is to allocate pages as we go, this seems the better choice here. This doesn't break any existing code either; NULL page pointers would have oopsed in xdr_get_next_encode_buffer before. From the memory management point of view, there is no difference in preallocating GFP_NOFS pages and allocating them on demand; the pages are allocated in the same task and locking context in both cases. So could you please explain why you object to this change? 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]
| From | Trond Myklebust <trond.myklebust@primarydata.com> |
|---|---|
| Date | 2015-11-05 17:00 +0100 |
| Subject | Re: [PATCH v13 45/51] sunrpc: Allow to demand-allocate pages to encode into |
| Message-ID | <qrv7e-9F-51@gated-at.bofh.it> |
| In reply to | #1263100 |
On Thu, Nov 5, 2015 at 6:07 AM, Andreas Gruenbacher <agruenba@redhat.com> wrote: > Trond, > > On Tue, Nov 3, 2015 at 5:25 PM, Trond Myklebust > <trond.myklebust@primarydata.com> wrote: >> On Tue, Nov 3, 2015 at 10:17 AM, Andreas Gruenbacher >> <agruenba@redhat.com> wrote: >>> When encoding large, variable-length objects such as acls into xdr_bufs, >>> it is easier to allocate buffer pages on demand rather than precomputing >>> the required buffer size. >> >> NACK. We're not doing allocations from inside the XDR encoders. This >> can and should be done before calling into the SUNRPC layer. > > an XDR-encoded ACL can be up to 64k (16 pages) in size. In practice, > large ACLs like that will almost never occur and almost all ACLs will > fit into a single page though. > > The XDR-encoded ACL contains strings for the user and group names > which need to be looked up when the idmapper is used. Those lookups > are somewhat expensive; in addition, the lookup results can change > over time. When precomputing the size, allocating space, and then > encoding the ACL, we could run out of space when encoding. > > So we could always allocate the maximum 16 pages, encode the acl, and > free the unused pages. This would be rather wasteful though. > > Given how simple it is to allocate pages as we go, this seems the > better choice here. This doesn't break any existing code either; NULL > page pointers would have oopsed in xdr_get_next_encode_buffer before. > > From the memory management point of view, there is no difference in > preallocating GFP_NOFS pages and allocating them on demand; the pages > are allocated in the same task and locking context in both cases. > > So could you please explain why you object to this change? > Allocating memory deep in the bowels of the RPC code with the expectation that it will be freed by the caller of the RPC request is a layering violation of the ugliest sort. How is anyone who is unfamiliar with the code going to be able to understand what is going on without tracing through 1000 lines of code to spot where the allocation is happening? Aside from that, we do not want any non-critical blocking while holding the RPC socket lock. Your allocation request will block all further traffic to the server until it is satisfied. That includes blocking page writeback, which might actually free up memory to satisfy the allocation. As I said above, there is no reason whatsoever to have to do all this inside encode_setacl(). The entire ACL encoding into pages can be done before even calling into the RPC layer, just like we do today. -- 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]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-08 23:20 +0100 |
| Subject | Re: [PATCH v13 45/51] sunrpc: Allow to demand-allocate pages to encode into |
| Message-ID | <qsGtA-61G-11@gated-at.bofh.it> |
| In reply to | #1263352 |
On Thu, Nov 5, 2015 at 4:57 PM, Trond Myklebust
<trond.myklebust@primarydata.com> wrote:
> On Thu, Nov 5, 2015 at 6:07 AM, Andreas Gruenbacher <agruenba@redhat.com> wrote:
>> Trond,
>>
>> On Tue, Nov 3, 2015 at 5:25 PM, Trond Myklebust
>> <trond.myklebust@primarydata.com> wrote:
>>> On Tue, Nov 3, 2015 at 10:17 AM, Andreas Gruenbacher
>>> <agruenba@redhat.com> wrote:
>>>> When encoding large, variable-length objects such as acls into xdr_bufs,
>>>> it is easier to allocate buffer pages on demand rather than precomputing
>>>> the required buffer size.
>>>
>>> NACK. We're not doing allocations from inside the XDR encoders. This
>>> can and should be done before calling into the SUNRPC layer.
>>
>> an XDR-encoded ACL can be up to 64k (16 pages) in size. In practice,
>> large ACLs like that will almost never occur and almost all ACLs will
>> fit into a single page though.
>>
>> The XDR-encoded ACL contains strings for the user and group names
>> which need to be looked up when the idmapper is used. Those lookups
>> are somewhat expensive; in addition, the lookup results can change
>> over time. When precomputing the size, allocating space, and then
>> encoding the ACL, we could run out of space when encoding.
>>
>> So we could always allocate the maximum 16 pages, encode the acl, and
>> free the unused pages. This would be rather wasteful though.
>>
>> Given how simple it is to allocate pages as we go, this seems the
>> better choice here. This doesn't break any existing code either; NULL
>> page pointers would have oopsed in xdr_get_next_encode_buffer before.
>>
>> From the memory management point of view, there is no difference in
>> preallocating GFP_NOFS pages and allocating them on demand; the pages
>> are allocated in the same task and locking context in both cases.
>>
>> So could you please explain why you object to this change?
>
> Allocating memory deep in the bowels of the RPC code with the
> expectation that it will be freed by the caller of the RPC request is
> a layering violation of the ugliest sort.
Ah, there we have it, Godwin's Law for software discussions.
What happens here is the following: the caller sets up an xdr_stream
that contains an array of NULL page pointers (__nfs4_proc_set_acl ->
nfs4_encode_acl -> xdr_init_encode_pages). It does so on purpose to
tell the XDR layer to allocate pages for it as needed, and it knows it
is responsible for later freeing those pages.
Without this patch, the XDR layer would immediately Oops when hitting
a NULL page pointer. This tells us that the XDR layer is so far not
prepared to handle NULL page pointers, and that we can assign a
meaning to NULL page pointers without affecting existing callers.
Using the existing XDR layer for XDR-encoding ACLs makes sense because
the XDR layer already knows how to align things, encode into multiple
pages, handle strings that wrap across pages, etc. I really don't want
to duplicate all that for ACLs.
> How is anyone who is
> unfamiliar with the code going to be able to understand what is going
> on without tracing through 1000 lines of code to spot where the
> allocation is happening?
Somebody unfamiliar with the existing code will not understand it
without putting some effort in, either. What do you expect? Besides,
the caller doesn't care where the allocation is happening, it just
cares that it is happening when it should.
> Aside from that, we do not want any non-critical blocking while
> holding the RPC socket lock. Your allocation request will block all
> further traffic to the server until it is satisfied. That includes
> blocking page writeback, which might actually free up memory to
> satisfy the allocation.
>
> As I said above, there is no reason whatsoever to have to do all this
> inside encode_setacl(). The entire ACL encoding into pages can be done
> before even calling into the RPC layer, just like we do today.
You have pointed that out before, and as a consequence, it was fixed
in the July 22 snapshot (https://lwn.net/Articles/652058/):
* Changes to the nfs patches: acls are now encoded above the sunrpc
layer. This means we can no longer encode small acls directly into the
scratch area of an xdr_buf, we always have to allocate extra memory.
But we also don't need to touch the nfs sunrpc code, which Trond objected
to.
Since then, the ACL encoding happens in __nfs4_proc_set_acl, before
calling into the RPC layer.
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]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-03 16:30 +0100 |
| Subject | [PATCH v13 48/51] nfs: Remove unused xdr page offsets in getacl/setacl arguments |
| Message-ID | <qqLH4-4sG-25@gated-at.bofh.it> |
| In reply to | #1261574 |
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]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-03 16:30 +0100 |
| Subject | [PATCH v13 51/51] nfs: Add support for the v4.1 dacl attribute |
| Message-ID | <qqLH4-4sG-27@gated-at.bofh.it> |
| In reply to | #1261574 |
The dacl attribute includes Automatic Inheritance flags not supported by
the acl attribute. it is only supported in NFS version 4.1 and higher.
On systems where NFS version 4.0 is still the default, an additional
mount option is needed:
mount -t nfs4 -o vers=4.1 [...]
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
fs/nfs/nfs4proc.c | 2 +-
fs/nfs/nfs4xdr.c | 54 ++++++++++++++++++++++++++++++++++++++++++-------
include/linux/nfs_xdr.h | 2 +-
3 files changed, 49 insertions(+), 9 deletions(-)
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 7bb2dea..191369f 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -4556,7 +4556,7 @@ static struct richacl *__nfs4_get_acl_uncached(struct inode *inode)
struct nfs_server *server = NFS_SERVER(inode);
struct page *pages[DIV_ROUND_UP(NFS4ACL_SIZE_MAX, PAGE_SIZE)] = {};
struct nfs_getaclargs args = {
- .fh = NFS_FH(inode),
+ .inode = inode,
.acl_pages = pages,
.acl_len = ARRAY_SIZE(pages) * PAGE_SIZE,
};
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 2f1d6be..a73f7c6 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -1661,9 +1661,16 @@ encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compoun
encode_nfs4_stateid(xdr, &zero_stateid);
/* Encode attribute bitmap. */
- p = reserve_space(xdr, 2*4);
- *p++ = cpu_to_be32(1);
- *p = cpu_to_be32(FATTR4_WORD0_ACL);
+ if (arg->server->attr_bitmask[1] & FATTR4_WORD1_DACL) {
+ p = reserve_space(xdr, 3*4);
+ *p++ = cpu_to_be32(2);
+ *p++ = 0;
+ *p = cpu_to_be32(FATTR4_WORD1_DACL);
+ } else {
+ p = reserve_space(xdr, 2*4);
+ *p++ = cpu_to_be32(1);
+ *p = cpu_to_be32(FATTR4_WORD0_ACL);
+ }
attrlen_offset = xdr->buf->len;
xdr_reserve_space(xdr, 4); /* to be backfilled later */
@@ -2498,9 +2505,12 @@ static void nfs4_xdr_enc_getacl(struct rpc_rqst *req, struct xdr_stream *xdr,
encode_compound_hdr(xdr, req, &hdr);
encode_sequence(xdr, &args->seq_args, &hdr);
- encode_putfh(xdr, args->fh, &hdr);
+ encode_putfh(xdr, NFS_FH(args->inode), &hdr);
replen = hdr.replen + op_decode_hdr_maxsz + 1;
- encode_getattr_two(xdr, FATTR4_WORD0_ACL, FATTR4_WORD1_MODE, &hdr);
+ if (NFS_SERVER(args->inode)->attr_bitmask[1] & FATTR4_WORD1_DACL)
+ encode_getattr_two(xdr, 0, FATTR4_WORD1_MODE | FATTR4_WORD1_DACL, &hdr);
+ else
+ encode_getattr_two(xdr, FATTR4_WORD0_ACL, FATTR4_WORD1_MODE, &hdr);
xdr_inline_pages(&req->rq_rcv_buf, replen << 2,
args->acl_pages, 0, args->acl_len);
@@ -5402,12 +5412,25 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
if (unlikely(bitmap[0] & (FATTR4_WORD0_ACL - 1U)))
return -EIO;
- if (likely(bitmap[0] & FATTR4_WORD0_ACL)) {
+
+ if (bitmap[0] & FATTR4_WORD0_ACL) {
+ struct richace *ace;
+
+ if (bitmap[1] & FATTR4_WORD1_DACL)
+ return -EIO;
+
acl = decode_acl_entries(xdr, res->server);
if (IS_ERR(acl))
return PTR_ERR(acl);
+
+ status = -EIO;
+ richacl_for_each_entry(ace, acl) {
+ if (ace->e_flags & RICHACE_INHERITED_ACE)
+ goto out;
+ }
+
bitmap[0] &= ~FATTR4_WORD0_ACL;
- } else
+ } else if (!(bitmap[1] & FATTR4_WORD1_DACL))
return -EOPNOTSUPP;
status = -EIO;
@@ -5417,6 +5440,23 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
status = decode_attr_mode(xdr, bitmap, &res->mode);
if (status < 0)
goto out;
+
+ if (bitmap[1] & FATTR4_WORD1_DACL) {
+ unsigned int flags;
+ __be32 *p;
+
+ p = xdr_inline_decode(xdr, 4);
+ if (unlikely(!p))
+ return -EIO;
+ flags = be32_to_cpup(p);
+
+ acl = decode_acl_entries(xdr, res->server);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+
+ acl->a_flags = flags;
+ bitmap[1] &= ~FATTR4_WORD1_DACL;
+ }
status = 0;
out:
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 337c341..9c2a078 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -695,7 +695,7 @@ struct nfs_setaclres {
struct nfs_getaclargs {
struct nfs4_sequence_args seq_args;
- struct nfs_fh * fh;
+ struct inode * inode;
size_t acl_len;
struct page ** acl_pages;
};
--
2.5.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-03 16:30 +0100 |
| Subject | [PATCH v13 39/51] nfsd: Add support for the v4.1 dacl attribute |
| Message-ID | <qqLH5-4sG-37@gated-at.bofh.it> |
| In reply to | #1261574 |
Richacls support the Automatic Inheritance permission propagation
mechanism as specified in NFSv4.1. Over NFS, this requires support for
the dacl attribute: compared to the acl attribute, the dacl attribute
has an additional flags field which indicates when Automatic Inheritance
is in use.
The server will only indicate dacl attribute support in protocol version
4.1 and later, on file systems with richacl support.
This commit also adds support for the NFSv4.1 NFS4_ACE_WRITE_RETENTION
and NFS4_ACE_WRITE_RETENTION_HOLD ACL permissions.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Acked-by: J. Bruce Fields <bfields@redhat.com>
---
fs/nfsd/nfs4proc.c | 3 +-
fs/nfsd/nfs4xdr.c | 219 ++++++++++++++++++++++++++++++----------------
fs/nfsd/nfsd.h | 6 +-
include/linux/nfs4.h | 1 +
include/uapi/linux/nfs4.h | 3 +-
5 files changed, 155 insertions(+), 77 deletions(-)
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 1bcfda2..a053e78 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -1781,7 +1781,8 @@ static inline u32 nfsd4_getattr_rsize(struct svc_rqst *rqstp,
u32 bmap0 = bmap[0], bmap1 = bmap[1], bmap2 = bmap[2];
u32 ret = 0;
- if (bmap0 & FATTR4_WORD0_ACL)
+ if (bmap0 & FATTR4_WORD0_ACL ||
+ bmap1 & FATTR4_WORD1_DACL)
return svc_max_payload(rqstp);
if (bmap0 & FATTR4_WORD0_FS_LOCATIONS)
return svc_max_payload(rqstp);
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 682a7d8..33d028c 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -301,6 +301,68 @@ nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval)
DECODE_TAIL;
}
+static unsigned int
+nfsd4_ace_mask(int minorversion)
+{
+ return minorversion == 0 ? NFS40_ACE_MASK_ALL : NFS4_ACE_MASK_ALL;
+}
+
+static __be32
+nfsd4_decode_acl_entries(struct nfsd4_compoundargs *argp, struct richacl **acl,
+ unsigned short flags_mask, unsigned int ace_mask,
+ int *plen)
+{
+ struct richace *ace;
+ u32 dummy32;
+ char *buf;
+ int len = 0;
+
+ DECODE_HEAD;
+
+ flags_mask &= RICHACE_VALID_FLAGS & ~RICHACE_SPECIAL_WHO;
+
+ READ_BUF(4); len += 4;
+ dummy32 = be32_to_cpup(p++);
+
+ if (dummy32 > NFSD4_ACL_MAX)
+ return nfserr_fbig;
+
+ *acl = svcxdr_alloc_richacl(argp, dummy32);
+ if (*acl == NULL)
+ return nfserr_jukebox;
+
+ richacl_for_each_entry(ace, *acl) {
+ READ_BUF(16); len += 16;
+
+ 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 & ~flags_mask)
+ return nfserr_inval;
+ ace->e_flags = dummy32;
+
+ dummy32 = be32_to_cpup(p++);
+ if (dummy32 & ~ace_mask)
+ return nfserr_inval;
+ ace->e_mask = dummy32;
+
+ dummy32 = be32_to_cpup(p++);
+ READ_BUF(dummy32);
+ len += XDR_QUADLEN(dummy32) << 2;
+ READMEM(buf, dummy32);
+ status = nfsd4_decode_ace_who(ace, argp->rqstp,
+ buf, dummy32);
+ if (status)
+ return status;
+ }
+ *plen += len;
+
+ DECODE_TAIL;
+}
+
static __be32
nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
struct iattr *iattr, struct richacl **acl,
@@ -312,6 +374,7 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
DECODE_HEAD;
iattr->ia_valid = 0;
+ *acl = NULL;
if ((status = nfsd4_decode_bitmap(argp, bmval)))
return status;
@@ -325,50 +388,18 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
iattr->ia_valid |= ATTR_SIZE;
}
if (bmval[0] & FATTR4_WORD0_ACL) {
- u32 nace;
- struct richace *ace;
-
- READ_BUF(4); len += 4;
- nace = be32_to_cpup(p++);
-
- if (nace > NFSD4_ACL_MAX)
- return nfserr_fbig;
+ if (bmval[1] & FATTR4_WORD1_DACL)
+ return nfserr_inval;
- *acl = svcxdr_alloc_richacl(argp, nace);
- if (*acl == NULL)
+ status = nfsd4_decode_acl_entries(argp, acl,
+ ~NFS4_ACE_INHERITED_ACE,
+ nfsd4_ace_mask(argp->minorversion),
+ &len);
+ if (status)
+ return status;
+ else if (*acl == NULL)
return nfserr_jukebox;
-
- richacl_for_each_entry(ace, *acl) {
- READ_BUF(16); len += 16;
-
- 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;
- READMEM(buf, dummy32);
- status = nfsd4_decode_ace_who(ace, argp->rqstp,
- buf, dummy32);
- if (status)
- return status;
- }
- } else
- *acl = NULL;
+ }
if (bmval[1] & FATTR4_WORD1_MODE) {
READ_BUF(4);
len += 4;
@@ -436,6 +467,22 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
goto xdr_error;
}
}
+ if (bmval[1] & FATTR4_WORD1_DACL) {
+ READ_BUF(4);
+ len += 4;
+ dummy32 = be32_to_cpup(p++);
+ if (dummy32 & (~RICHACL_VALID_FLAGS | RICHACL_MASKED))
+ return nfserr_inval;
+ status = nfsd4_decode_acl_entries(argp, acl,
+ ~0,
+ nfsd4_ace_mask(argp->minorversion),
+ &len);
+ if (status)
+ return status;
+ else if (*acl == NULL)
+ return nfserr_jukebox;
+ (*acl)->a_flags = dummy32;
+ }
label->len = 0;
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
@@ -2272,6 +2319,42 @@ out_resource:
return nfserr_resource;
}
+static __be32 nfsd4_encode_acl_entries(struct xdr_stream *xdr,
+ struct richacl *acl, struct svc_rqst *rqstp,
+ unsigned short flags_mask, unsigned int ace_mask)
+{
+ __be32 *p;
+
+ flags_mask &= ~RICHACE_SPECIAL_WHO;
+
+ p = xdr_reserve_space(xdr, 4);
+ if (!p)
+ return nfserr_resource;
+
+ if (acl == NULL) {
+ *p++ = cpu_to_be32(0);
+ } else {
+ struct richace *ace;
+
+ *p++ = cpu_to_be32(acl->a_count);
+
+ richacl_for_each_entry(ace, acl) {
+ __be32 status;
+
+ p = xdr_reserve_space(xdr, 4*3);
+ if (!p)
+ return nfserr_resource;
+ *p++ = cpu_to_be32(ace->e_type);
+ *p++ = cpu_to_be32(ace->e_flags & flags_mask);
+ *p++ = cpu_to_be32(ace->e_mask & ace_mask);
+ status = nfsd4_encode_ace_who(xdr, rqstp, ace);
+ if (status)
+ return status;
+ }
+ }
+ return 0;
+}
+
/*
* Note: @fhp can be NULL; in this case, we might have to compose the filehandle
* ourselves.
@@ -2342,15 +2425,16 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
goto out;
fhp = tempfh;
}
- if (bmval0 & FATTR4_WORD0_ACL) {
+ if ((bmval0 & FATTR4_WORD0_ACL) || (bmval1 & FATTR4_WORD1_DACL)) {
acl = nfsd4_get_acl(rqstp, dentry);
if (IS_ERR(acl)) {
err = PTR_ERR(acl);
acl = NULL;
}
- if (err == -EOPNOTSUPP)
+ if (err == -EOPNOTSUPP) {
bmval0 &= ~FATTR4_WORD0_ACL;
- else if (err == -EINVAL) {
+ bmval1 &= ~FATTR4_WORD1_DACL;
+ } else if (err == -EINVAL) {
status = nfserr_attrnotsupp;
goto out;
} else if (err != 0)
@@ -2389,6 +2473,8 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
if (!IS_ACL(d_inode(dentry)))
word0 &= ~FATTR4_WORD0_ACL;
+ if (!IS_RICHACL(d_inode(dentry)))
+ word1 &= ~FATTR4_WORD1_DACL;
if (!contextsupport)
word2 &= ~FATTR4_WORD2_SECURITY_LABEL;
if (!word2) {
@@ -2502,35 +2588,12 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
*p++ = cpu_to_be32(rdattr_err);
}
if (bmval0 & FATTR4_WORD0_ACL) {
- struct richace *ace;
-
- if (acl == NULL) {
- p = xdr_reserve_space(xdr, 4);
- if (!p)
- goto out_resource;
-
- *p++ = cpu_to_be32(0);
- goto out_acl;
- }
- p = xdr_reserve_space(xdr, 4);
- if (!p)
- goto out_resource;
- *p++ = cpu_to_be32(acl->a_count);
-
- richacl_for_each_entry(ace, acl) {
- p = xdr_reserve_space(xdr, 4*3);
- if (!p)
- goto out_resource;
- *p++ = cpu_to_be32(ace->e_type);
- *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)
- goto out;
- }
+ status = nfsd4_encode_acl_entries(xdr, acl, rqstp,
+ ~NFS4_ACE_INHERITED_ACE,
+ nfsd4_ace_mask(minorversion));
+ if (status)
+ goto out;
}
-out_acl:
if (bmval0 & FATTR4_WORD0_ACLSUPPORT) {
p = xdr_reserve_space(xdr, 4);
if (!p)
@@ -2746,6 +2809,16 @@ out_acl:
}
p = xdr_encode_hyper(p, ino);
}
+ if (bmval1 & FATTR4_WORD1_DACL) {
+ p = xdr_reserve_space(xdr, 4);
+ if (!p)
+ goto out_resource;
+ *p++ = cpu_to_be32(acl->a_flags);
+ status = nfsd4_encode_acl_entries(xdr, acl, rqstp,
+ ~0, nfsd4_ace_mask(minorversion));
+ if (status)
+ goto out;
+ }
#ifdef CONFIG_NFSD_PNFS
if (bmval1 & FATTR4_WORD1_FS_LAYOUT_TYPES) {
status = nfsd4_encode_layout_type(xdr, exp->ex_layout_type);
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
index cf98052..cb5c3ed 100644
--- a/fs/nfsd/nfsd.h
+++ b/fs/nfsd/nfsd.h
@@ -339,7 +339,8 @@ void nfsd_lockd_shutdown(void);
NFSD4_SUPPORTED_ATTRS_WORD0
#define NFSD4_1_SUPPORTED_ATTRS_WORD1 \
- (NFSD4_SUPPORTED_ATTRS_WORD1 | PNFSD_SUPPORTED_ATTRS_WORD1)
+ (NFSD4_SUPPORTED_ATTRS_WORD1 | PNFSD_SUPPORTED_ATTRS_WORD1 | \
+ FATTR4_WORD1_DACL)
#define NFSD4_1_SUPPORTED_ATTRS_WORD2 \
(NFSD4_SUPPORTED_ATTRS_WORD2 | PNFSD_SUPPORTED_ATTRS_WORD2 | \
@@ -386,7 +387,8 @@ static inline u32 nfsd_suppattrs2(u32 minorversion)
(FATTR4_WORD0_SIZE | FATTR4_WORD0_ACL)
#define NFSD_WRITEABLE_ATTRS_WORD1 \
(FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \
- | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET)
+ | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET \
+ | FATTR4_WORD1_DACL)
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
#define NFSD_WRITEABLE_ATTRS_WORD2 FATTR4_WORD2_SECURITY_LABEL
#else
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 1422fc6..682ced3 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -394,6 +394,7 @@ enum lock_type4 {
#define FATTR4_WORD1_TIME_MODIFY (1UL << 21)
#define FATTR4_WORD1_TIME_MODIFY_SET (1UL << 22)
#define FATTR4_WORD1_MOUNTED_ON_FILEID (1UL << 23)
+#define FATTR4_WORD1_DACL (1UL << 26)
#define FATTR4_WORD1_FS_LAYOUT_TYPES (1UL << 30)
#define FATTR4_WORD2_LAYOUT_TYPES (1UL << 0)
#define FATTR4_WORD2_LAYOUT_BLKSIZE (1UL << 1)
diff --git a/include/uapi/linux/nfs4.h b/include/uapi/linux/nfs4.h
index 2b871e0..b850ffd 100644
--- a/include/uapi/linux/nfs4.h
+++ b/include/uapi/linux/nfs4.h
@@ -121,7 +121,8 @@
#define NFS4_ACE_GENERIC_READ 0x00120081
#define NFS4_ACE_GENERIC_WRITE 0x00160106
#define NFS4_ACE_GENERIC_EXECUTE 0x001200A0
-#define NFS4_ACE_MASK_ALL 0x001F01FF
+#define NFS40_ACE_MASK_ALL 0x001F01FF
+#define NFS4_ACE_MASK_ALL 0x001F07FF
#define EXCHGID4_FLAG_SUPP_MOVED_REFER 0x00000001
#define EXCHGID4_FLAG_SUPP_MOVED_MIGR 0x00000002
--
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]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-03 16:30 +0100 |
| Subject | [PATCH v13 32/51] richacl: Set the other permissions to the other mask |
| Message-ID | <qqLH5-4sG-41@gated-at.bofh.it> |
| In reply to | #1261574 |
Change the acl so that everyone@ is granted the permissions set in the
other mask.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Reviewed-by: J. Bruce Fields <bfields@redhat.com>
---
fs/richacl_compat.c | 41 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 41 insertions(+)
diff --git a/fs/richacl_compat.c b/fs/richacl_compat.c
index d9fee8b..76183c9 100644
--- a/fs/richacl_compat.c
+++ b/fs/richacl_compat.c
@@ -462,3 +462,44 @@ richacl_set_owner_permissions(struct richacl_alloc *alloc)
}
return 0;
}
+
+/**
+ * richacl_set_other_permissions - set the other permissions to the other mask
+ * @alloc: acl and number of allocated entries
+ * @added: permissions added for everyone@
+ *
+ * Change the acl so that everyone@ is granted the permissions set in the other
+ * mask. This leaves at most one efective everyone@ allow entry at the end of
+ * the acl. If everyone@ end up being granted additional permissions, these
+ * permissions are returned in @added.
+ */
+static int
+richacl_set_other_permissions(struct richacl_alloc *alloc, unsigned int *added)
+{
+ struct richacl *acl = alloc->acl;
+ unsigned int x = RICHACE_POSIX_ALWAYS_ALLOWED;
+ unsigned int other_mask = acl->a_other_mask & ~x;
+ struct richace *ace;
+
+ if (!(other_mask &&
+ (acl->a_flags & RICHACL_WRITE_THROUGH)))
+ return 0;
+
+ *added = other_mask;
+ ace = acl->a_entries + acl->a_count - 1;
+ if (acl->a_count == 0 ||
+ !richace_is_everyone(ace) ||
+ richace_is_inherit_only(ace)) {
+ ace++;
+ if (richacl_insert_entry(alloc, &ace))
+ return -1;
+ ace->e_type = RICHACE_ACCESS_ALLOWED_ACE_TYPE;
+ ace->e_flags = RICHACE_SPECIAL_WHO;
+ ace->e_mask = other_mask;
+ ace->e_id.special = RICHACE_EVERYONE_SPECIAL_ID;
+ } else {
+ *added &= ~ace->e_mask;
+ richace_change_mask(alloc, &ace, other_mask);
+ }
+ return 0;
+}
--
2.5.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-03 16:30 +0100 |
| Subject | [PATCH v13 33/51] richacl: Isolate the owner and group classes |
| Message-ID | <qqLH5-4sG-43@gated-at.bofh.it> |
| In reply to | #1261574 |
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 76183c9..7553f1a 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]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-03 16:30 +0100 |
| Subject | [PATCH v13 28/51] richacl: acl editing helper functions |
| Message-ID | <qqLH5-4sG-35@gated-at.bofh.it> |
| In reply to | #1261574 |
The file masks in richacls make chmod and creating new files more
efficient than having to apply file permission bits to the acl directly.
They also allow us to regain permissions from an acl even after a
restrictive chmod, because the permissions in the acl itself are not
being destroyed. In POSIX ACLs, the mask entry has a similar function.
Protocols like nfsv4 do not understand file masks. For those protocols,
we need to compute nfs4 acls which represent the effective permissions
granted by a richacl: we need to "apply" the file masks to the acl.
This is the first in a series of richacl transformation patches; it
implements basic richacl editing functions. The following patches
implement algorithms for transforming a richacl so that it can be
evaluated as a plain nfs4 acl, with identical permission check results.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Reviewed-by: J. Bruce Fields <bfields@redhat.com>
---
fs/Makefile | 3 +-
fs/richacl_compat.c | 155 +++++++++++++++++++++++++++++++++++++++++
include/linux/richacl_compat.h | 40 +++++++++++
3 files changed, 197 insertions(+), 1 deletion(-)
create mode 100644 fs/richacl_compat.c
create mode 100644 include/linux/richacl_compat.h
diff --git a/fs/Makefile b/fs/Makefile
index 35e640d..32b391b 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -49,7 +49,8 @@ obj-$(CONFIG_SYSCTL) += drop_caches.o
obj-$(CONFIG_FHANDLE) += fhandle.o
obj-$(CONFIG_FS_RICHACL) += richacl.o
-richacl-y := richacl_base.o richacl_inode.o richacl_xattr.o
+richacl-y := richacl_base.o richacl_inode.o \
+ richacl_xattr.o richacl_compat.o
obj-y += quota/
diff --git a/fs/richacl_compat.c b/fs/richacl_compat.c
new file mode 100644
index 0000000..5c59999
--- /dev/null
+++ b/fs/richacl_compat.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2006, 2010 Novell, Inc.
+ * Copyright (C) 2015 Red Hat, Inc.
+ * Written by Andreas Gruenbacher <agruenba@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/richacl_compat.h>
+
+/**
+ * richacl_prepare - allocate richacl being constructed
+ *
+ * Allocate a richacl which can hold @count entries but which is initially
+ * empty.
+ */
+struct richacl *richacl_prepare(struct richacl_alloc *alloc, unsigned int count)
+{
+ alloc->acl = richacl_alloc(count, GFP_KERNEL);
+ if (!alloc->acl)
+ return NULL;
+ alloc->acl->a_count = 0;
+ alloc->count = count;
+ return alloc->acl;
+}
+EXPORT_SYMBOL_GPL(richacl_prepare);
+
+/**
+ * richacl_delete_entry - delete an entry in an acl
+ * @alloc: acl and number of allocated entries
+ * @ace: an entry in @alloc->acl
+ *
+ * Updates @ace so that it points to the entry before the deleted entry
+ * on return. (When deleting the first entry, @ace will point to the
+ * (non-existent) entry before the first entry). This behavior is the
+ * expected behavior when deleting entries while forward iterating over
+ * an acl.
+ */
+void
+richacl_delete_entry(struct richacl_alloc *alloc, struct richace **ace)
+{
+ void *end = alloc->acl->a_entries + alloc->acl->a_count;
+
+ memmove(*ace, *ace + 1, end - (void *)(*ace + 1));
+ (*ace)--;
+ alloc->acl->a_count--;
+}
+EXPORT_SYMBOL_GPL(richacl_delete_entry);
+
+/**
+ * richacl_insert_entry - insert an entry in an acl
+ * @alloc: acl and number of allocated entries
+ * @ace: entry before which the new entry shall be inserted
+ *
+ * Insert a new entry in @alloc->acl at position @ace and zero-initialize
+ * it. This may require reallocating @alloc->acl.
+ */
+int
+richacl_insert_entry(struct richacl_alloc *alloc, struct richace **ace)
+{
+ struct richacl *acl = alloc->acl;
+ unsigned int index = *ace - acl->a_entries;
+ size_t tail_size = (acl->a_count - index) * sizeof(struct richace);
+
+ if (alloc->count == acl->a_count) {
+ size_t new_size = sizeof(struct richacl) +
+ (acl->a_count + 1) * sizeof(struct richace);
+
+ acl = krealloc(acl, new_size, GFP_KERNEL);
+ if (!acl)
+ return -1;
+ *ace = acl->a_entries + index;
+ alloc->acl = acl;
+ alloc->count++;
+ }
+
+ memmove(*ace + 1, *ace, tail_size);
+ memset(*ace, 0, sizeof(**ace));
+ acl->a_count++;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(richacl_insert_entry);
+
+/**
+ * richacl_append_entry - append an entry to an acl
+ * @alloc: acl and number of allocated entries
+ *
+ * This may require reallocating @alloc->acl.
+ */
+struct richace *richacl_append_entry(struct richacl_alloc *alloc)
+{
+ struct richacl *acl = alloc->acl;
+ struct richace *ace = acl->a_entries + acl->a_count;
+
+ if (alloc->count > alloc->acl->a_count) {
+ acl->a_count++;
+ return ace;
+ }
+ return richacl_insert_entry(alloc, &ace) ? NULL : ace;
+}
+EXPORT_SYMBOL_GPL(richacl_append_entry);
+
+/**
+ * richace_change_mask - set the mask of @ace to @mask
+ * @alloc: acl and number of allocated entries
+ * @ace: entry to modify
+ * @mask: new mask for @ace
+ *
+ * If @ace is inheritable, a inherit-only ace is inserted before @ace which
+ * includes the inheritable permissions of @ace and the inheritance flags of
+ * @ace are cleared before changing the mask.
+ *
+ * If @mask is 0, the original ace is turned into an inherit-only entry if
+ * there are any inheritable permissions, and removed otherwise.
+ *
+ * The returned @ace points to the modified or inserted effective-only acl
+ * entry if that entry exists, to the entry that has become inheritable-only,
+ * or else to the previous entry in the acl.
+ */
+static int
+richace_change_mask(struct richacl_alloc *alloc, struct richace **ace,
+ unsigned int mask)
+{
+ if (mask && (*ace)->e_mask == mask)
+ (*ace)->e_flags &= ~RICHACE_INHERIT_ONLY_ACE;
+ else if (mask & ~RICHACE_POSIX_ALWAYS_ALLOWED) {
+ if (richace_is_inheritable(*ace)) {
+ if (richacl_insert_entry(alloc, ace))
+ return -1;
+ richace_copy(*ace, *ace + 1);
+ (*ace)->e_flags |= RICHACE_INHERIT_ONLY_ACE;
+ (*ace)++;
+ (*ace)->e_flags &= ~RICHACE_INHERITANCE_FLAGS |
+ RICHACE_INHERITED_ACE;
+ }
+ (*ace)->e_mask = mask;
+ } else {
+ if (richace_is_inheritable(*ace))
+ (*ace)->e_flags |= RICHACE_INHERIT_ONLY_ACE;
+ else
+ richacl_delete_entry(alloc, ace);
+ }
+ return 0;
+}
diff --git a/include/linux/richacl_compat.h b/include/linux/richacl_compat.h
new file mode 100644
index 0000000..a9ff630
--- /dev/null
+++ b/include/linux/richacl_compat.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc.
+ * Written by Andreas Gruenbacher <agruenba@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __RICHACL_COMPAT_H
+#define __RICHACL_COMPAT_H
+
+#include <linux/richacl.h>
+
+/**
+ * struct richacl_alloc - remember how many entries are actually allocated
+ * @acl: acl with a_count <= @count
+ * @count: the actual number of entries allocated in @acl
+ *
+ * We pass around this structure while modifying an acl so that we do
+ * not have to reallocate when we remove existing entries followed by
+ * adding new entries.
+ */
+struct richacl_alloc {
+ struct richacl *acl;
+ unsigned int count;
+};
+
+struct richacl *richacl_prepare(struct richacl_alloc *, unsigned int);
+struct richace *richacl_append_entry(struct richacl_alloc *);
+int richacl_insert_entry(struct richacl_alloc *, struct richace **);
+void richacl_delete_entry(struct richacl_alloc *, struct richace **);
+
+#endif /* __RICHACL_COMPAT_H */
--
2.5.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-03 16:30 +0100 |
| Subject | [PATCH v13 47/51] nfs: Fix GETATTR bitmap verification |
| Message-ID | <qqLH5-4sG-45@gated-at.bofh.it> |
| In reply to | #1261574 |
When decoding GETATTR replies, the client checks the attribute bitmap for which attributes the server has sent. It misses bits at the word boundaries, though; fix that. Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com> --- fs/nfs/nfs4xdr.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 788adf3..6f6d921 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -4375,6 +4375,11 @@ static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat) goto xdr_error; if ((status = decode_attr_files_total(xdr, bitmap, &fsstat->tfiles)) != 0) goto xdr_error; + + status = -EIO; + if (unlikely(bitmap[0])) + goto xdr_error; + if ((status = decode_attr_space_avail(xdr, bitmap, &fsstat->abytes)) != 0) goto xdr_error; if ((status = decode_attr_space_free(xdr, bitmap, &fsstat->fbytes)) != 0) @@ -4574,6 +4579,10 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap, goto xdr_error; fattr->valid |= status; + status = -EIO; + if (unlikely(bitmap[0])) + goto xdr_error; + status = decode_attr_mode(xdr, bitmap, &fmode); if (status < 0) goto xdr_error; @@ -4627,6 +4636,10 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap, goto xdr_error; fattr->valid |= status; + status = -EIO; + if (unlikely(bitmap[1])) + goto xdr_error; + status = decode_attr_mdsthreshold(xdr, bitmap, fattr->mdsthreshold); if (status < 0) goto xdr_error; @@ -4789,12 +4802,22 @@ static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo) if ((status = decode_attr_maxwrite(xdr, bitmap, &fsinfo->wtmax)) != 0) goto xdr_error; fsinfo->wtpref = fsinfo->wtmax; + + status = -EIO; + if (unlikely(bitmap[0])) + goto xdr_error; + status = decode_attr_time_delta(xdr, bitmap, &fsinfo->time_delta); if (status != 0) goto xdr_error; status = decode_attr_pnfstype(xdr, bitmap, &fsinfo->layouttype); if (status != 0) goto xdr_error; + + status = -EIO; + if (unlikely(bitmap[1])) + goto xdr_error; + status = decode_attr_layout_blksize(xdr, bitmap, &fsinfo->blksize); if (status) goto xdr_error; -- 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]
| From | Trond Myklebust <trond.myklebust@primarydata.com> |
|---|---|
| Date | 2015-11-03 17:40 +0100 |
| Subject | Re: [PATCH v13 47/51] nfs: Fix GETATTR bitmap verification |
| Message-ID | <qqMMO-5fY-7@gated-at.bofh.it> |
| In reply to | #1261609 |
On Tue, Nov 3, 2015 at 10:17 AM, Andreas Gruenbacher <agruenba@redhat.com> wrote: > When decoding GETATTR replies, the client checks the attribute bitmap > for which attributes the server has sent. It misses bits at the word > boundaries, though; fix that. > > Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com> > --- > fs/nfs/nfs4xdr.c | 23 +++++++++++++++++++++++ > 1 file changed, 23 insertions(+) > > diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c > index 788adf3..6f6d921 100644 > --- a/fs/nfs/nfs4xdr.c > +++ b/fs/nfs/nfs4xdr.c > @@ -4375,6 +4375,11 @@ static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat) > goto xdr_error; > if ((status = decode_attr_files_total(xdr, bitmap, &fsstat->tfiles)) != 0) > goto xdr_error; > + > + status = -EIO; > + if (unlikely(bitmap[0])) > + goto xdr_error; > + > if ((status = decode_attr_space_avail(xdr, bitmap, &fsstat->abytes)) != 0) > goto xdr_error; > if ((status = decode_attr_space_free(xdr, bitmap, &fsstat->fbytes)) != 0) > @@ -4574,6 +4579,10 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap, > goto xdr_error; > fattr->valid |= status; > > + status = -EIO; > + if (unlikely(bitmap[0])) > + goto xdr_error; > + > status = decode_attr_mode(xdr, bitmap, &fmode); > if (status < 0) > goto xdr_error; > @@ -4627,6 +4636,10 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap, > goto xdr_error; > fattr->valid |= status; > > + status = -EIO; > + if (unlikely(bitmap[1])) > + goto xdr_error; > + > status = decode_attr_mdsthreshold(xdr, bitmap, fattr->mdsthreshold); > if (status < 0) > goto xdr_error; > @@ -4789,12 +4802,22 @@ static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo) > if ((status = decode_attr_maxwrite(xdr, bitmap, &fsinfo->wtmax)) != 0) > goto xdr_error; > fsinfo->wtpref = fsinfo->wtmax; > + > + status = -EIO; > + if (unlikely(bitmap[0])) > + goto xdr_error; > + > status = decode_attr_time_delta(xdr, bitmap, &fsinfo->time_delta); > if (status != 0) > goto xdr_error; > status = decode_attr_pnfstype(xdr, bitmap, &fsinfo->layouttype); > if (status != 0) > goto xdr_error; > + > + status = -EIO; > + if (unlikely(bitmap[1])) > + goto xdr_error; > + > status = decode_attr_layout_blksize(xdr, bitmap, &fsinfo->blksize); > if (status) > goto xdr_error; > -- > 2.5.0 This patch can and should be merged separately from this patchset. Please submit it through the usual channels. Trond -- 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]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-03 16:30 +0100 |
| Subject | [PATCH v13 42/51] nfsd: Add support for unmapped richace identifiers |
| Message-ID | <qqLH5-4sG-51@gated-at.bofh.it> |
| In reply to | #1261574 |
Add support for encoding unmapped identifiers in richacl entries: local
filesystems are not usually supposed to store unmapped identifiers, but
allowing that for debugging purposes can be useful; for that, nfsd must
also be able to encode them.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
fs/nfsd/acl.h | 2 +-
fs/nfsd/nfs4acl.c | 17 +++++++++++------
fs/nfsd/nfs4xdr.c | 4 ++--
3 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/fs/nfsd/acl.h b/fs/nfsd/acl.h
index d73c664..4935144 100644
--- a/fs/nfsd/acl.h
+++ b/fs/nfsd/acl.h
@@ -51,7 +51,7 @@ struct svc_rqst;
__be32 nfsd4_decode_ace_who(struct richace *ace, struct svc_rqst *rqstp,
char *who, u32 len);
__be32 nfsd4_encode_ace_who(struct xdr_stream *xdr, struct svc_rqst *rqstp,
- struct richace *ace);
+ struct richace *ace, struct richacl *acl);
struct richacl *nfsd4_get_acl(struct svc_rqst *rqstp, struct dentry *dentry);
__be32 nfsd4_set_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c
index f017a76..3cc83fd 100644
--- a/fs/nfsd/nfs4acl.c
+++ b/fs/nfsd/nfs4acl.c
@@ -885,17 +885,22 @@ __be32 nfsd4_decode_ace_who(struct richace *ace, struct svc_rqst *rqstp,
}
__be32 nfsd4_encode_ace_who(struct xdr_stream *xdr, struct svc_rqst *rqstp,
- struct richace *ace)
+ struct richace *ace, struct richacl *acl)
{
- if (ace->e_flags & RICHACE_SPECIAL_WHO) {
- unsigned int special_id = ace->e_id.special;
+ if (ace->e_flags & (RICHACE_SPECIAL_WHO | RICHACE_UNMAPPED_WHO)) {
const char *who;
unsigned int len;
__be32 *p;
- if (!nfs4acl_special_id_to_who(special_id, &who, &len)) {
- WARN_ON_ONCE(1);
- return nfserr_serverfault;
+ if (ace->e_flags & RICHACE_SPECIAL_WHO) {
+ if (!nfs4acl_special_id_to_who(ace->e_id.special,
+ &who, &len)) {
+ WARN_ON_ONCE(1);
+ return nfserr_serverfault;
+ }
+ } else {
+ who = richace_unmapped_identifier(ace, acl);
+ len = strlen(who);
}
p = xdr_reserve_space(xdr, len + 4);
if (!p)
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 33d028c..8728d0e 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -2325,7 +2325,7 @@ static __be32 nfsd4_encode_acl_entries(struct xdr_stream *xdr,
{
__be32 *p;
- flags_mask &= ~RICHACE_SPECIAL_WHO;
+ flags_mask &= ~(RICHACE_SPECIAL_WHO | RICHACE_UNMAPPED_WHO);
p = xdr_reserve_space(xdr, 4);
if (!p)
@@ -2347,7 +2347,7 @@ static __be32 nfsd4_encode_acl_entries(struct xdr_stream *xdr,
*p++ = cpu_to_be32(ace->e_type);
*p++ = cpu_to_be32(ace->e_flags & flags_mask);
*p++ = cpu_to_be32(ace->e_mask & ace_mask);
- status = nfsd4_encode_ace_who(xdr, rqstp, ace);
+ status = nfsd4_encode_ace_who(xdr, rqstp, ace, acl);
if (status)
return status;
}
--
2.5.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-03 16:30 +0100 |
| Subject | [PATCH v13 19/51] vfs: Add richacl permission checking |
| Message-ID | <qqLH5-4sG-53@gated-at.bofh.it> |
| In reply to | #1261574 |
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]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-03 16:30 +0100 |
| Subject | [PATCH v13 25/51] xfs: Add richacl support |
| Message-ID | <qqLH5-4sG-55@gated-at.bofh.it> |
| In reply to | #1261574 |
The richacl feature flag (mkfs.xfs -m richacl=1) determines whether an xfs
filesystem supports posix acls or richacls. Richacls are stored in
"system.richacl" xattrs.
On the grounds that richacls add relatively little overhead compared to the
size of xfs itself, to keep the testing matrix small, and because xfs users
are highly likely to enable richacls anyway, richacl support cannot be
compiled out in xfs.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
fs/xfs/Kconfig | 1 +
fs/xfs/Makefile | 1 +
fs/xfs/libxfs/xfs_format.h | 11 ++++-
fs/xfs/xfs_iops.c | 44 +++++++++++++++----
fs/xfs/xfs_richacl.c | 103 +++++++++++++++++++++++++++++++++++++++++++++
fs/xfs/xfs_richacl.h | 23 ++++++++++
fs/xfs/xfs_super.c | 6 ++-
fs/xfs/xfs_super.h | 4 ++
fs/xfs/xfs_xattr.c | 43 ++++++++++++++++---
9 files changed, 218 insertions(+), 18 deletions(-)
create mode 100644 fs/xfs/xfs_richacl.c
create mode 100644 fs/xfs/xfs_richacl.h
diff --git a/fs/xfs/Kconfig b/fs/xfs/Kconfig
index 5d47b4d..3fd00f8 100644
--- a/fs/xfs/Kconfig
+++ b/fs/xfs/Kconfig
@@ -4,6 +4,7 @@ config XFS_FS
depends on (64BIT || LBDAF)
select EXPORTFS
select LIBCRC32C
+ select FS_RICHACL
help
XFS is a high performance journaling filesystem which originated
on the SGI IRIX platform. It is completely multi-threaded, can
diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
index a096841..1e6b984 100644
--- a/fs/xfs/Makefile
+++ b/fs/xfs/Makefile
@@ -84,6 +84,7 @@ xfs-y += xfs_aops.o \
xfs_message.o \
xfs_mount.o \
xfs_mru_cache.o \
+ xfs_richacl.o \
xfs_super.o \
xfs_symlink.o \
xfs_sysfs.o \
diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index 9590a06..923247c 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -461,10 +461,13 @@ xfs_sb_has_ro_compat_feature(
#define XFS_SB_FEAT_INCOMPAT_FTYPE (1 << 0) /* filetype in dirent */
#define XFS_SB_FEAT_INCOMPAT_SPINODES (1 << 1) /* sparse inode chunks */
#define XFS_SB_FEAT_INCOMPAT_META_UUID (1 << 2) /* metadata UUID */
+#define XFS_SB_FEAT_INCOMPAT_RICHACL (1 << 3) /* richacls */
+
#define XFS_SB_FEAT_INCOMPAT_ALL \
(XFS_SB_FEAT_INCOMPAT_FTYPE| \
XFS_SB_FEAT_INCOMPAT_SPINODES| \
- XFS_SB_FEAT_INCOMPAT_META_UUID)
+ XFS_SB_FEAT_INCOMPAT_META_UUID| \
+ XFS_SB_FEAT_INCOMPAT_RICHACL)
#define XFS_SB_FEAT_INCOMPAT_UNKNOWN ~XFS_SB_FEAT_INCOMPAT_ALL
static inline bool
@@ -530,6 +533,12 @@ static inline bool xfs_sb_version_hasmetauuid(struct xfs_sb *sbp)
(sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_META_UUID);
}
+static inline bool xfs_sb_version_hasrichacl(struct xfs_sb *sbp)
+{
+ return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) &&
+ (sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_RICHACL);
+}
+
/*
* end of superblock version macros
*/
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index 8294132..9e4103b 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -27,6 +27,7 @@
#include "xfs_bmap.h"
#include "xfs_bmap_util.h"
#include "xfs_acl.h"
+#include "xfs_richacl.h"
#include "xfs_quota.h"
#include "xfs_error.h"
#include "xfs_attr.h"
@@ -42,6 +43,7 @@
#include <linux/capability.h>
#include <linux/xattr.h>
#include <linux/posix_acl.h>
+#include <linux/richacl.h>
#include <linux/security.h>
#include <linux/fiemap.h>
#include <linux/slab.h>
@@ -133,7 +135,8 @@ xfs_generic_create(
{
struct inode *inode;
struct xfs_inode *ip = NULL;
- struct posix_acl *default_acl, *acl;
+ struct posix_acl *default_acl = NULL, *acl = NULL;
+ struct richacl *richacl = NULL;
struct xfs_name name;
int error;
@@ -149,9 +152,15 @@ xfs_generic_create(
rdev = 0;
}
- error = posix_acl_create(dir, &mode, &default_acl, &acl);
- if (error)
- return error;
+ if (IS_RICHACL(dir)) {
+ richacl = richacl_create(&mode, dir);
+ if (IS_ERR(richacl))
+ return PTR_ERR(richacl);
+ } else {
+ error = posix_acl_create(dir, &mode, &default_acl, &acl);
+ if (error)
+ return error;
+ }
if (!tmpfile) {
xfs_dentry_to_name(&name, dentry, mode);
@@ -180,6 +189,11 @@ xfs_generic_create(
goto out_cleanup_inode;
}
#endif
+ if (richacl) {
+ error = xfs_set_richacl(inode, richacl);
+ if (error)
+ goto out_cleanup_inode;
+ }
if (tmpfile)
d_tmpfile(dentry, inode);
@@ -189,10 +203,9 @@ xfs_generic_create(
xfs_finish_inode_setup(ip);
out_free_acl:
- if (default_acl)
- posix_acl_release(default_acl);
- if (acl)
- posix_acl_release(acl);
+ posix_acl_release(default_acl);
+ posix_acl_release(acl);
+ richacl_put(richacl);
return error;
out_cleanup_inode:
@@ -534,6 +547,13 @@ xfs_setattr_time(
}
}
+static inline int
+xfs_acl_chmod(struct inode *inode, umode_t mode)
+{
+ if (IS_RICHACL(inode))
+ return richacl_chmod(inode, inode->i_mode);
+ return posix_acl_chmod(inode, inode->i_mode);
+}
int
xfs_setattr_nonsize(
struct xfs_inode *ip,
@@ -722,7 +742,7 @@ xfs_setattr_nonsize(
* Posix ACL code seems to care about this issue either.
*/
if ((mask & ATTR_MODE) && !(flags & XFS_ATTR_NOACL)) {
- error = posix_acl_chmod(inode, inode->i_mode);
+ error = xfs_acl_chmod(inode, inode->i_mode);
if (error)
return error;
}
@@ -1104,6 +1124,8 @@ xfs_vn_tmpfile(
static const struct inode_operations xfs_inode_operations = {
.get_acl = xfs_get_acl,
.set_acl = xfs_set_acl,
+ .get_richacl = xfs_get_richacl,
+ .set_richacl = xfs_set_richacl,
.getattr = xfs_vn_getattr,
.setattr = xfs_vn_setattr,
.setxattr = generic_setxattr,
@@ -1132,6 +1154,8 @@ static const struct inode_operations xfs_dir_inode_operations = {
.rename2 = xfs_vn_rename,
.get_acl = xfs_get_acl,
.set_acl = xfs_set_acl,
+ .get_richacl = xfs_get_richacl,
+ .set_richacl = xfs_set_richacl,
.getattr = xfs_vn_getattr,
.setattr = xfs_vn_setattr,
.setxattr = generic_setxattr,
@@ -1160,6 +1184,8 @@ static const struct inode_operations xfs_dir_ci_inode_operations = {
.rename2 = xfs_vn_rename,
.get_acl = xfs_get_acl,
.set_acl = xfs_set_acl,
+ .get_richacl = xfs_get_richacl,
+ .set_richacl = xfs_set_richacl,
.getattr = xfs_vn_getattr,
.setattr = xfs_vn_setattr,
.setxattr = generic_setxattr,
diff --git a/fs/xfs/xfs_richacl.c b/fs/xfs/xfs_richacl.c
new file mode 100644
index 0000000..92a036e
--- /dev/null
+++ b/fs/xfs/xfs_richacl.c
@@ -0,0 +1,103 @@
+/*
+ * 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/xattr.h>
+#include <linux/richacl_xattr.h>
+
+struct richacl *
+xfs_get_richacl(struct inode *inode)
+{
+ struct xfs_inode *ip = XFS_I(inode);
+ struct richacl *acl = NULL;
+ int size = XATTR_SIZE_MAX;
+ void *value;
+ int error;
+
+ value = kmem_zalloc_large(size, KM_SLEEP);
+ if (!value)
+ return ERR_PTR(-ENOMEM);
+
+ error = xfs_attr_get(ip, XATTR_RICHACL, value, &size, ATTR_ROOT);
+ if (error) {
+ /*
+ * If the attribute doesn't exist make sure we have a negative
+ * cache entry, for any other error assume it is transient and
+ * leave the cache entry as ACL_NOT_CACHED.
+ */
+ if (error != -ENOATTR)
+ acl = ERR_PTR(error);
+ } else
+ acl = richacl_from_xattr(&init_user_ns, value, size);
+
+ if (!IS_ERR(acl))
+ set_cached_richacl(inode, acl);
+ kfree(value);
+
+ return acl;
+}
+
+static int
+xfs_remove_richacl(struct inode *inode)
+{
+ struct xfs_inode *ip = XFS_I(inode);
+ int error;
+
+ error = xfs_attr_remove(ip, XATTR_RICHACL, ATTR_ROOT);
+ if (error == -ENOATTR)
+ error = 0;
+ if (!error)
+ set_cached_richacl(inode, NULL);
+ return error;
+}
+
+int
+xfs_set_richacl(struct inode *inode, struct richacl *acl)
+{
+ struct xfs_inode *ip = XFS_I(inode);
+ umode_t mode = inode->i_mode;
+ int error, size;
+ void *value;
+
+ if (!acl)
+ return xfs_remove_richacl(inode);
+
+ if (richacl_equiv_mode(acl, &mode) == 0) {
+ xfs_set_mode(inode, mode);
+ return xfs_remove_richacl(inode);
+ }
+
+ size = richacl_xattr_size(acl);
+ value = kmem_zalloc_large(size, KM_SLEEP);
+ if (!value)
+ return -ENOMEM;
+ richacl_to_xattr(&init_user_ns, acl, value, size);
+ error = xfs_attr_set(ip, XATTR_RICHACL, value, size,
+ ATTR_ROOT);
+ kfree(value);
+ if (error)
+ return error;
+
+ mode &= ~S_IRWXUGO;
+ mode |= richacl_masks_to_mode(acl);
+ xfs_set_mode(inode, mode);
+ set_cached_richacl(inode, acl);
+
+ return 0;
+}
diff --git a/fs/xfs/xfs_richacl.h b/fs/xfs/xfs_richacl.h
new file mode 100644
index 0000000..431aa25
--- /dev/null
+++ b/fs/xfs/xfs_richacl.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc.
+ * Author: Andreas Gruenbacher <agruenba@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#ifndef __FS_XFS_RICHACL_H
+#define __FS_XFS_RICHACL_H
+
+struct richacl;
+
+extern struct richacl *xfs_get_richacl(struct inode *);
+extern int xfs_set_richacl(struct inode *, struct richacl *);
+
+#endif /* __FS_XFS_RICHACL_H */
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index 904f637..f82ce1a 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -1500,7 +1500,11 @@ xfs_fs_fill_super(
sb->s_maxbytes = xfs_max_file_offset(sb->s_blocksize_bits);
sb->s_max_links = XFS_MAXLINK;
sb->s_time_gran = 1;
- set_posix_acl_flag(sb);
+
+ if (xfs_sb_version_hasrichacl(&mp->m_sb))
+ set_richacl_flag(sb);
+ else
+ set_posix_acl_flag(sb);
/* version 5 superblocks support inode version counters. */
if (XFS_SB_VERSION_NUM(&mp->m_sb) == XFS_SB_VERSION_5)
diff --git a/fs/xfs/xfs_super.h b/fs/xfs/xfs_super.h
index 499058f..7ae21d9 100644
--- a/fs/xfs/xfs_super.h
+++ b/fs/xfs/xfs_super.h
@@ -36,6 +36,9 @@ extern void xfs_qm_exit(void);
# define set_posix_acl_flag(sb) do { } while (0)
#endif
+# define XFS_RICHACL_STRING "Richacls, "
+# define set_richacl_flag(sb) ((sb)->s_flags |= MS_RICHACL)
+
#define XFS_SECURITY_STRING "security attributes, "
#ifdef CONFIG_XFS_RT
@@ -52,6 +55,7 @@ extern void xfs_qm_exit(void);
#define XFS_VERSION_STRING "SGI XFS"
#define XFS_BUILD_OPTIONS XFS_ACL_STRING \
+ XFS_RICHACL_STRING \
XFS_SECURITY_STRING \
XFS_REALTIME_STRING \
XFS_DBG_STRING /* DBG must be last */
diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
index 8428aed..64aac05 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>
@@ -74,6 +75,24 @@ xfs_xattr_set(struct dentry *dentry, const char *name, const void *value,
(void *)value, size, xflags);
}
+static int
+xfs_xattr_get_trusted(struct dentry *dentry, const char *name,
+ void *value, size_t size, int xflags)
+{
+ if (strcmp(name, XATTR_RICHACL) == 0)
+ return -EOPNOTSUPP;
+ return xfs_xattr_get(dentry, name, value, size, xflags);
+}
+
+static int
+xfs_xattr_set_trusted(struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags, int xflags)
+{
+ if (strcmp(name, XATTR_RICHACL) == 0)
+ return -EOPNOTSUPP;
+ return xfs_xattr_set(dentry, name, value, size, flags, xflags);
+}
+
static const struct xattr_handler xfs_xattr_user_handler = {
.prefix = XATTR_USER_PREFIX,
.flags = 0, /* no flags implies user namespace */
@@ -84,8 +103,8 @@ static const struct xattr_handler xfs_xattr_user_handler = {
static const struct xattr_handler xfs_xattr_trusted_handler = {
.prefix = XATTR_TRUSTED_PREFIX,
.flags = ATTR_ROOT,
- .get = xfs_xattr_get,
- .set = xfs_xattr_set,
+ .get = xfs_xattr_get_trusted,
+ .set = xfs_xattr_set_trusted,
};
static const struct xattr_handler xfs_xattr_security_handler = {
@@ -103,6 +122,7 @@ const struct xattr_handler *xfs_xattr_handlers[] = {
&posix_acl_access_xattr_handler,
&posix_acl_default_xattr_handler,
#endif
+ &richacl_xattr_handler,
NULL
};
@@ -152,10 +172,10 @@ xfs_xattr_put_listent(
ASSERT(context->count >= 0);
if (flags & XFS_ATTR_ROOT) {
-#ifdef CONFIG_XFS_POSIX_ACL
if (namelen == SGI_ACL_FILE_SIZE &&
strncmp(name, SGI_ACL_FILE,
- SGI_ACL_FILE_SIZE) == 0) {
+ SGI_ACL_FILE_SIZE) == 0 &&
+ IS_POSIXACL(&context->dp->i_vnode)) {
int ret = __xfs_xattr_put_listent(
context, XATTR_SYSTEM_PREFIX,
XATTR_SYSTEM_PREFIX_LEN,
@@ -164,8 +184,9 @@ xfs_xattr_put_listent(
if (ret)
return ret;
} else if (namelen == SGI_ACL_DEFAULT_SIZE &&
- strncmp(name, SGI_ACL_DEFAULT,
- SGI_ACL_DEFAULT_SIZE) == 0) {
+ strncmp(name, SGI_ACL_DEFAULT,
+ SGI_ACL_DEFAULT_SIZE) == 0 &&
+ IS_POSIXACL(&context->dp->i_vnode)) {
int ret = __xfs_xattr_put_listent(
context, XATTR_SYSTEM_PREFIX,
XATTR_SYSTEM_PREFIX_LEN,
@@ -173,8 +194,16 @@ xfs_xattr_put_listent(
strlen(XATTR_POSIX_ACL_DEFAULT));
if (ret)
return ret;
+ } else if (namelen == strlen(XATTR_RICHACL) &&
+ strncmp(name, XATTR_RICHACL,
+ strlen(XATTR_RICHACL)) == 0 &&
+ IS_RICHACL(&context->dp->i_vnode)) {
+ return __xfs_xattr_put_listent(
+ context, XATTR_SYSTEM_PREFIX,
+ XATTR_SYSTEM_PREFIX_LEN,
+ XATTR_RICHACL,
+ strlen(XATTR_RICHACL));
}
-#endif
/*
* Only show root namespace entries if we are actually allowed to
--
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]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-03 16:30 +0100 |
| Subject | [PATCH v13 44/51] xfs: Don't allow unmapped identifiers in richacls |
| Message-ID | <qqLH5-4sG-57@gated-at.bofh.it> |
| In reply to | #1261574 |
Don't allow acls which contain unmapped identifiers: they are meaningful
for remote file systems only.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
fs/xfs/xfs_richacl.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/fs/xfs/xfs_richacl.c b/fs/xfs/xfs_richacl.c
index f8f5a62..4a2e21a 100644
--- a/fs/xfs/xfs_richacl.c
+++ b/fs/xfs/xfs_richacl.c
@@ -78,6 +78,10 @@ __xfs_set_richacl(struct inode *inode, struct richacl *acl, int xflags)
if (!acl)
return xfs_remove_richacl(inode);
+ /* Don't allow acls with unmapped identifiers. */
+ if (richacl_has_unmapped_identifiers(acl))
+ return -EINVAL;
+
if (richacl_equiv_mode(acl, &mode) == 0) {
xfs_set_mode(inode, mode);
return xfs_remove_richacl(inode);
--
2.5.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
Page 2 of 4 — ← Prev page 1 [2] 3 4 Next page →
Back to top | Article view | linux.kernel
csiph-web