static int decode_path(struct xdr_stream *xdr) { u32 length, recvd; __be32 *p; p = xdr_inline_decode(xdr, 4); if (unlikely(p == NULL)) goto out_overflow; length = be32_to_cpup(p); if (unlikely(length >= xdr->buf->page_len || length > NFS_MAXPATHLEN)) goto out_size; recvd = xdr_read_pages(xdr, length); if (unlikely(length > recvd)) goto out_cheating; xdr_terminate_string(xdr->buf, length); return 0; out_size: dprintk("NFS: returned pathname too long: %u\n", length); return -ENAMETOOLONG; out_cheating: dprintk("NFS: server cheating in pathname result: " "length %u > received %u\n", length, recvd); return -EIO; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
/* * typedef opaque nfsdata<>; */ static int decode_nfsdata(struct xdr_stream *xdr, struct nfs_readres *result) { u32 recvd, count; __be32 *p; p = xdr_inline_decode(xdr, 4); if (unlikely(p == NULL)) goto out_overflow; count = be32_to_cpup(p); recvd = xdr_read_pages(xdr, count); if (unlikely(count > recvd)) goto out_cheating; out: result->eof = 0; /* NFSv2 does not pass EOF flag on the wire. */ result->count = count; return count; out_cheating: dprintk("NFS: server cheating in read result: " "count %u > recvd %u\n", count, recvd); count = recvd; goto out; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
static int decode_nfspath3(struct xdr_stream *xdr) { u32 recvd, count; size_t hdrlen; __be32 *p; p = xdr_inline_decode(xdr, 4); if (unlikely(p == NULL)) goto out_overflow; count = be32_to_cpup(p); if (unlikely(count >= xdr->buf->page_len || count > NFS3_MAXPATHLEN)) goto out_nametoolong; hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base; recvd = xdr->buf->len - hdrlen; if (unlikely(count > recvd)) goto out_cheating; xdr_read_pages(xdr, count); xdr_terminate_string(xdr->buf, count); return 0; out_nametoolong: dprintk("NFS: returned pathname too long: %u\n", count); return -ENAMETOOLONG; out_cheating: dprintk("NFS: server cheating in pathname result: " "count %u > recvd %u\n", count, recvd); return -EIO; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
/* * 2.2.17. readdirres * * union readdirres switch (stat status) { * case NFS_OK: * struct { * entry *entries; * bool eof; * } readdirok; * default: * void; * }; * * Read the directory contents into the page cache, but don't * touch them. The actual decoding is done by nfs2_decode_dirent() * during subsequent nfs_readdir() calls. */ static int decode_readdirok(struct xdr_stream *xdr) { u32 recvd, pglen; size_t hdrlen; pglen = xdr->buf->page_len; hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base; recvd = xdr->buf->len - hdrlen; if (unlikely(pglen > recvd)) goto out_cheating; out: xdr_read_pages(xdr, pglen); return pglen; out_cheating: dprintk("NFS: server cheating in readdir result: " "pglen %u > recvd %u\n", pglen, recvd); pglen = recvd; goto out; }
static int decode_read3resok(struct xdr_stream *xdr, struct nfs_readres *result) { u32 eof, count, ocount, recvd; size_t hdrlen; __be32 *p; p = xdr_inline_decode(xdr, 4 + 4 + 4); if (unlikely(p == NULL)) goto out_overflow; count = be32_to_cpup(p++); eof = be32_to_cpup(p++); ocount = be32_to_cpup(p++); if (unlikely(ocount != count)) goto out_mismatch; hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base; recvd = xdr->buf->len - hdrlen; if (unlikely(count > recvd)) goto out_cheating; out: xdr_read_pages(xdr, count); result->eof = eof; result->count = count; return count; out_mismatch: dprintk("NFS: READ count doesn't match length of opaque: " "count %u != ocount %u\n", count, ocount); return -EIO; out_cheating: dprintk("NFS: server cheating in read result: " "count %u > recvd %u\n", count, recvd); count = recvd; eof = 0; goto out; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
/* * 2.2.17. readdirres * * union readdirres switch (stat status) { * case NFS_OK: * struct { * entry *entries; * bool eof; * } readdirok; * default: * void; * }; * * Read the directory contents into the page cache, but don't * touch them. The actual decoding is done by nfs2_decode_dirent() * during subsequent nfs_readdir() calls. */ static int decode_readdirok(struct xdr_stream *xdr) { return xdr_read_pages(xdr, xdr->buf->page_len); }