[DTrace-devel] [PATCH] Fix dt_tp_event_info() not to overrun buffer
Kris Van Hees
kris.van.hees at oracle.com
Sat Dec 2 03:02:57 UTC 2023
On Tue, Nov 28, 2023 at 11:48:07PM -0500, eugene.loh at oracle.com wrote:
>
> In dt_tp_event_info(), we read a format file for information about a
> raw tracepoint. In the first pass, we get the event ID and sizing
> information for argument information. In the second pass, we read
> actual argument information. Unfortunately, the way we manipulate
> the buffer, we can overrun the buffer.
>
> Consider this example from OL8, UEK7:
> # dtrace -lvn sdt:rpcrdma::xprtrdma_inline_thresh
> This reads information from
> /sys/kernel/debug/tracing/events/rpcrdma/xprtrdma_inline_thresh/format
> including a line like
> field:unsigned char srcaddr[sizeof(struct sockaddr_in6)];
> offset:24; size:28; signed:0;
> (Here, we wrap the line around, since we are dealing with long line
> lengths.)
>
> Note that "buf" points to the beginning of the line. Then:
> p = strstr(buf, "size:");
> makes "p" point to "size:". Then we have
> sscanf(buf, " field:%[^;]", p);
> which takes the text between "field:" and ";" and writes it to p.
> Well, this is exactly the problem. That text can be long and overwrite
> the rest of the buffer. We end up with
> field:unsigned char srcaddr[sizeof(struct sockaddr_in6)];
> offset:24; unsigned char srcaddr[sizeof(struct sockaddr_in6)]
> which is quite a bit longer than the original line.
See, this is the problem when using C-like languages for too long. I must have
been thinking about another C-like language I have done a lot of work in where
sscanf() does not copy data but rather places the address of the start of the
match in the string argument (along with the match size - it uses strings that
are represented as (address, length) data pairs).
But that is obviously not valid in C. My bad - good catch!
> Fix this. Specifically, once
> p = strstr(buf, "size:");
> has been used, recompute p to point earlier in the buffer. E.g.
> p = strstr(buf, "field:") + strlen("field:");
> will work in place, but the even simpler solution
> p = buf;
> also seems to work and is akin to how we handle "__data_loc".
This commit message is way too verbose for the problem you are addressing
though. It suffices to say that the code is not resetting p to the beginning
of the buffer, and then the patch itself speaks for itself.
> Signed-off-by: Eugene Loh <eugene.loh at oracle.com>
Reviewed-by: Kris Van Hees <kris.van.hees at oracle.com>
... with the commit message changed as stated above.
> ---
> libdtrace/dt_provider_tp.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/libdtrace/dt_provider_tp.c b/libdtrace/dt_provider_tp.c
> index f3e03323..3ded9370 100644
> --- a/libdtrace/dt_provider_tp.c
> +++ b/libdtrace/dt_provider_tp.c
> @@ -196,6 +196,7 @@ dt_tp_event_info(dtrace_hdl_t *dtp, FILE *f, int skip, tp_probe_t *tpp,
> if (p != NULL)
> size = strtol(p + 5, NULL, 10);
>
> + p = buf;
> if (sscanf(buf, " field:%[^;]", p) <= 0)
> continue;
> sscanf(p, "__data_loc %[^;]", p);
> --
> 2.18.4
>
>
More information about the DTrace-devel
mailing list