2023-05-10 22:10:53

by Azeem Shaikh

[permalink] [raw]
Subject: [PATCH] NFSD: Replace all non-returning strlcpy with strscpy

strlcpy() reads the entire source buffer first.
This read may exceed the destination size limit.
This is both inefficient and can lead to linear read
overflows if a source string is not NUL-terminated [1].
In an effort to remove strlcpy() completely [2], replace
strlcpy() here with strscpy().
No return values were used, so direct replacement is safe.

[1] https://www.kernel.org/doc/html/latest/process/deprecated.html#strlcpy
[2] https://github.com/KSPP/linux/issues/89

Signed-off-by: Azeem Shaikh <[email protected]>
---
fs/nfsd/trace.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h
index 4183819ea082..9b32cda54808 100644
--- a/fs/nfsd/trace.h
+++ b/fs/nfsd/trace.h
@@ -1370,7 +1370,7 @@ TRACE_EVENT(nfsd_cb_setup,
TP_fast_assign(
__entry->cl_boot = clp->cl_clientid.cl_boot;
__entry->cl_id = clp->cl_clientid.cl_id;
- strlcpy(__entry->netid, netid, sizeof(__entry->netid));
+ strscpy(__entry->netid, netid, sizeof(__entry->netid));
__entry->authflavor = authflavor;
__assign_sockaddr(addr, &clp->cl_cb_conn.cb_addr,
clp->cl_cb_conn.cb_addrlen)



2023-05-11 14:50:40

by Chuck Lever III

[permalink] [raw]
Subject: Re: [PATCH] NFSD: Replace all non-returning strlcpy with strscpy

Hello Azeem -

> On May 10, 2023, at 3:09 PM, Azeem Shaikh <[email protected]> wrote:
>
> strlcpy() reads the entire source buffer first.
> This read may exceed the destination size limit.
> This is both inefficient and can lead to linear read
> overflows if a source string is not NUL-terminated [1].
> In an effort to remove strlcpy() completely [2], replace
> strlcpy() here with strscpy().
> No return values were used, so direct replacement is safe.

Actually netid should use the __string() and __assign_str()
macros rather than open-coding a string copy, I think.


> [1] https://www.kernel.org/doc/html/latest/process/deprecated.html#strlcpy
> [2] https://github.com/KSPP/linux/issues/89
>

I suggest adding:

Fixes: 3c92fba557c6 ("NFSD: Enhance the nfsd_cb_setup tracepoint")

> Signed-off-by: Azeem Shaikh <[email protected]>
> ---
> fs/nfsd/trace.h | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h
> index 4183819ea082..9b32cda54808 100644
> --- a/fs/nfsd/trace.h
> +++ b/fs/nfsd/trace.h
> @@ -1370,7 +1370,7 @@ TRACE_EVENT(nfsd_cb_setup,
> TP_fast_assign(
> __entry->cl_boot = clp->cl_clientid.cl_boot;
> __entry->cl_id = clp->cl_clientid.cl_id;
> - strlcpy(__entry->netid, netid, sizeof(__entry->netid));
> + strscpy(__entry->netid, netid, sizeof(__entry->netid));
> __entry->authflavor = authflavor;
> __assign_sockaddr(addr, &clp->cl_cb_conn.cb_addr,
> clp->cl_cb_conn.cb_addrlen)
>

--
Chuck Lever



2023-05-12 14:34:35

by Azeem Shaikh

[permalink] [raw]
Subject: Re: [PATCH] NFSD: Replace all non-returning strlcpy with strscpy

Thanks Chuck and Kees for the review.

> > Actually netid should use the __string() and __assign_str()
> > macros rather than open-coding a string copy, I think.

Do you mean something like this?

diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h
index 4183819ea082..72a906a053dc 100644
--- a/fs/nfsd/trace.h
+++ b/fs/nfsd/trace.h
@@ -1365,19 +1365,19 @@ TRACE_EVENT(nfsd_cb_setup,
__field(u32, cl_id)
__field(unsigned long, authflavor)
__sockaddr(addr, clp->cl_cb_conn.cb_addrlen)
- __array(unsigned char, netid, 8)
+ __string(netid, netid)
),
TP_fast_assign(
__entry->cl_boot = clp->cl_clientid.cl_boot;
__entry->cl_id = clp->cl_clientid.cl_id;
- strlcpy(__entry->netid, netid, sizeof(__entry->netid));
+ __assign_str(netid, netid);
__entry->authflavor = authflavor;
__assign_sockaddr(addr, &clp->cl_cb_conn.cb_addr,
clp->cl_cb_conn.cb_addrlen)
),
TP_printk("addr=%pISpc client %08x:%08x proto=%s flavor=%s",
__get_sockaddr(addr), __entry->cl_boot, __entry->cl_id,
- __entry->netid, show_nfsd_authflavor(__entry->authflavor))
+ __get_str(netid), show_nfsd_authflavor(__entry->authflavor))
);

> > Fixes: 3c92fba557c6 ("NFSD: Enhance the nfsd_cb_setup tracepoint")

Ack.

2023-05-12 14:43:22

by Chuck Lever III

[permalink] [raw]
Subject: Re: [PATCH] NFSD: Replace all non-returning strlcpy with strscpy



> On May 12, 2023, at 7:30 AM, Azeem Shaikh <[email protected]> wrote:
>
> Thanks Chuck and Kees for the review.
>
>>> Actually netid should use the __string() and __assign_str()
>>> macros rather than open-coding a string copy, I think.
>
> Do you mean something like this?
>
> diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h
> index 4183819ea082..72a906a053dc 100644
> --- a/fs/nfsd/trace.h
> +++ b/fs/nfsd/trace.h
> @@ -1365,19 +1365,19 @@ TRACE_EVENT(nfsd_cb_setup,
> __field(u32, cl_id)
> __field(unsigned long, authflavor)
> __sockaddr(addr, clp->cl_cb_conn.cb_addrlen)
> - __array(unsigned char, netid, 8)
> + __string(netid, netid)
> ),
> TP_fast_assign(
> __entry->cl_boot = clp->cl_clientid.cl_boot;
> __entry->cl_id = clp->cl_clientid.cl_id;
> - strlcpy(__entry->netid, netid, sizeof(__entry->netid));
> + __assign_str(netid, netid);
> __entry->authflavor = authflavor;
> __assign_sockaddr(addr, &clp->cl_cb_conn.cb_addr,
> clp->cl_cb_conn.cb_addrlen)
> ),
> TP_printk("addr=%pISpc client %08x:%08x proto=%s flavor=%s",
> __get_sockaddr(addr), __entry->cl_boot, __entry->cl_id,
> - __entry->netid, show_nfsd_authflavor(__entry->authflavor))
> + __get_str(netid), show_nfsd_authflavor(__entry->authflavor))
> );

Yes. I don't remember why I chose to open-code the string
handling in here.

I agree with Kees, also: __assign_str() needs to handle
the memory accesses properly, and I had assumed it did
that already. My bad. That IMO should be handled as a
separate patch.


>>> Fixes: 3c92fba557c6 ("NFSD: Enhance the nfsd_cb_setup tracepoint")
>
> Ack.

I agree that it's not a high priority backport. However,
I expect those who want to use trace points on KASAN-
enabled stable kernels might prefer to have the
__assign_str fix in place, along with this one.

So, I'm good with including Fixes: or leaving it off. Up
to you!

--
Chuck Lever



2023-05-14 00:52:50

by Steven Rostedt

[permalink] [raw]
Subject: Re: [PATCH] NFSD: Replace all non-returning strlcpy with strscpy

On Thu, 11 May 2023 09:32:31 -0700
Kees Cook <[email protected]> wrote:

> On Thu, May 11, 2023 at 02:47:54PM +0000, Chuck Lever III wrote:
> > Hello Azeem -
> >
> > > On May 10, 2023, at 3:09 PM, Azeem Shaikh <[email protected]> wrote:
> > >
> > > strlcpy() reads the entire source buffer first.
> > > This read may exceed the destination size limit.
> > > This is both inefficient and can lead to linear read
> > > overflows if a source string is not NUL-terminated [1].
> > > In an effort to remove strlcpy() completely [2], replace
> > > strlcpy() here with strscpy().
> > > No return values were used, so direct replacement is safe.
> >
> > Actually netid should use the __string() and __assign_str()
> > macros rather than open-coding a string copy, I think.
>
> Ah, hm, yeah, this is tracing wrappers.
>
> Steve, is there a reason __assign_str() is using "strcpy" and not
> strscpy()?

Yes. Because __assign_str() predates strscpy() ;-)

Note, to use __assign_str(), you first need to do __string(), which
will do (in all that TRACE_EVENT() macro magic):

#undef __dynamic_array
#define __dynamic_array(type, item, len) \
__item_length = (len) * sizeof(type); \
__data_offsets->item = __data_size + \
offsetof(typeof(*entry), __data); \
__data_offsets->item |= __item_length << 16; \
__data_size += __item_length;

#undef __string
#define __string(item, src) __dynamic_array(char, item, \
strlen((src) ? (const char *)(src) : "(null)") + 1)

In order to save a dynamic size string (or array) it must first
calculate that size with a strlen(). If the source is not terminated,
then this will crash there regardless.

The strlen() is to know how much to allocate on the ring buffer, then a
copy is done to copy it. I guess you could be worried about the size
"changing" between the time it is allocated and copied. If that's the
concern then we could do a length copy.

>
> > Fixes: 3c92fba557c6 ("NFSD: Enhance the nfsd_cb_setup tracepoint")
>
> Yeah, that works. I was on the fence about adding Fixes for these kinds
> of refactoring. Like, it's not really _broken_; we're just trying to
> remove the API.
>
> > > Signed-off-by: Azeem Shaikh <[email protected]>
> > > ---
> > > fs/nfsd/trace.h | 2 +-
> > > 1 file changed, 1 insertion(+), 1 deletion(-)
> > >
> > > diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h
> > > index 4183819ea082..9b32cda54808 100644
> > > --- a/fs/nfsd/trace.h
> > > +++ b/fs/nfsd/trace.h
> > > @@ -1370,7 +1370,7 @@ TRACE_EVENT(nfsd_cb_setup,
> > > TP_fast_assign(
> > > __entry->cl_boot = clp->cl_clientid.cl_boot;
> > > __entry->cl_id = clp->cl_clientid.cl_id;
> > > - strlcpy(__entry->netid, netid, sizeof(__entry->netid));
> > > + strscpy(__entry->netid, netid, sizeof(__entry->netid));
> > > __entry->authflavor = authflavor;
> > > __assign_sockaddr(addr, &clp->cl_cb_conn.cb_addr,
> > > clp->cl_cb_conn.cb_addrlen)
>
> Leaving code context for Steve to see...
>

The above isn't __assign_str(). Not exactly sure what you want me to
see here.

-- Steve