|
@@ -100,6 +100,13 @@ static const umode_t nfs_type2fmt[] = {
|
|
|
[NF3FIFO] = S_IFIFO,
|
|
|
};
|
|
|
|
|
|
+static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
|
|
|
+{
|
|
|
+ dprintk("nfs: %s: prematurely hit end of receive buffer. "
|
|
|
+ "Remaining buffer length is %tu words.\n",
|
|
|
+ func, xdr->end - xdr->p);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Common NFS XDR functions as inlines
|
|
|
*/
|
|
@@ -119,6 +126,29 @@ xdr_decode_fhandle(__be32 *p, struct nfs_fh *fh)
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
+static inline __be32 *
|
|
|
+xdr_decode_fhandle_stream(struct xdr_stream *xdr, struct nfs_fh *fh)
|
|
|
+{
|
|
|
+ __be32 *p;
|
|
|
+ p = xdr_inline_decode(xdr, 4);
|
|
|
+ if (unlikely(!p))
|
|
|
+ goto out_overflow;
|
|
|
+ fh->size = ntohl(*p++);
|
|
|
+
|
|
|
+ if (fh->size <= NFS3_FHSIZE) {
|
|
|
+ p = xdr_inline_decode(xdr, fh->size);
|
|
|
+ if (unlikely(!p))
|
|
|
+ goto out_overflow;
|
|
|
+ memcpy(fh->data, p, fh->size);
|
|
|
+ return p + XDR_QUADLEN(fh->size);
|
|
|
+ }
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+out_overflow:
|
|
|
+ print_overflow_msg(__func__, xdr);
|
|
|
+ return ERR_PTR(-EIO);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Encode/decode time.
|
|
|
*/
|
|
@@ -240,6 +270,26 @@ xdr_decode_post_op_attr(__be32 *p, struct nfs_fattr *fattr)
|
|
|
return p;
|
|
|
}
|
|
|
|
|
|
+static inline __be32 *
|
|
|
+xdr_decode_post_op_attr_stream(struct xdr_stream *xdr, struct nfs_fattr *fattr)
|
|
|
+{
|
|
|
+ __be32 *p;
|
|
|
+
|
|
|
+ p = xdr_inline_decode(xdr, 4);
|
|
|
+ if (unlikely(!p))
|
|
|
+ goto out_overflow;
|
|
|
+ if (ntohl(*p++)) {
|
|
|
+ p = xdr_inline_decode(xdr, 84);
|
|
|
+ if (unlikely(!p))
|
|
|
+ goto out_overflow;
|
|
|
+ p = xdr_decode_fattr(p, fattr);
|
|
|
+ }
|
|
|
+ return p;
|
|
|
+out_overflow:
|
|
|
+ print_overflow_msg(__func__, xdr);
|
|
|
+ return ERR_PTR(-EIO);
|
|
|
+}
|
|
|
+
|
|
|
static inline __be32 *
|
|
|
xdr_decode_pre_op_attr(__be32 *p, struct nfs_fattr *fattr)
|
|
|
{
|
|
@@ -616,19 +666,33 @@ err_unmap:
|
|
|
}
|
|
|
|
|
|
__be32 *
|
|
|
-nfs3_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
|
|
|
+nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, int plus)
|
|
|
{
|
|
|
+ __be32 *p;
|
|
|
struct nfs_entry old = *entry;
|
|
|
|
|
|
- if (!*p++) {
|
|
|
- if (!*p)
|
|
|
+ p = xdr_inline_decode(xdr, 4);
|
|
|
+ if (unlikely(!p))
|
|
|
+ goto out_overflow;
|
|
|
+ if (!ntohl(*p++)) {
|
|
|
+ p = xdr_inline_decode(xdr, 4);
|
|
|
+ if (unlikely(!p))
|
|
|
+ goto out_overflow;
|
|
|
+ if (!ntohl(*p++))
|
|
|
return ERR_PTR(-EAGAIN);
|
|
|
entry->eof = 1;
|
|
|
return ERR_PTR(-EBADCOOKIE);
|
|
|
}
|
|
|
|
|
|
+ p = xdr_inline_decode(xdr, 12);
|
|
|
+ if (unlikely(!p))
|
|
|
+ goto out_overflow;
|
|
|
p = xdr_decode_hyper(p, &entry->ino);
|
|
|
entry->len = ntohl(*p++);
|
|
|
+
|
|
|
+ p = xdr_inline_decode(xdr, entry->len + 8);
|
|
|
+ if (unlikely(!p))
|
|
|
+ goto out_overflow;
|
|
|
entry->name = (const char *) p;
|
|
|
p += XDR_QUADLEN(entry->len);
|
|
|
entry->prev_cookie = entry->cookie;
|
|
@@ -636,10 +700,17 @@ nfs3_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
|
|
|
|
|
|
if (plus) {
|
|
|
entry->fattr->valid = 0;
|
|
|
- p = xdr_decode_post_op_attr(p, entry->fattr);
|
|
|
+ p = xdr_decode_post_op_attr_stream(xdr, entry->fattr);
|
|
|
+ if (IS_ERR(p))
|
|
|
+ goto out_overflow_exit;
|
|
|
/* In fact, a post_op_fh3: */
|
|
|
+ p = xdr_inline_decode(xdr, 4);
|
|
|
+ if (unlikely(!p))
|
|
|
+ goto out_overflow;
|
|
|
if (*p++) {
|
|
|
- p = xdr_decode_fhandle(p, entry->fh);
|
|
|
+ p = xdr_decode_fhandle_stream(xdr, entry->fh);
|
|
|
+ if (IS_ERR(p))
|
|
|
+ goto out_overflow_exit;
|
|
|
/* Ugh -- server reply was truncated */
|
|
|
if (p == NULL) {
|
|
|
dprintk("NFS: FH truncated\n");
|
|
@@ -650,8 +721,18 @@ nfs3_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
|
|
|
memset((u8*)(entry->fh), 0, sizeof(*entry->fh));
|
|
|
}
|
|
|
|
|
|
- entry->eof = !p[0] && p[1];
|
|
|
+ p = xdr_inline_peek(xdr, 8);
|
|
|
+ if (p != NULL)
|
|
|
+ entry->eof = !p[0] && p[1];
|
|
|
+ else
|
|
|
+ entry->eof = 0;
|
|
|
+
|
|
|
return p;
|
|
|
+
|
|
|
+out_overflow:
|
|
|
+ print_overflow_msg(__func__, xdr);
|
|
|
+out_overflow_exit:
|
|
|
+ return ERR_PTR(-EIO);
|
|
|
}
|
|
|
|
|
|
/*
|