RPC: Ensure XDR iovec length is initialized correctly in call_header Fix up call_header() so that it calls xdr_adjust_iovec(). Fix calculation of the scratch buffer length in xdr_init_encode(). Signed-off-by: Trond Myklebust --- clnt.c | 4 +++- svc.c | 1 + xdr.c | 18 +++++++++++++++--- 3 files changed, 19 insertions(+), 4 deletions(-) Index: linux-2.6.12-rc1/net/sunrpc/xdr.c =================================================================== --- linux-2.6.12-rc1.orig/net/sunrpc/xdr.c +++ linux-2.6.12-rc1/net/sunrpc/xdr.c @@ -616,12 +616,24 @@ xdr_shift_buf(struct xdr_buf *buf, size_ void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p) { struct kvec *iov = buf->head; + int scratch_len = buf->buflen - buf->page_len - buf->tail[0].iov_len; + BUG_ON(scratch_len < 0); xdr->buf = buf; xdr->iov = iov; - xdr->end = (uint32_t *)((char *)iov->iov_base + iov->iov_len); - buf->len = iov->iov_len = (char *)p - (char *)iov->iov_base; - xdr->p = p; + xdr->p = (uint32_t *)((char *)iov->iov_base + iov->iov_len); + xdr->end = (uint32_t *)((char *)iov->iov_base + scratch_len); + BUG_ON(iov->iov_len > scratch_len); + + if (p != xdr->p && p != NULL) { + size_t len; + + BUG_ON(p < xdr->p || p > xdr->end); + len = (char *)p - (char *)xdr->p; + xdr->p = p; + buf->len += len; + iov->iov_len += len; + } } EXPORT_SYMBOL(xdr_init_encode); Index: linux-2.6.12-rc1/net/sunrpc/clnt.c =================================================================== --- linux-2.6.12-rc1.orig/net/sunrpc/clnt.c +++ linux-2.6.12-rc1/net/sunrpc/clnt.c @@ -957,7 +957,9 @@ call_header(struct rpc_task *task) *p++ = htonl(clnt->cl_prog); /* program number */ *p++ = htonl(clnt->cl_vers); /* program version */ *p++ = htonl(task->tk_msg.rpc_proc->p_proc); /* procedure */ - return rpcauth_marshcred(task, p); + p = rpcauth_marshcred(task, p); + req->rq_slen = xdr_adjust_iovec(&req->rq_svec[0], p); + return p; } /* Index: linux-2.6.12-rc1/net/sunrpc/svc.c =================================================================== --- linux-2.6.12-rc1.orig/net/sunrpc/svc.c +++ linux-2.6.12-rc1/net/sunrpc/svc.c @@ -281,6 +281,7 @@ svc_process(struct svc_serv *serv, struc rqstp->rq_res.len = 0; rqstp->rq_res.page_base = 0; rqstp->rq_res.page_len = 0; + rqstp->rq_res.buflen = PAGE_SIZE; rqstp->rq_res.tail[0].iov_len = 0; /* tcp needs a space for the record length... */ if (rqstp->rq_prot == IPPROTO_TCP)