static int decode_filename_inline(struct xdr_stream *xdr, const char **name, u32 *length) { __be32 *p; u32 count; p = xdr_inline_decode(xdr, 4); if (unlikely(p == NULL)) goto out_overflow; count = be32_to_cpup(p); if (count > NFS3_MAXNAMLEN) goto out_nametoolong; p = xdr_inline_decode(xdr, count); if (unlikely(p == NULL)) goto out_overflow; *name = (const char *)p; *length = count; return 0; out_nametoolong: dprintk("NFS: returned filename too long: %u\n", count); return -ENAMETOOLONG; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
static int unx_validate(struct rpc_task *task, struct xdr_stream *xdr) { struct rpc_auth *auth = task->tk_rqstp->rq_cred->cr_auth; __be32 *p; u32 size; p = xdr_inline_decode(xdr, 2 * sizeof(*p)); if (!p) return -EIO; switch (*p++) { case rpc_auth_null: case rpc_auth_unix: case rpc_auth_short: break; default: return -EIO; } size = be32_to_cpup(p); if (size > RPC_MAX_AUTH_SIZE) return -EIO; p = xdr_inline_decode(xdr, size); if (!p) return -EIO; auth->au_verfsize = XDR_QUADLEN(size) + 2; auth->au_rslack = XDR_QUADLEN(size) + 2; auth->au_ralign = XDR_QUADLEN(size) + 2; return 0; }
static int decode_cookie(struct xdr_stream *xdr, struct nlm_cookie *cookie) { u32 length; __be32 *p; p = xdr_inline_decode(xdr, 4); if (unlikely(p == NULL)) goto out_overflow; length = be32_to_cpup(p++); /* apparently HPUX can return empty cookies */ if (length == 0) goto out_hpux; if (length > NLM_MAXCOOKIELEN) goto out_size; p = xdr_inline_decode(xdr, length); if (unlikely(p == NULL)) goto out_overflow; cookie->len = length; memcpy(cookie->data, p, length); return 0; out_hpux: cookie->len = 4; memset(cookie->data, 0, 4); return 0; out_size: dprintk("NFS: returned cookie was too long: %u\n", length); return -EIO; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
static int decode_filename(struct xdr_stream *xdr, char *name, u32 *length) { __be32 *p; u32 count; p = xdr_inline_decode(xdr, 4); if (!p) goto out_overflow; count = be32_to_cpup(p); if (count > 255) goto out_nametoolong; p = xdr_inline_decode(xdr, count); if (!p) goto out_overflow; memcpy(name, p, count); name[count] = 0; *length = count; return 0; out_nametoolong: printk("NFS: returned filename too long: %u\n", count); return -ENAMETOOLONG; out_overflow: printf("%s overflow\n",__func__); return -EIO; }
static int gssx_dec_buffer(struct xdr_stream *xdr, gssx_buffer *buf) { u32 length; __be32 *p; p = xdr_inline_decode(xdr, 4); if (unlikely(p == NULL)) return -ENOSPC; length = be32_to_cpup(p); p = xdr_inline_decode(xdr, length); if (unlikely(p == NULL)) return -ENOSPC; if (buf->len == 0) { /* we intentionally are not interested in this buffer */ return 0; } if (length > buf->len) return -ENOSPC; if (!buf->data) { buf->data = kmemdup(p, length, GFP_KERNEL); if (!buf->data) return -ENOMEM; } else { memcpy(buf->data, p, length); } buf->len = length; return 0; }
static int gssx_dec_linux_creds(struct xdr_stream *xdr, struct svc_cred *creds) { u32 length; __be32 *p; u32 tmp; u32 N; int i, err; p = xdr_inline_decode(xdr, 4); if (unlikely(p == NULL)) return -ENOSPC; length = be32_to_cpup(p); if (length > (3 + NGROUPS_MAX) * sizeof(u32)) return -ENOSPC; /* uid */ err = get_host_u32(xdr, &tmp); if (err) return err; creds->cr_uid = make_kuid(&init_user_ns, tmp); /* gid */ err = get_host_u32(xdr, &tmp); if (err) return err; creds->cr_gid = make_kgid(&init_user_ns, tmp); /* number of additional gid's */ err = get_host_u32(xdr, &tmp); if (err) return err; N = tmp; if ((3 + N) * sizeof(u32) != length) return -EINVAL; creds->cr_group_info = groups_alloc(N); if (creds->cr_group_info == NULL) return -ENOMEM; /* gid's */ for (i = 0; i < N; i++) { kgid_t kgid; err = get_host_u32(xdr, &tmp); if (err) goto out_free_groups; err = -EINVAL; kgid = make_kgid(&init_user_ns, tmp); if (!gid_valid(kgid)) goto out_free_groups; creds->cr_group_info->gid[i] = kgid; } groups_sort(creds->cr_group_info); return 0; out_free_groups: groups_free(creds->cr_group_info); return err; }
/* * 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_fattr3(struct xdr_stream *xdr, struct nfs_fattr *fattr) { umode_t fmode; __be32 *p; p = xdr_inline_decode(xdr, NFS3_fattr_sz << 2); if (unlikely(p == NULL)) goto out_overflow; p = xdr_decode_ftype3(p, &fmode); fattr->mode = (be32_to_cpup(p++) & ~S_IFMT) | fmode; fattr->nlink = be32_to_cpup(p++); fattr->uid = be32_to_cpup(p++); fattr->gid = be32_to_cpup(p++); p = xdr_decode_size3(p, &fattr->size); p = xdr_decode_size3(p, &fattr->du.nfs3.used); p = xdr_decode_specdata3(p, &fattr->rdev); p = xdr_decode_hyper(p, &fattr->fsid.major); fattr->fsid.minor = 0; p = xdr_decode_fileid3(p, &fattr->fileid); p = xdr_decode_nfstime3(p, &fattr->atime); p = xdr_decode_nfstime3(p, &fattr->mtime); xdr_decode_nfstime3(p, &fattr->ctime); fattr->valid |= NFS_ATTR_FATTR_V3; return 0; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
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; }
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; }
static int decode_fsinfo3resok(struct xdr_stream *xdr, struct nfs_fsinfo *result) { __be32 *p; p = xdr_inline_decode(xdr, 4 * 7 + 8 + 8 + 4); if (unlikely(p == NULL)) goto out_overflow; result->rtmax = be32_to_cpup(p++); result->rtpref = be32_to_cpup(p++); result->rtmult = be32_to_cpup(p++); result->wtmax = be32_to_cpup(p++); result->wtpref = be32_to_cpup(p++); result->wtmult = be32_to_cpup(p++); result->dtpref = be32_to_cpup(p++); p = xdr_decode_size3(p, &result->maxfilesize); xdr_decode_nfstime3(p, &result->time_delta); result->lease_time = 0; return 0; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
/** * nfs2_decode_dirent - Decode a single NFSv2 directory entry stored in * the local page cache. * @xdr: XDR stream where entry resides * @entry: buffer to fill in with entry data * @plus: boolean indicating whether this should be a readdirplus entry * * Returns zero if successful, otherwise a negative errno value is * returned. * * This function is not invoked during READDIR reply decoding, but * rather whenever an application invokes the getdents(2) system call * on a directory already in our cache. * * 2.2.17. entry * * struct entry { * unsigned fileid; * filename name; * nfscookie cookie; * entry *nextentry; * }; */ int nfs2_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, int plus) { __be32 *p; int error; p = xdr_inline_decode(xdr, 4); if (unlikely(p == NULL)) goto out_overflow; if (*p++ == xdr_zero) { p = xdr_inline_decode(xdr, 4); if (unlikely(p == NULL)) goto out_overflow; if (*p++ == xdr_zero) return -EAGAIN; entry->eof = 1; return -EBADCOOKIE; } p = xdr_inline_decode(xdr, 4); if (unlikely(p == NULL)) goto out_overflow; entry->ino = be32_to_cpup(p); error = decode_filename_inline(xdr, &entry->name, &entry->len); if (unlikely(error)) return error; /* * The type (size and byte order) of nfscookie isn't defined in * RFC 1094. This implementation assumes that it's an XDR uint32. */ entry->prev_cookie = entry->cookie; p = xdr_inline_decode(xdr, 4); if (unlikely(p == NULL)) goto out_overflow; entry->cookie = be32_to_cpup(p); entry->d_type = DT_UNKNOWN; return 0; out_overflow: print_overflow_msg(__func__, xdr); return -EAGAIN; }
static int decode_nlm4_holder(struct xdr_stream *xdr, struct nlm_res *result) { struct nlm_lock *lock = &result->lock; struct file_lock *fl = &lock->fl; u64 l_offset, l_len; u32 exclusive; int error; __be32 *p; s32 end; memset(lock, 0, sizeof(*lock)); locks_init_lock(fl); p = xdr_inline_decode(xdr, 4 + 4); if (unlikely(p == NULL)) goto out_overflow; exclusive = be32_to_cpup(p++); lock->svid = be32_to_cpup(p); fl->fl_pid = (pid_t)lock->svid; error = decode_netobj(xdr, &lock->oh); if (unlikely(error)) goto out; p = xdr_inline_decode(xdr, 8 + 8); if (unlikely(p == NULL)) goto out_overflow; fl->fl_flags = FL_POSIX; fl->fl_type = exclusive != 0 ? F_WRLCK : F_RDLCK; p = xdr_decode_hyper(p, &l_offset); xdr_decode_hyper(p, &l_len); end = l_offset + l_len - 1; fl->fl_start = (loff_t)l_offset; if (l_len == 0 || end < 0) fl->fl_end = OFFSET_MAX; else fl->fl_end = (loff_t)end; error = 0; out: return error; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
static uint32_t *read_buf(struct xdr_stream *xdr, int nbytes) { uint32_t *p; p = xdr_inline_decode(xdr, nbytes); if (unlikely(p == NULL)) printk(KERN_WARNING "NFSv4 callback reply buffer overflowed!\n"); return p; }
static int _osd_xdr_decode_opaque_cred(struct pnfs_osd_opaque_cred *opaque_cred, struct xdr_stream *xdr) { __be32 *p = xdr_inline_decode(xdr, 1); if (!p) return -EINVAL; opaque_cred->cred_len = be32_to_cpu(*p++); p = xdr_inline_decode(xdr, opaque_cred->cred_len); if (!p) return -EINVAL; opaque_cred->cred = p; return 0; }
struct nfs4_deviceid_node * bl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev, gfp_t gfp_mask) { struct nfs4_deviceid_node *node = NULL; struct pnfs_block_volume *volumes; struct pnfs_block_dev *top; struct xdr_stream xdr; struct xdr_buf buf; struct page *scratch; int nr_volumes, ret, i; __be32 *p; scratch = alloc_page(gfp_mask); if (!scratch) goto out; xdr_init_decode_pages(&xdr, &buf, pdev->pages, pdev->pglen); xdr_set_scratch_buffer(&xdr, page_address(scratch), PAGE_SIZE); p = xdr_inline_decode(&xdr, sizeof(__be32)); if (!p) goto out_free_scratch; nr_volumes = be32_to_cpup(p++); volumes = kcalloc(nr_volumes, sizeof(struct pnfs_block_volume), gfp_mask); if (!volumes) goto out_free_scratch; for (i = 0; i < nr_volumes; i++) { ret = nfs4_block_decode_volume(&xdr, &volumes[i]); if (ret < 0) goto out_free_volumes; } top = kzalloc(sizeof(*top), gfp_mask); if (!top) goto out_free_volumes; ret = bl_parse_deviceid(server, top, volumes, nr_volumes - 1, gfp_mask); if (ret) { bl_free_device(top); kfree(top); goto out_free_volumes; } node = &top->node; nfs4_init_deviceid_node(node, server, &pdev->dev_id); out_free_volumes: kfree(volumes); out_free_scratch: __free_page(scratch); out: return node; }
__be32 * nfs_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_server *server, int plus) { __be32 *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, 8); if (unlikely(!p)) goto out_overflow; entry->ino = ntohl(*p++); entry->len = ntohl(*p++); p = xdr_inline_decode(xdr, entry->len + 4); if (unlikely(!p)) goto out_overflow; entry->name = (const char *) p; p += XDR_QUADLEN(entry->len); entry->prev_cookie = entry->cookie; entry->cookie = ntohl(*p++); 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); return ERR_PTR(-EIO); }
static int gssx_dec_status(struct xdr_stream *xdr, struct gssx_status *status) { __be32 *p; int err; /* status->major_status */ p = xdr_inline_decode(xdr, 8); if (unlikely(p == NULL)) return -ENOSPC; p = xdr_decode_hyper(p, &status->major_status); /* status->mech */ err = gssx_dec_buffer(xdr, &status->mech); if (err) return err; /* status->minor_status */ p = xdr_inline_decode(xdr, 8); if (unlikely(p == NULL)) return -ENOSPC; p = xdr_decode_hyper(p, &status->minor_status); /* status->major_status_string */ err = gssx_dec_buffer(xdr, &status->major_status_string); if (err) return err; /* status->minor_status_string */ err = gssx_dec_buffer(xdr, &status->minor_status_string); if (err) return err; /* status->server_ctx */ err = gssx_dec_buffer(xdr, &status->server_ctx); if (err) return err; /* we assume we have no options for now, so simply consume them */ /* status->options */ err = dummy_dec_opt_array(xdr, &status->options); return err; }
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 int gssx_dec_bool(struct xdr_stream *xdr, u32 *v) { __be32 *p; p = xdr_inline_decode(xdr, 4); if (unlikely(p == NULL)) return -ENOSPC; *v = be32_to_cpu(*p); return 0; }
__be32 * nfs_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_server *server, int plus) { __be32 *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, 8); if (unlikely(!p)) goto out_overflow; entry->ino = ntohl(*p++); entry->len = ntohl(*p++); p = xdr_inline_decode(xdr, entry->len); if (unlikely(!p)) goto out_overflow; entry->name = (const char *) p; p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) goto out_overflow; entry->prev_cookie = entry->cookie; entry->cookie = be32_to_cpup(p); entry->d_type = DT_UNKNOWN; return p; out_overflow: print_overflow_msg(__func__, xdr); return ERR_PTR(-EAGAIN); }
static int get_host_u32(struct xdr_stream *xdr, u32 *res) { __be32 *p; p = xdr_inline_decode(xdr, 4); if (!p) return -EINVAL; /* Contents of linux creds are all host-endian: */ memcpy(res, p, sizeof(u32)); return 0; }
/* * CB_COMPOUND4res * * struct CB_COMPOUND4res { * nfsstat4 status; * utf8str_cs tag; * nfs_cb_resop4 resarray<>; * }; */ static int decode_cb_compound4res(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr) { u32 length; __be32 *p; p = xdr_inline_decode(xdr, 4 + 4); if (unlikely(p == NULL)) goto out_overflow; hdr->status = be32_to_cpup(p++); /* Ignore the tag */ length = be32_to_cpup(p++); p = xdr_inline_decode(xdr, length + 4); if (unlikely(p == NULL)) goto out_overflow; hdr->nops = be32_to_cpup(p); return 0; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
static int decode_uint32(struct xdr_stream *xdr, u32 *value) { __be32 *p; p = xdr_inline_decode(xdr, 4); if (unlikely(p == NULL)) goto out_overflow; *value = be32_to_cpup(p); return 0; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
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); }
static int decode_uint64(struct xdr_stream *xdr, u64 *value) { __be32 *p; p = xdr_inline_decode(xdr, 8); if (unlikely(p == NULL)) goto out_overflow; xdr_decode_hyper(p, value); return 0; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
static int decode_writeverf3(struct xdr_stream *xdr, __be32 *verifier) { __be32 *p; p = xdr_inline_decode(xdr, NFS3_WRITEVERFSIZE); if (unlikely(p == NULL)) goto out_overflow; memcpy(verifier, p, NFS3_WRITEVERFSIZE); return 0; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
static int decode_post_op_fh3(struct xdr_stream *xdr, struct nfs_fh *fh) { __be32 *p = xdr_inline_decode(xdr, 4); if (unlikely(p == NULL)) goto out_overflow; if (*p != xdr_zero) return decode_nfs_fh3(xdr, fh); zero_nfs_fh3(fh); return 0; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
/* * enum stat { * NFS_OK = 0, * NFSERR_PERM = 1, * NFSERR_NOENT = 2, * NFSERR_IO = 5, * NFSERR_NXIO = 6, * NFSERR_ACCES = 13, * NFSERR_EXIST = 17, * NFSERR_NODEV = 19, * NFSERR_NOTDIR = 20, * NFSERR_ISDIR = 21, * NFSERR_FBIG = 27, * NFSERR_NOSPC = 28, * NFSERR_ROFS = 30, * NFSERR_NAMETOOLONG = 63, * NFSERR_NOTEMPTY = 66, * NFSERR_DQUOT = 69, * NFSERR_STALE = 70, * NFSERR_WFLUSH = 99 * }; */ static int decode_stat(struct xdr_stream *xdr, enum nfs_stat *status) { __be32 *p; p = xdr_inline_decode(xdr, 4); if (unlikely(p == NULL)) goto out_overflow; *status = be32_to_cpup(p); return 0; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
/* * CB_SEQUENCE4resok * * struct CB_SEQUENCE4resok { * sessionid4 csr_sessionid; * sequenceid4 csr_sequenceid; * slotid4 csr_slotid; * slotid4 csr_highest_slotid; * slotid4 csr_target_highest_slotid; * }; * * union CB_SEQUENCE4res switch (nfsstat4 csr_status) { * case NFS4_OK: * CB_SEQUENCE4resok csr_resok4; * default: * void; * }; * * Our current back channel implmentation supports a single backchannel * with a single slot. */ static int decode_cb_sequence4resok(struct xdr_stream *xdr, struct nfsd4_callback *cb) { struct nfsd4_session *session = cb->cb_clp->cl_cb_session; struct nfs4_sessionid id; int status; __be32 *p; u32 dummy; status = -ESERVERFAULT; /* * If the server returns different values for sessionID, slotID or * sequence number, the server is looney tunes. */ p = xdr_inline_decode(xdr, NFS4_MAX_SESSIONID_LEN + 4 + 4 + 4 + 4); if (unlikely(p == NULL)) goto out_overflow; memcpy(id.data, p, NFS4_MAX_SESSIONID_LEN); if (memcmp(id.data, session->se_sessionid.data, NFS4_MAX_SESSIONID_LEN) != 0) { dprintk("NFS: %s Invalid session id\n", __func__); goto out; } p += XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN); dummy = be32_to_cpup(p++); if (dummy != session->se_cb_seq_nr) { dprintk("NFS: %s Invalid sequence number\n", __func__); goto out; } dummy = be32_to_cpup(p++); if (dummy != 0) { dprintk("NFS: %s Invalid slotid\n", __func__); goto out; } /* * FIXME: process highest slotid and target highest slotid */ status = 0; out: if (status) nfsd4_mark_cb_fault(cb->cb_clp, status); return status; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }