From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
To: linux-kernel@vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
stable@vger.kernel.org, Andy Adamson <andros@netapp.com>,
Trond Myklebust <Trond.Myklebust@netapp.com>,
Jiri Slaby <jslaby@suse.cz>
Subject: [ 24/56] NFSv4: include bitmap in nfsv4 get acl data
Date: Tue, 2 Apr 2013 15:49:51 -0700 [thread overview]
Message-ID: <20130402224714.708823449@linuxfoundation.org> (raw)
In-Reply-To: <20130402224711.840825715@linuxfoundation.org>
3.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andy Adamson <andros@netapp.com>
commit bf118a342f10dafe44b14451a1392c3254629a1f upstream.
The NFSv4 bitmap size is unbounded: a server can return an arbitrary
sized bitmap in an FATTR4_WORD0_ACL request. Replace using the
nfs4_fattr_bitmap_maxsz as a guess to the maximum bitmask returned by a server
with the inclusion of the bitmap (xdr length plus bitmasks) and the acl data
xdr length to the (cached) acl page data.
This is a general solution to commit e5012d1f "NFSv4.1: update
nfs4_fattr_bitmap_maxsz" and fixes hitting a BUG_ON in xdr_shrink_bufhead
when getting ACLs.
Fix a bug in decode_getacl that returned -EINVAL on ACLs > page when getxattr
was called with a NULL buffer, preventing ACL > PAGE_SIZE from being retrieved.
Signed-off-by: Andy Adamson <andros@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
fs/nfs/nfs4proc.c | 96 ++++++++++++++++++++++++++-------------------
fs/nfs/nfs4xdr.c | 31 ++++++++++----
include/linux/nfs_xdr.h | 5 ++
include/linux/sunrpc/xdr.h | 2
net/sunrpc/xdr.c | 3 -
5 files changed, 89 insertions(+), 48 deletions(-)
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -3440,19 +3440,6 @@ static inline int nfs4_server_supports_a
*/
#define NFS4ACL_MAXPAGES (XATTR_SIZE_MAX >> PAGE_CACHE_SHIFT)
-static void buf_to_pages(const void *buf, size_t buflen,
- struct page **pages, unsigned int *pgbase)
-{
- const void *p = buf;
-
- *pgbase = offset_in_page(buf);
- p -= *pgbase;
- while (p < buf + buflen) {
- *(pages++) = virt_to_page(p);
- p += PAGE_CACHE_SIZE;
- }
-}
-
static int buf_to_pages_noslab(const void *buf, size_t buflen,
struct page **pages, unsigned int *pgbase)
{
@@ -3549,9 +3536,19 @@ out:
nfs4_set_cached_acl(inode, acl);
}
+/*
+ * The getxattr API returns the required buffer length when called with a
+ * NULL buf. The NFSv4 acl tool then calls getxattr again after allocating
+ * the required buf. On a NULL buf, we send a page of data to the server
+ * guessing that the ACL request can be serviced by a page. If so, we cache
+ * up to the page of ACL data, and the 2nd call to getxattr is serviced by
+ * the cache. If not so, we throw away the page, and cache the required
+ * length. The next getxattr call will then produce another round trip to
+ * the server, this time with the input buf of the required size.
+ */
static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen)
{
- struct page *pages[NFS4ACL_MAXPAGES];
+ struct page *pages[NFS4ACL_MAXPAGES] = {NULL, };
struct nfs_getaclargs args = {
.fh = NFS_FH(inode),
.acl_pages = pages,
@@ -3566,41 +3563,60 @@ static ssize_t __nfs4_get_acl_uncached(s
.rpc_argp = &args,
.rpc_resp = &res,
};
- struct page *localpage = NULL;
- int ret;
+ int ret = -ENOMEM, npages, i, acl_len = 0;
- if (buflen < PAGE_SIZE) {
- /* As long as we're doing a round trip to the server anyway,
- * let's be prepared for a page of acl data. */
- localpage = alloc_page(GFP_KERNEL);
- resp_buf = page_address(localpage);
- if (localpage == NULL)
- return -ENOMEM;
- args.acl_pages[0] = localpage;
- args.acl_pgbase = 0;
- args.acl_len = PAGE_SIZE;
- } else {
- resp_buf = buf;
- buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase);
+ npages = (buflen + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ /* As long as we're doing a round trip to the server anyway,
+ * let's be prepared for a page of acl data. */
+ if (npages == 0)
+ npages = 1;
+
+ for (i = 0; i < npages; i++) {
+ pages[i] = alloc_page(GFP_KERNEL);
+ if (!pages[i])
+ goto out_free;
}
- ret = nfs4_call_sync(NFS_SERVER(inode)->client, NFS_SERVER(inode), &msg, &args.seq_args, &res.seq_res, 0);
+ if (npages > 1) {
+ /* for decoding across pages */
+ args.acl_scratch = alloc_page(GFP_KERNEL);
+ if (!args.acl_scratch)
+ goto out_free;
+ }
+ args.acl_len = npages * PAGE_SIZE;
+ args.acl_pgbase = 0;
+ /* Let decode_getfacl know not to fail if the ACL data is larger than
+ * the page we send as a guess */
+ if (buf == NULL)
+ res.acl_flags |= NFS4_ACL_LEN_REQUEST;
+ resp_buf = page_address(pages[0]);
+
+ dprintk("%s buf %p buflen %ld npages %d args.acl_len %ld\n",
+ __func__, buf, buflen, npages, args.acl_len);
+ ret = nfs4_call_sync(NFS_SERVER(inode)->client, NFS_SERVER(inode),
+ &msg, &args.seq_args, &res.seq_res, 0);
if (ret)
goto out_free;
- if (res.acl_len > args.acl_len)
- nfs4_write_cached_acl(inode, NULL, res.acl_len);
+
+ acl_len = res.acl_len - res.acl_data_offset;
+ if (acl_len > args.acl_len)
+ nfs4_write_cached_acl(inode, NULL, acl_len);
else
- nfs4_write_cached_acl(inode, resp_buf, res.acl_len);
+ nfs4_write_cached_acl(inode, resp_buf + res.acl_data_offset,
+ acl_len);
if (buf) {
ret = -ERANGE;
- if (res.acl_len > buflen)
+ if (acl_len > buflen)
goto out_free;
- if (localpage)
- memcpy(buf, resp_buf, res.acl_len);
+ _copy_from_pages(buf, pages, res.acl_data_offset,
+ res.acl_len);
}
- ret = res.acl_len;
+ ret = acl_len;
out_free:
- if (localpage)
- __free_page(localpage);
+ for (i = 0; i < npages; i++)
+ if (pages[i])
+ __free_page(pages[i]);
+ if (args.acl_scratch)
+ __free_page(args.acl_scratch);
return ret;
}
@@ -3631,6 +3647,8 @@ static ssize_t nfs4_proc_get_acl(struct
nfs_zap_acl_cache(inode);
ret = nfs4_read_cached_acl(inode, buf, buflen);
if (ret != -ENOENT)
+ /* -ENOENT is returned if there is no ACL or if there is an ACL
+ * but no cached acl data, just the acl length */
return ret;
return nfs4_get_acl_uncached(inode, buf, buflen);
}
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -2374,11 +2374,13 @@ static void nfs4_xdr_enc_getacl(struct r
encode_compound_hdr(xdr, req, &hdr);
encode_sequence(xdr, &args->seq_args, &hdr);
encode_putfh(xdr, args->fh, &hdr);
- replen = hdr.replen + op_decode_hdr_maxsz + nfs4_fattr_bitmap_maxsz + 1;
+ replen = hdr.replen + op_decode_hdr_maxsz + 1;
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);
+ xdr_set_scratch_buffer(xdr, page_address(args->acl_scratch), PAGE_SIZE);
+
encode_nops(&hdr);
}
@@ -4714,17 +4716,18 @@ decode_restorefh(struct xdr_stream *xdr)
}
static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
- size_t *acl_len)
+ struct nfs_getaclres *res)
{
- __be32 *savep;
+ __be32 *savep, *bm_p;
uint32_t attrlen,
bitmap[2] = {0};
struct kvec *iov = req->rq_rcv_buf.head;
int status;
- *acl_len = 0;
+ res->acl_len = 0;
if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
goto out;
+ bm_p = xdr->p;
if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
goto out;
if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
@@ -4736,18 +4739,30 @@ static int decode_getacl(struct xdr_stre
size_t hdrlen;
u32 recvd;
+ /* The bitmap (xdr len + bitmaps) and the attr xdr len words
+ * are stored with the acl data to handle the problem of
+ * variable length bitmaps.*/
+ xdr->p = bm_p;
+ res->acl_data_offset = be32_to_cpup(bm_p) + 2;
+ res->acl_data_offset <<= 2;
+
/* We ignore &savep and don't do consistency checks on
* the attr length. Let userspace figure it out.... */
hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base;
+ attrlen += res->acl_data_offset;
recvd = req->rq_rcv_buf.len - hdrlen;
if (attrlen > recvd) {
- dprintk("NFS: server cheating in getattr"
- " acl reply: attrlen %u > recvd %u\n",
+ if (res->acl_flags & NFS4_ACL_LEN_REQUEST) {
+ /* getxattr interface called with a NULL buf */
+ res->acl_len = attrlen;
+ goto out;
+ }
+ dprintk("NFS: acl reply: attrlen %u > recvd %u\n",
attrlen, recvd);
return -EINVAL;
}
xdr_read_pages(xdr, attrlen);
- *acl_len = attrlen;
+ res->acl_len = attrlen;
} else
status = -EOPNOTSUPP;
@@ -5682,7 +5697,7 @@ nfs4_xdr_dec_getacl(struct rpc_rqst *rqs
status = decode_putfh(xdr);
if (status)
goto out;
- status = decode_getacl(xdr, rqstp, &res->acl_len);
+ status = decode_getacl(xdr, rqstp, res);
out:
return status;
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -588,11 +588,16 @@ struct nfs_getaclargs {
size_t acl_len;
unsigned int acl_pgbase;
struct page ** acl_pages;
+ struct page * acl_scratch;
struct nfs4_sequence_args seq_args;
};
+/* getxattr ACL interface flags */
+#define NFS4_ACL_LEN_REQUEST 0x0001 /* zero length getxattr buffer */
struct nfs_getaclres {
size_t acl_len;
+ size_t acl_data_offset;
+ int acl_flags;
struct nfs4_sequence_res seq_res;
};
--- a/include/linux/sunrpc/xdr.h
+++ b/include/linux/sunrpc/xdr.h
@@ -191,6 +191,8 @@ extern int xdr_decode_array2(struct xdr_
struct xdr_array2_desc *desc);
extern int xdr_encode_array2(struct xdr_buf *buf, unsigned int base,
struct xdr_array2_desc *desc);
+extern void _copy_from_pages(char *p, struct page **pages, size_t pgbase,
+ size_t len);
/*
* Provide some simple tools for XDR buffer overflow-checking etc.
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -296,7 +296,7 @@ _copy_to_pages(struct page **pages, size
* Copies data into an arbitrary memory location from an array of pages
* The copy is assumed to be non-overlapping.
*/
-static void
+void
_copy_from_pages(char *p, struct page **pages, size_t pgbase, size_t len)
{
struct page **pgfrom;
@@ -324,6 +324,7 @@ _copy_from_pages(char *p, struct page **
} while ((len -= copy) != 0);
}
+EXPORT_SYMBOL_GPL(_copy_from_pages);
/*
* xdr_shrink_bufhead
next prev parent reply other threads:[~2013-04-02 22:59 UTC|newest]
Thread overview: 62+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-04-02 22:49 [ 00/56] 3.0.72-stable review Greg Kroah-Hartman
2013-04-02 22:49 ` [ 01/56] signal: Define __ARCH_HAS_SA_RESTORER so we know whether to clear sa_restorer Greg Kroah-Hartman
2013-04-02 22:49 ` [ 02/56] kernel/signal.c: use __ARCH_HAS_SA_RESTORER instead of SA_RESTORER Greg Kroah-Hartman
2013-04-02 22:49 ` [ 03/56] SUNRPC: Add barriers to ensure read ordering in rpc_wake_up_task_queue_locked Greg Kroah-Hartman
2013-04-02 22:49 ` [ 04/56] Bluetooth: Fix not closing SCO sockets in the BT_CONNECT2 state Greg Kroah-Hartman
2013-04-02 22:49 ` [ 05/56] Bluetooth: Add support for Dell[QCA 0cf3:0036] Greg Kroah-Hartman
2013-04-02 22:49 ` [ 06/56] Bluetooth: Add support for Dell[QCA 0cf3:817a] Greg Kroah-Hartman
2013-04-02 22:49 ` [ 07/56] staging: comedi: s626: fix continuous acquisition Greg Kroah-Hartman
2013-04-02 22:49 ` [ 08/56] sysfs: fix race between readdir and lseek Greg Kroah-Hartman
2013-04-02 22:49 ` [ 09/56] sysfs: handle failure path correctly for readdir() Greg Kroah-Hartman
2013-04-02 22:49 ` [ 10/56] b43: A fix for DMA transmission sequence errors Greg Kroah-Hartman
2013-04-02 22:49 ` [ 11/56] xen-blkback: fix dispatch_rw_block_io() error path Greg Kroah-Hartman
2013-04-02 22:49 ` [ 12/56] usb: ftdi_sio: Add support for Mitsubishi FX-USB-AW/-BD Greg Kroah-Hartman
2013-04-02 22:49 ` [ 13/56] vt: synchronize_rcu() under spinlock is not nice Greg Kroah-Hartman
2013-04-02 22:49 ` [ 14/56] mwifiex: cancel cmd timer and free curr_cmd in shutdown process Greg Kroah-Hartman
2013-04-06 19:55 ` Ben Hutchings
2013-04-08 17:58 ` Bing Zhao
2013-04-08 17:58 ` Bing Zhao
2013-04-02 22:49 ` [ 15/56] net/irda: add missing error path release_sock call Greg Kroah-Hartman
2013-04-02 22:49 ` [ 16/56] usb: xhci: Fix TRB transfer length macro used for Event TRB Greg Kroah-Hartman
2013-04-02 22:49 ` [ 17/56] Btrfs: limit the global reserve to 512mb Greg Kroah-Hartman
2013-04-02 22:49 ` [ 18/56] KVM: Clean up error handling during VCPU creation Greg Kroah-Hartman
2013-04-02 22:49 ` [ 19/56] x25: Validate incoming call user data lengths Greg Kroah-Hartman
2013-04-02 22:49 ` [ 20/56] x25: Handle undersized/fragmented skbs Greg Kroah-Hartman
2013-04-02 22:49 ` [ 21/56] batman-adv: bat_socket_read missing checks Greg Kroah-Hartman
2013-04-02 22:49 ` [ 22/56] batman-adv: Only write requested number of byte to user buffer Greg Kroah-Hartman
2013-04-02 22:49 ` [ 23/56] KVM: x86: Prevent starting PIT timers in the absence of irqchip support Greg Kroah-Hartman
2013-04-02 22:49 ` Greg Kroah-Hartman [this message]
2013-04-02 22:49 ` [ 25/56] NFSv4: Fix an Oops in the NFSv4 getacl code Greg Kroah-Hartman
2013-04-02 22:49 ` [ 26/56] NFS: nfs_getaclargs.acl_len is a size_t Greg Kroah-Hartman
2013-04-02 22:49 ` [ 27/56] KVM: Ensure all vcpus are consistent with in-kernel irqchip settings Greg Kroah-Hartman
2013-04-02 22:49 ` [ 28/56] macvtap: zerocopy: validate vectors before building skb Greg Kroah-Hartman
2013-04-02 22:49 ` [ 29/56] KVM: Fix buffer overflow in kvm_set_irq() Greg Kroah-Hartman
2013-04-02 22:49 ` [ 30/56] mm/hotplug: correctly add new zone to all other nodes zone lists Greg Kroah-Hartman
2013-04-02 22:49 ` [ 31/56] KVM: x86: invalid opcode oops on SET_SREGS with OSXSAVE bit set (CVE-2012-4461) Greg Kroah-Hartman
2013-04-02 22:49 ` [ 32/56] loop: prevent bdev freeing while device in use Greg Kroah-Hartman
2013-04-02 22:50 ` [ 33/56] nfsd4: reject "negative" acl lengths Greg Kroah-Hartman
2013-04-02 22:50 ` [ 34/56] drm/i915: dont set unpin_work if vblank_get fails Greg Kroah-Hartman
2013-04-02 22:50 ` [ 35/56] drm/i915: Dont clobber crtc->fb when queue_flip fails Greg Kroah-Hartman
2013-04-02 22:50 ` [ 36/56] efivars: explicitly calculate length of VariableName Greg Kroah-Hartman
2013-04-02 22:50 ` [ 37/56] efivars: Handle duplicate names from get_next_variable() Greg Kroah-Hartman
2013-04-02 22:50 ` [ 38/56] ext4: use atomic64_t for the per-flexbg free_clusters count Greg Kroah-Hartman
2013-04-02 22:50 ` [ 39/56] tracing: Protect tracer flags with trace_types_lock Greg Kroah-Hartman
2013-04-02 22:50 ` [ 40/56] tracing: Prevent buffer overwrite disabled for latency tracers Greg Kroah-Hartman
2013-04-02 22:50 ` [ 41/56] sky2: Receive Overflows not counted Greg Kroah-Hartman
2013-04-02 22:50 ` [ 42/56] sky2: Threshold for Pause Packet is set wrong Greg Kroah-Hartman
2013-04-02 22:50 ` [ 43/56] tcp: preserve ACK clocking in TSO Greg Kroah-Hartman
2013-04-02 22:50 ` [ 44/56] tcp: undo spurious timeout after SACK reneging Greg Kroah-Hartman
2013-04-02 22:50 ` [ 45/56] 8021q: fix a potential use-after-free Greg Kroah-Hartman
2013-04-02 22:50 ` [ 46/56] thermal: shorten too long mcast group name Greg Kroah-Hartman
2013-04-02 22:50 ` [ 47/56] unix: fix a race condition in unix_release() Greg Kroah-Hartman
2013-04-02 22:50 ` [ 48/56] aoe: reserve enough headroom on skbs Greg Kroah-Hartman
2013-04-02 22:50 ` [ 49/56] drivers: net: ethernet: davinci_emac: use netif_wake_queue() while restarting tx queue Greg Kroah-Hartman
2013-04-02 22:50 ` [ 50/56] atl1e: drop pci-msi support because of packet corruption Greg Kroah-Hartman
2013-04-02 22:50 ` Greg Kroah-Hartman
2013-04-02 22:50 ` [ 51/56] ipv6: fix bad free of addrconf_init_net Greg Kroah-Hartman
2013-04-02 22:50 ` [ 52/56] ks8851: Fix interpretation of rxlen field Greg Kroah-Hartman
2013-04-02 22:50 ` [ 53/56] net: add a synchronize_net() in netdev_rx_handler_unregister() Greg Kroah-Hartman
2013-04-02 22:50 ` [ 54/56] pch_gbe: fix ip_summed checksum reporting on rx Greg Kroah-Hartman
2013-04-02 22:50 ` [ 55/56] smsc75xx: fix jumbo frame support Greg Kroah-Hartman
2013-04-02 22:50 ` [ 56/56] iommu/amd: Make sure dma_ops are set for hotplug devices Greg Kroah-Hartman
2013-04-03 15:19 ` [ 00/56] 3.0.72-stable review Shuah Khan
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20130402224714.708823449@linuxfoundation.org \
--to=gregkh@linuxfoundation.org \
--cc=Trond.Myklebust@netapp.com \
--cc=andros@netapp.com \
--cc=jslaby@suse.cz \
--cc=linux-kernel@vger.kernel.org \
--cc=stable@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.