From dccb90df2d3fa9e4ac08b7e91f9e900273bbedef Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 21 Nov 2002 19:08:38 -0800 Subject: [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. --- include/linux/nfs_xdr.h | 4 +++ include/linux/sunrpc/xdr.h | 87 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) (limited to 'include') diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 6c82048e2acf..970ffa785f78 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -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; }; diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index 0233988f40b4..74c5260b2343 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -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_ */ -- cgit v1.2.3