Commit 4d500445 authored by Chuck Lever's avatar Chuck Lever

SUNRPC: Fix the svc_deferred_event trace class

Fix a NULL deref crash that occurs when an svc_rqst is deferred
while the sunrpc tracing subsystem is enabled. svc_revisit() sets
dr->xprt to NULL, so it can't be relied upon in the tracepoint to
provide the remote's address.

Unfortunately we can't revert the "svc_deferred_class" hunk in
commit ece200dd ("sunrpc: Save remote presentation address in
svc_xprt for trace events") because there is now a specific check
of event format specifiers for unsafe dereferences. The warning
that check emits is:

  event svc_defer_recv has unsafe dereference of argument 1

A "%pISpc" format specifier with a "struct sockaddr *" is indeed
flagged by this check.

Instead, take the brute-force approach used by the svcrdma_qp_error
tracepoint. Convert the dr::addr field into a presentation address
in the TP_fast_assign() arm of the trace event, and store that as
a string. This fix can be backported to -stable kernels.

In the meantime, commit c6ced229 ("tracing: Update print fmt
check to handle new __get_sockaddr() macro") is now in v5.18, so
this wonky fix can be replaced with __sockaddr() and friends
properly during the v5.19 merge window.

Fixes: ece200dd ("sunrpc: Save remote presentation address in svc_xprt for trace events")
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
parent 773f91b2
...@@ -2017,17 +2017,18 @@ DECLARE_EVENT_CLASS(svc_deferred_event, ...@@ -2017,17 +2017,18 @@ DECLARE_EVENT_CLASS(svc_deferred_event,
TP_STRUCT__entry( TP_STRUCT__entry(
__field(const void *, dr) __field(const void *, dr)
__field(u32, xid) __field(u32, xid)
__string(addr, dr->xprt->xpt_remotebuf) __array(__u8, addr, INET6_ADDRSTRLEN + 10)
), ),
TP_fast_assign( TP_fast_assign(
__entry->dr = dr; __entry->dr = dr;
__entry->xid = be32_to_cpu(*(__be32 *)(dr->args + __entry->xid = be32_to_cpu(*(__be32 *)(dr->args +
(dr->xprt_hlen>>2))); (dr->xprt_hlen>>2)));
__assign_str(addr, dr->xprt->xpt_remotebuf); snprintf(__entry->addr, sizeof(__entry->addr) - 1,
"%pISpc", (struct sockaddr *)&dr->addr);
), ),
TP_printk("addr=%s dr=%p xid=0x%08x", __get_str(addr), __entry->dr, TP_printk("addr=%s dr=%p xid=0x%08x", __entry->addr, __entry->dr,
__entry->xid) __entry->xid)
); );
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment