Commit dccb90df authored by Trond Myklebust's avatar Trond Myklebust Committed by Linus Torvalds

[PATCH] Split buffer overflow checking out of struct nfs4_compound

Here is the a pre-patch in the attempt to get rid of 'struct
nfs4_compound', and the associated horrible union in 'struct
nfs4_op'.

It splits out the fields that are meant to do buffer overflow checking
and iovec adjusting on the XDR received/sent data. It moves support
for that nto the dedicated structure 'xdr_stream', and the associated
functions 'xdr_reserve_space()', 'xdr_inline_decode()'.

The patch also expands out the all macros ENCODE_HEAD, ENCODE_TAIL,
ADJUST_ARGS and DECODE_HEAD, as well as most of the DECODE_TAILs.
parent 241c59e2
......@@ -65,11 +65,6 @@ nfs4_setup_compound(struct nfs4_compound *cp, struct nfs4_op *ops,
memset(cp, 0, sizeof(*cp));
cp->ops = ops;
cp->server = server;
#if NFS4_DEBUG
cp->taglen = strlen(tag);
cp->tag = tag;
#endif
}
static void
......@@ -373,6 +368,7 @@ nfs4_setup_open(struct nfs4_compound *cp, int flags, struct qstr *name,
BUG_ON(cp->flags);
open->op_client_state = cp->server->nfs4_state;
open->op_share_access = flags & 3;
open->op_opentype = (flags & O_CREAT) ? NFS4_OPEN_CREATE : NFS4_OPEN_NOCREATE;
open->op_createmode = NFS4_CREATE_UNCHECKED;
......@@ -527,6 +523,10 @@ nfs4_setup_rename(struct nfs4_compound *cp, struct qstr *old, struct qstr *new,
static void
nfs4_setup_renew(struct nfs4_compound *cp)
{
struct nfs4_client **client_state = GET_OP(cp, renew);
*client_state = cp->server->nfs4_state;
OPNUM(cp) = OP_RENEW;
cp->req_nops++;
cp->renew_index = cp->req_nops;
......@@ -575,6 +575,7 @@ nfs4_setup_setclientid(struct nfs4_compound *cp, u32 program, unsigned short por
sprintf(setclientid->sc_uaddr, "%s.%d.%d", server->ip_addr, port >> 8, port & 255);
setclientid->sc_prog = program;
setclientid->sc_cb_ident = 0;
setclientid->sc_state = server->nfs4_state;
OPNUM(cp) = OP_SETCLIENTID;
cp->req_nops++;
......@@ -583,6 +584,10 @@ nfs4_setup_setclientid(struct nfs4_compound *cp, u32 program, unsigned short por
static void
nfs4_setup_setclientid_confirm(struct nfs4_compound *cp)
{
struct nfs4_client **client_state = GET_OP(cp, setclientid_confirm);
*client_state = cp->server->nfs4_state;
OPNUM(cp) = OP_SETCLIENTID_CONFIRM;
cp->req_nops++;
cp->renew_index = cp->req_nops;
......
This diff is collapsed.
......@@ -398,6 +398,7 @@ struct nfs4_lookup {
};
struct nfs4_open {
struct nfs4_client * op_client_state; /* request */
u32 op_share_access; /* request */
u32 op_opentype; /* request */
u32 op_createmode; /* request */
......@@ -472,6 +473,7 @@ struct nfs4_setclientid {
char sc_netid[4]; /* request */
char sc_uaddr[24]; /* request */
u32 sc_cb_ident; /* request */
struct nfs4_client * sc_state; /* response */
};
struct nfs4_write {
......@@ -504,8 +506,10 @@ struct nfs4_op {
struct nfs4_readlink readlink;
struct nfs4_remove remove;
struct nfs4_rename rename;
struct nfs4_client * renew;
struct nfs4_setattr setattr;
struct nfs4_setclientid setclientid;
struct nfs4_client * setclientid_confirm;
struct nfs4_write write;
} u;
};
......
......@@ -155,6 +155,93 @@ typedef size_t (*skb_read_actor_t)(skb_reader_t *desc, void *to, size_t len);
extern void xdr_partial_copy_from_skb(struct xdr_buf *, unsigned int,
skb_reader_t *, skb_read_actor_t);
/*
* Provide some simple tools for XDR buffer overflow-checking etc.
*/
struct xdr_stream {
uint32_t *p; /* start of available buffer */
struct xdr_buf *buf; /* XDR buffer to read/write */
uint32_t *end; /* end of available buffer space */
struct iovec *iov; /* pointer to the current iovec */
};
/*
* Initialize an xdr_stream for encoding data.
*
* Note: at the moment the RPC client only passes the length of our
* scratch buffer in the xdr_buf's header iovec. Previously this
* meant we needed to call xdr_adjust_iovec() after encoding the
* data. With the new scheme, the xdr_stream manages the details
* of the buffer length, and takes care of adjusting the iovec
* length for us.
*/
static inline void
xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p)
{
struct iovec *iov = buf->head;
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;
}
/*
* Check that we have enough buffer space to encode 'nbytes' more
* bytes of data. If so, update the total xdr_buf length, and
* adjust the length of the current iovec.
*/
static inline uint32_t *
xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes)
{
uint32_t *p = xdr->p;
uint32_t *q;
/* align nbytes on the next 32-bit boundary */
nbytes += 3;
nbytes &= ~3;
q = p + (nbytes >> 2);
if (unlikely(q > xdr->end || q < p))
return NULL;
xdr->p = q;
xdr->iov->iov_len += nbytes;
xdr->buf->len += nbytes;
return p;
}
/*
* Initialize an xdr_stream for decoding data.
*/
static inline void
xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p)
{
struct iovec *iov = buf->head;
xdr->buf = buf;
xdr->iov = iov;
xdr->p = p;
xdr->end = (uint32_t *)((char *)iov->iov_base + iov->iov_len);
}
/*
* Check if the input buffer is long enough to enable us to decode
* 'nbytes' more bytes of data starting at the current position.
* If so return the current pointer, then update the current
* position.
*/
static inline uint32_t *
xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
{
uint32_t *p = xdr->p;
uint32_t *q = p + XDR_QUADLEN(nbytes);
if (unlikely(q > xdr->end || q < p))
return NULL;
xdr->p = q;
return p;
}
#endif /* __KERNEL__ */
#endif /* _SUNRPC_XDR_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment