APPLIED: [UBUNTU F 1/1] NFSD: Cap rsize_bop result based on send buffer size

Stefan Bader stefan.bader at canonical.com
Fri Dec 16 14:23:10 UTC 2022


On 14.12.22 17:37, Thadeu Lima de Souza Cascardo wrote:
> From: Chuck Lever <chuck.lever at oracle.com>
> 
> Since before the git era, NFSD has conserved the number of pages
> held by each nfsd thread by combining the RPC receive and send
> buffers into a single array of pages. This works because there are
> no cases where an operation needs a large RPC Call message and a
> large RPC Reply at the same time.
> 
> Once an RPC Call has been received, svc_process() updates
> svc_rqst::rq_res to describe the part of rq_pages that can be
> used for constructing the Reply. This means that the send buffer
> (rq_res) shrinks when the received RPC record containing the RPC
> Call is large.
> 
> Add an NFSv4 helper that computes the size of the send buffer. It
> replaces svc_max_payload() in spots where svc_max_payload() returns
> a value that might be larger than the remaining send buffer space.
> Callers who need to know the transport's actual maximum payload size
> will continue to use svc_max_payload().
> 
> Signed-off-by: Chuck Lever <chuck.lever at oracle.com>
> (backported from commit 76ce4dcec0dc08a032db916841ddc4e3998be317)
> CVE-2022-43945
> Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo at canonical.com>
> ---

Applied to focal:linux/master-next. Thanks.

-Stefan

>   fs/nfsd/nfs4proc.c | 35 +++++++++++++++++++++--------------
>   1 file changed, 21 insertions(+), 14 deletions(-)
> 
> diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
> index 452ed633a2c7..cb1b9a10a16c 100644
> --- a/fs/nfsd/nfs4proc.c
> +++ b/fs/nfsd/nfs4proc.c
> @@ -2075,6 +2075,22 @@ nfsd4_proc_compound(struct svc_rqst *rqstp)
>   
>   #define op_encode_channel_attrs_maxsz	(6 + 1 + 1)
>   
> +/*
> + * The _rsize() helpers are invoked by the NFSv4 COMPOUND decoder, which
> + * is called before sunrpc sets rq_res.buflen. Thus we have to compute
> + * the maximum payload size here, based on transport limits and the size
> + * of the remaining space in the rq_pages array.
> + */
> +static u32 nfsd4_max_payload(const struct svc_rqst *rqstp)
> +{
> +	u32 buflen;
> +
> +	buflen = (rqstp->rq_page_end - rqstp->rq_next_page) * PAGE_SIZE;
> +	buflen -= rqstp->rq_auth_slack;
> +	buflen -= rqstp->rq_res.head[0].iov_len;
> +	return min_t(u32, buflen, svc_max_payload(rqstp));
> +}
> +
>   static inline u32 nfsd4_only_status_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
>   {
>   	return (op_encode_hdr_size) * sizeof(__be32);
> @@ -2115,9 +2131,9 @@ static inline u32 nfsd4_getattr_rsize(struct svc_rqst *rqstp,
>   	u32 ret = 0;
>   
>   	if (bmap0 & FATTR4_WORD0_ACL)
> -		return svc_max_payload(rqstp);
> +		return nfsd4_max_payload(rqstp);
>   	if (bmap0 & FATTR4_WORD0_FS_LOCATIONS)
> -		return svc_max_payload(rqstp);
> +		return nfsd4_max_payload(rqstp);
>   
>   	if (bmap1 & FATTR4_WORD1_OWNER) {
>   		ret += IDMAP_NAMESZ + 4;
> @@ -2172,20 +2188,14 @@ static inline u32 nfsd4_open_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
>   
>   static inline u32 nfsd4_read_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
>   {
> -	u32 maxcount = 0, rlen = 0;
> -
> -	maxcount = svc_max_payload(rqstp);
> -	rlen = min(op->u.read.rd_length, maxcount);
> +	u32 rlen = min(op->u.read.rd_length, nfsd4_max_payload(rqstp));
>   
>   	return (op_encode_hdr_size + 2 + XDR_QUADLEN(rlen)) * sizeof(__be32);
>   }
>   
>   static inline u32 nfsd4_readdir_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
>   {
> -	u32 maxcount = 0, rlen = 0;
> -
> -	maxcount = svc_max_payload(rqstp);
> -	rlen = min(op->u.readdir.rd_maxcount, maxcount);
> +	u32 rlen = min(op->u.readdir.rd_maxcount, nfsd4_max_payload(rqstp));
>   
>   	return (op_encode_hdr_size + op_encode_verifier_maxsz +
>   		XDR_QUADLEN(rlen)) * sizeof(__be32);
> @@ -2296,10 +2306,7 @@ static inline u32 nfsd4_offload_status_rsize(struct svc_rqst *rqstp,
>   #ifdef CONFIG_NFSD_PNFS
>   static inline u32 nfsd4_getdeviceinfo_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
>   {
> -	u32 maxcount = 0, rlen = 0;
> -
> -	maxcount = svc_max_payload(rqstp);
> -	rlen = min(op->u.getdeviceinfo.gd_maxcount, maxcount);
> +	u32 rlen = min(op->u.getdeviceinfo.gd_maxcount, nfsd4_max_payload(rqstp));
>   
>   	return (op_encode_hdr_size +
>   		1 /* gd_layout_type*/ +

-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_signature
Type: application/pgp-signature
Size: 833 bytes
Desc: OpenPGP digital signature
URL: <https://lists.ubuntu.com/archives/kernel-team/attachments/20221216/57aa4b7b/attachment.sig>


More information about the kernel-team mailing list