2024-04-01 23:50:45

by Justin Stitt

[permalink] [raw]
Subject: [PATCH] trace: events: cleanup deprecated strncpy uses

strncpy() is deprecated for use on NUL-terminated destination strings
[1] and as such we should prefer more robust and less ambiguous string
interfaces.

For 2 out of 3 of these changes we can simply swap in strscpy() as it
guarantess NUL-termination which is needed for the following trace
print.

trace_rpcgss_context() should use memcpy as its format specifier %.*s
allows for the length to be specifier (__entry->len). Due to this,
acceptor does not technically need to be NUL-terminated. Moreover,
swapping in strscpy() and keeping everything else the same could result
in truncation of the source string by one byte. To remedy this, we could
use `len + 1` but I am unsure of the size of the destination buffer so a
simple memcpy should suffice.
| TP_printk("win_size=%u expiry=%lu now=%lu timeout=%u acceptor=%.*s",
| __entry->window_size, __entry->expiry, __entry->now,
| __entry->timeout, __entry->len, __get_str(acceptor))

I suspect acceptor not to naturally be a NUL-terminated string due to
the presence of some stringify methods.
| .crstringify_acceptor = gss_stringify_acceptor,

Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1]
Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2]
Link: https://github.com/KSPP/linux/issues/90
Cc: [email protected]
Signed-off-by: Justin Stitt <[email protected]>
---
Note: build-tested only.

Found with: $ rg "strncpy\("
---
include/trace/events/mdio.h | 2 +-
include/trace/events/rpcgss.h | 2 +-
include/trace/events/sock.h | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/include/trace/events/mdio.h b/include/trace/events/mdio.h
index 0f241cbe00ab..285b3e4f83ba 100644
--- a/include/trace/events/mdio.h
+++ b/include/trace/events/mdio.h
@@ -25,7 +25,7 @@ TRACE_EVENT_CONDITION(mdio_access,
),

TP_fast_assign(
- strncpy(__entry->busid, bus->id, MII_BUS_ID_SIZE);
+ strscpy(__entry->busid, bus->id, MII_BUS_ID_SIZE);
__entry->read = read;
__entry->addr = addr;
__entry->regnum = regnum;
diff --git a/include/trace/events/rpcgss.h b/include/trace/events/rpcgss.h
index ba2d96a1bc2f..274c297f1b15 100644
--- a/include/trace/events/rpcgss.h
+++ b/include/trace/events/rpcgss.h
@@ -618,7 +618,7 @@ TRACE_EVENT(rpcgss_context,
__entry->timeout = timeout;
__entry->window_size = window_size;
__entry->len = len;
- strncpy(__get_str(acceptor), data, len);
+ memcpy(__get_str(acceptor), data, len);
),

TP_printk("win_size=%u expiry=%lu now=%lu timeout=%u acceptor=%.*s",
diff --git a/include/trace/events/sock.h b/include/trace/events/sock.h
index fd206a6ab5b8..1d0b98e6b2cc 100644
--- a/include/trace/events/sock.h
+++ b/include/trace/events/sock.h
@@ -109,7 +109,7 @@ TRACE_EVENT(sock_exceed_buf_limit,
),

TP_fast_assign(
- strncpy(__entry->name, prot->name, 32);
+ strscpy(__entry->name, prot->name, 32);
__entry->sysctl_mem[0] = READ_ONCE(prot->sysctl_mem[0]);
__entry->sysctl_mem[1] = READ_ONCE(prot->sysctl_mem[1]);
__entry->sysctl_mem[2] = READ_ONCE(prot->sysctl_mem[2]);

---
base-commit: 928a87efa42302a23bb9554be081a28058495f22
change-id: 20240401-strncpy-include-trace-events-mdio-h-0a325676b468

Best regards,
--
Justin Stitt <[email protected]>



2024-04-03 13:36:35

by Chuck Lever

[permalink] [raw]
Subject: Re: [PATCH] trace: events: cleanup deprecated strncpy uses

On Mon, Apr 01, 2024 at 11:48:52PM +0000, Justin Stitt wrote:
> strncpy() is deprecated for use on NUL-terminated destination strings
> [1] and as such we should prefer more robust and less ambiguous string
> interfaces.
>
> For 2 out of 3 of these changes we can simply swap in strscpy() as it
> guarantess NUL-termination which is needed for the following trace
> print.
>
> trace_rpcgss_context() should use memcpy as its format specifier %.*s
> allows for the length to be specifier (__entry->len). Due to this,
> acceptor does not technically need to be NUL-terminated. Moreover,
> swapping in strscpy() and keeping everything else the same could result
> in truncation of the source string by one byte. To remedy this, we could
> use `len + 1` but I am unsure of the size of the destination buffer so a
> simple memcpy should suffice.
> | TP_printk("win_size=%u expiry=%lu now=%lu timeout=%u acceptor=%.*s",
> | __entry->window_size, __entry->expiry, __entry->now,
> | __entry->timeout, __entry->len, __get_str(acceptor))
>
> I suspect acceptor not to naturally be a NUL-terminated string due to
> the presence of some stringify methods.
> | .crstringify_acceptor = gss_stringify_acceptor,
>
> Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1]
> Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2]
> Link: https://github.com/KSPP/linux/issues/90
> Cc: [email protected]
> Signed-off-by: Justin Stitt <[email protected]>
> ---
> Note: build-tested only.
>
> Found with: $ rg "strncpy\("
> ---
> include/trace/events/mdio.h | 2 +-
> include/trace/events/rpcgss.h | 2 +-
> include/trace/events/sock.h | 2 +-
> 3 files changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/include/trace/events/mdio.h b/include/trace/events/mdio.h
> index 0f241cbe00ab..285b3e4f83ba 100644
> --- a/include/trace/events/mdio.h
> +++ b/include/trace/events/mdio.h
> @@ -25,7 +25,7 @@ TRACE_EVENT_CONDITION(mdio_access,
> ),
>
> TP_fast_assign(
> - strncpy(__entry->busid, bus->id, MII_BUS_ID_SIZE);
> + strscpy(__entry->busid, bus->id, MII_BUS_ID_SIZE);
> __entry->read = read;
> __entry->addr = addr;
> __entry->regnum = regnum;
> diff --git a/include/trace/events/rpcgss.h b/include/trace/events/rpcgss.h
> index ba2d96a1bc2f..274c297f1b15 100644
> --- a/include/trace/events/rpcgss.h
> +++ b/include/trace/events/rpcgss.h
> @@ -618,7 +618,7 @@ TRACE_EVENT(rpcgss_context,
> __entry->timeout = timeout;
> __entry->window_size = window_size;
> __entry->len = len;
> - strncpy(__get_str(acceptor), data, len);
> + memcpy(__get_str(acceptor), data, len);
> ),
>
> TP_printk("win_size=%u expiry=%lu now=%lu timeout=%u acceptor=%.*s",
> diff --git a/include/trace/events/sock.h b/include/trace/events/sock.h
> index fd206a6ab5b8..1d0b98e6b2cc 100644
> --- a/include/trace/events/sock.h
> +++ b/include/trace/events/sock.h
> @@ -109,7 +109,7 @@ TRACE_EVENT(sock_exceed_buf_limit,
> ),
>
> TP_fast_assign(
> - strncpy(__entry->name, prot->name, 32);
> + strscpy(__entry->name, prot->name, 32);
> __entry->sysctl_mem[0] = READ_ONCE(prot->sysctl_mem[0]);
> __entry->sysctl_mem[1] = READ_ONCE(prot->sysctl_mem[1]);
> __entry->sysctl_mem[2] = READ_ONCE(prot->sysctl_mem[2]);
>
> ---
> base-commit: 928a87efa42302a23bb9554be081a28058495f22
> change-id: 20240401-strncpy-include-trace-events-mdio-h-0a325676b468
>
> Best regards,
> --
> Justin Stitt <[email protected]>
>

Acked-by: Chuck Lever <[email protected]>


--
Chuck Lever

2024-04-10 15:33:42

by Steven Rostedt

[permalink] [raw]
Subject: Re: [PATCH] trace: events: cleanup deprecated strncpy uses

On Mon, 01 Apr 2024 23:48:52 +0000
Justin Stitt <[email protected]> wrote:

> diff --git a/include/trace/events/rpcgss.h b/include/trace/events/rpcgss.h
> index ba2d96a1bc2f..274c297f1b15 100644
> --- a/include/trace/events/rpcgss.h
> +++ b/include/trace/events/rpcgss.h
> @@ -618,7 +618,7 @@ TRACE_EVENT(rpcgss_context,
> __entry->timeout = timeout;
> __entry->window_size = window_size;
> __entry->len = len;
> - strncpy(__get_str(acceptor), data, len);
> + memcpy(__get_str(acceptor), data, len);
> ),
>
> TP_printk("win_size=%u expiry=%lu now=%lu timeout=%u acceptor=%.*s",

WTF, that code is just buggy. Looking at the rpcgss_context event we have:

> TRACE_EVENT(rpcgss_context,
> TP_PROTO(
> u32 window_size,
> unsigned long expiry,
> unsigned long now,
> unsigned int timeout,
> unsigned int len,
> const u8 *data
> ),
>
> TP_ARGS(window_size, expiry, now, timeout, len, data),
>
> TP_STRUCT__entry(
> __field(unsigned long, expiry)
> __field(unsigned long, now)
> __field(unsigned int, timeout)
> __field(u32, window_size)
> __field(int, len)
> __string(acceptor, data)

The __string() macro expects "data" to be a string and does *not* check
length when copying.

If anything, it needs to be:

__string_len(acceptor, data, len)

as the macro code has changed recently, and the current code will crash!

> ),
>
> TP_fast_assign(
> __entry->expiry = expiry;
> __entry->now = now;
> __entry->timeout = timeout;
> __entry->window_size = window_size;
> __entry->len = len;
> strncpy(__get_str(acceptor), data, len);

Then this needs to be:

__assign_str(acceptor, data);

Note, the length is now saved via __string_len() and not needed here.

I'll go send a patch to fix this.

-- Steve


> ),

2024-04-10 15:42:02

by Chuck Lever

[permalink] [raw]
Subject: Re: [PATCH] trace: events: cleanup deprecated strncpy uses

On Wed, Apr 10, 2024 at 11:36:14AM -0400, Steven Rostedt wrote:
> On Mon, 01 Apr 2024 23:48:52 +0000
> Justin Stitt <[email protected]> wrote:
>
> > diff --git a/include/trace/events/rpcgss.h b/include/trace/events/rpcgss.h
> > index ba2d96a1bc2f..274c297f1b15 100644
> > --- a/include/trace/events/rpcgss.h
> > +++ b/include/trace/events/rpcgss.h
> > @@ -618,7 +618,7 @@ TRACE_EVENT(rpcgss_context,
> > __entry->timeout = timeout;
> > __entry->window_size = window_size;
> > __entry->len = len;
> > - strncpy(__get_str(acceptor), data, len);
> > + memcpy(__get_str(acceptor), data, len);
> > ),
> >
> > TP_printk("win_size=%u expiry=%lu now=%lu timeout=%u acceptor=%.*s",
>
> WTF, that code is just buggy. Looking at the rpcgss_context event we have:
>
> > TRACE_EVENT(rpcgss_context,
> > TP_PROTO(
> > u32 window_size,
> > unsigned long expiry,
> > unsigned long now,
> > unsigned int timeout,
> > unsigned int len,
> > const u8 *data
> > ),
> >
> > TP_ARGS(window_size, expiry, now, timeout, len, data),
> >
> > TP_STRUCT__entry(
> > __field(unsigned long, expiry)
> > __field(unsigned long, now)
> > __field(unsigned int, timeout)
> > __field(u32, window_size)
> > __field(int, len)
> > __string(acceptor, data)
>
> The __string() macro expects "data" to be a string and does *not* check
> length when copying.
>
> If anything, it needs to be:
>
> __string_len(acceptor, data, len)
>
> as the macro code has changed recently, and the current code will crash!

A general question:

Is there a test suite we should run regularly to build some
confidence in the kernel's observability apparatus? We're building
a menagerie of tests around kdevops, and one area where we know
there is a testing gap is the tracepoints in NFSD and SunRPC.


> > ),
> >
> > TP_fast_assign(
> > __entry->expiry = expiry;
> > __entry->now = now;
> > __entry->timeout = timeout;
> > __entry->window_size = window_size;
> > __entry->len = len;
> > strncpy(__get_str(acceptor), data, len);
>
> Then this needs to be:
>
> __assign_str(acceptor, data);
>
> Note, the length is now saved via __string_len() and not needed here.
>
> I'll go send a patch to fix this.
>
> -- Steve
>
>
> > ),

--
Chuck Lever