Skip to content

Commit

Permalink
rxrpc: Trace protocol errors in received packets
Browse files Browse the repository at this point in the history
Add a tracepoint (rxrpc_rx_proto) to record protocol errors in received
packets.  The following changes are made:

 (1) Add a function, __rxrpc_abort_eproto(), to note a protocol error on a
     call and mark the call aborted.  This is wrapped by
     rxrpc_abort_eproto() that makes the why string usable in trace.

 (2) Add trace_rxrpc_rx_proto() or rxrpc_abort_eproto() to protocol error
     generation points, replacing rxrpc_abort_call() with the latter.

 (3) Only send an abort packet in rxkad_verify_packet*() if we actually
     managed to abort the call.

Note that a trace event is also emitted if a kernel user (e.g. afs) tries
to send data through a call when it's not in the transmission phase, though
it's not technically a receive event.

Signed-off-by: David Howells <[email protected]>
  • Loading branch information
dhowells committed Apr 6, 2017
1 parent ef68622 commit fb46f6e
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 40 deletions.
24 changes: 24 additions & 0 deletions include/trace/events/rxrpc.h
Original file line number Diff line number Diff line change
Expand Up @@ -1087,6 +1087,30 @@ TRACE_EVENT(rxrpc_improper_term,
__entry->abort_code)
);

TRACE_EVENT(rxrpc_rx_eproto,
TP_PROTO(struct rxrpc_call *call, rxrpc_serial_t serial,
const char *why),

TP_ARGS(call, serial, why),

TP_STRUCT__entry(
__field(struct rxrpc_call *, call )
__field(rxrpc_serial_t, serial )
__field(const char *, why )
),

TP_fast_assign(
__entry->call = call;
__entry->serial = serial;
__entry->why = why;
),

TP_printk("c=%p EPROTO %08x %s",
__entry->call,
__entry->serial,
__entry->why)
);

#endif /* _TRACE_RXRPC_H */

/* This part must be outside protection */
Expand Down
19 changes: 19 additions & 0 deletions net/rxrpc/ar-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,25 @@ static inline bool rxrpc_abort_call(const char *why, struct rxrpc_call *call,
return ret;
}

/*
* Abort a call due to a protocol error.
*/
static inline bool __rxrpc_abort_eproto(struct rxrpc_call *call,
struct sk_buff *skb,
const char *eproto_why,
const char *why,
u32 abort_code)
{
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);

trace_rxrpc_rx_eproto(call, sp->hdr.serial, eproto_why);
return rxrpc_abort_call(why, call, sp->hdr.seq, abort_code, -EPROTO);
}

#define rxrpc_abort_eproto(call, skb, eproto_why, abort_why, abort_code) \
__rxrpc_abort_eproto((call), (skb), tracepoint_string(eproto_why), \
(abort_why), (abort_code))

/*
* conn_client.c
*/
Expand Down
9 changes: 6 additions & 3 deletions net/rxrpc/conn_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -281,8 +281,11 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,

case RXRPC_PACKET_TYPE_ABORT:
if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header),
&wtmp, sizeof(wtmp)) < 0)
&wtmp, sizeof(wtmp)) < 0) {
trace_rxrpc_rx_eproto(NULL, sp->hdr.serial,
tracepoint_string("bad_abort"));
return -EPROTO;
}
abort_code = ntohl(wtmp);
_proto("Rx ABORT %%%u { ac=%d }", sp->hdr.serial, abort_code);

Expand Down Expand Up @@ -327,7 +330,8 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
return 0;

default:
_leave(" = -EPROTO [%u]", sp->hdr.type);
trace_rxrpc_rx_eproto(NULL, sp->hdr.serial,
tracepoint_string("bad_conn_pkt"));
return -EPROTO;
}
}
Expand Down Expand Up @@ -422,6 +426,5 @@ void rxrpc_process_connection(struct work_struct *work)
if (rxrpc_abort_connection(conn, ret, abort_code) < 0)
goto requeue_and_leave;
rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
_leave(" [EPROTO]");
goto out;
}
5 changes: 4 additions & 1 deletion net/rxrpc/input.c
Original file line number Diff line number Diff line change
Expand Up @@ -1017,8 +1017,11 @@ int rxrpc_extract_header(struct rxrpc_skb_priv *sp, struct sk_buff *skb)
struct rxrpc_wire_header whdr;

/* dig out the RxRPC connection details */
if (skb_copy_bits(skb, 0, &whdr, sizeof(whdr)) < 0)
if (skb_copy_bits(skb, 0, &whdr, sizeof(whdr)) < 0) {
trace_rxrpc_rx_eproto(NULL, sp->hdr.serial,
tracepoint_string("bad_hdr"));
return -EBADMSG;
}

memset(sp, 0, sizeof(*sp));
sp->hdr.epoch = ntohl(whdr.epoch);
Expand Down
10 changes: 8 additions & 2 deletions net/rxrpc/insecure.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,21 @@ static int none_respond_to_challenge(struct rxrpc_connection *conn,
struct sk_buff *skb,
u32 *_abort_code)
{
*_abort_code = RX_PROTOCOL_ERROR;
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);

trace_rxrpc_rx_eproto(NULL, sp->hdr.serial,
tracepoint_string("chall_none"));
return -EPROTO;
}

static int none_verify_response(struct rxrpc_connection *conn,
struct sk_buff *skb,
u32 *_abort_code)
{
*_abort_code = RX_PROTOCOL_ERROR;
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);

trace_rxrpc_rx_eproto(NULL, sp->hdr.serial,
tracepoint_string("resp_none"));
return -EPROTO;
}

Expand Down
2 changes: 2 additions & 0 deletions net/rxrpc/recvmsg.c
Original file line number Diff line number Diff line change
Expand Up @@ -682,9 +682,11 @@ int rxrpc_kernel_recv_data(struct socket *sock, struct rxrpc_call *call,
return ret;

short_data:
trace_rxrpc_rx_eproto(call, 0, tracepoint_string("short_data"));
ret = -EBADMSG;
goto out;
excess_data:
trace_rxrpc_rx_eproto(call, 0, tracepoint_string("excess_data"));
ret = -EMSGSIZE;
goto out;
call_complete:
Expand Down
Loading

0 comments on commit fb46f6e

Please sign in to comment.