Re: [PATCH V2] SUNRPC: Fix a potential buffer overflow in 'svc_print_xprts()'

From: Chuck Lever
Date: Fri Mar 27 2020 - 12:34:04 EST




> On Mar 27, 2020, at 12:15 PM, Christophe JAILLET <christophe.jaillet@xxxxxxxxxx> wrote:
>
> 'maxlen' is the total size of the destination buffer. There is only one
> caller and this value is 256.
>
> When we compute the size already used and what we would like to add in
> the buffer, the trailling NULL character is not taken into account.
> However, this trailling character will be added by the 'strcat' once we
> have checked that we have enough place.
>
> So, there is a off-by-one issue and 1 byte of the stack could be
> erroneously overwridden.
>
> Take into account the trailling NULL, when checking if there is enough
> place in the destination buffer.
>
>
> While at it, also replace a 'sprintf' by a safer 'snprintf', check for
> output truncation and avoid a superfluous 'strlen'.
>
> Fixes: dc9a16e49dbba ("svc: Add /proc/sys/sunrpc/transport files")
> Signed-off-by: Christophe JAILLET <christophe.jaillet@xxxxxxxxxx>
> ---
> V2: add a doxygen comment to clarify the goal of the function
> merge previous 2 patches into a single one
> keep strcat for clarity, this function being just a slow path anyway
>
> Doc being most of the time a matter of taste, please adjust the description
> as needed.

I've applied this to my local nfsd-5.7 with a very small adjustment
to the doc-comment. Testing it now. Thanks, all.


> ---
> net/sunrpc/svc_xprt.c | 19 ++++++++++++++-----
> 1 file changed, 14 insertions(+), 5 deletions(-)
>
> diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
> index de3c077733a7..e0f61a8c1965 100644
> --- a/net/sunrpc/svc_xprt.c
> +++ b/net/sunrpc/svc_xprt.c
> @@ -104,8 +104,17 @@ void svc_unreg_xprt_class(struct svc_xprt_class *xcl)
> }
> EXPORT_SYMBOL_GPL(svc_unreg_xprt_class);
>
> -/*
> - * Format the transport list for printing
> +/**
> + * svc_print_xprts - Format the transport list for printing
> + * @buf: target buffer for formatted address
> + * @maxlen: length of target buffer
> + *
> + * Fills in @buf with a string containing a list of transport names, each name
> + * terminated with '\n'. If the buffer is too small, some entries may be
> + * missing, but it is guaranteed that the line in the output buffer are
> + * complete.
> + *
> + * Returns positive length of the filled-in string.
> */
> int svc_print_xprts(char *buf, int maxlen)
> {
> @@ -118,9 +127,9 @@ int svc_print_xprts(char *buf, int maxlen)
> list_for_each_entry(xcl, &svc_xprt_class_list, xcl_list) {
> int slen;
>
> - sprintf(tmpstr, "%s %d\n", xcl->xcl_name, xcl->xcl_max_payload);
> - slen = strlen(tmpstr);
> - if (len + slen > maxlen)
> + slen = snprintf(tmpstr, sizeof(tmpstr), "%s %d\n",
> + xcl->xcl_name, xcl->xcl_max_payload);
> + if (slen >= sizeof(tmpstr) || len + slen >= maxlen)
> break;
> len += slen;
> strcat(buf, tmpstr);
> --
> 2.20.1
>

--
Chuck Lever