rxrpc: Add tracepoint for working out where aborts happen
Add a tracepoint for working out where local aborts happen. Each tracepoint call is labelled with a 3-letter code so that they can be distinguished - and the DATA sequence number is added too where available. rxrpc_kernel_abort_call() also takes a 3-letter code so that AFS can indicate the circumstances when it aborts a call. Signed-off-by: David Howells <dhowells@redhat.com>
This commit is contained in:
Родитель
e8d6bbb05a
Коммит
5a42976d4f
|
@ -377,7 +377,7 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp,
|
||||||
return wait_mode->wait(call);
|
return wait_mode->wait(call);
|
||||||
|
|
||||||
error_do_abort:
|
error_do_abort:
|
||||||
rxrpc_kernel_abort_call(afs_socket, rxcall, RX_USER_ABORT);
|
rxrpc_kernel_abort_call(afs_socket, rxcall, RX_USER_ABORT, -ret, "KSD");
|
||||||
error_kill_call:
|
error_kill_call:
|
||||||
afs_end_call(call);
|
afs_end_call(call);
|
||||||
_leave(" = %d", ret);
|
_leave(" = %d", ret);
|
||||||
|
@ -425,12 +425,12 @@ static void afs_deliver_to_call(struct afs_call *call)
|
||||||
case -ENOTCONN:
|
case -ENOTCONN:
|
||||||
abort_code = RX_CALL_DEAD;
|
abort_code = RX_CALL_DEAD;
|
||||||
rxrpc_kernel_abort_call(afs_socket, call->rxcall,
|
rxrpc_kernel_abort_call(afs_socket, call->rxcall,
|
||||||
abort_code);
|
abort_code, -ret, "KNC");
|
||||||
goto do_abort;
|
goto do_abort;
|
||||||
case -ENOTSUPP:
|
case -ENOTSUPP:
|
||||||
abort_code = RX_INVALID_OPERATION;
|
abort_code = RX_INVALID_OPERATION;
|
||||||
rxrpc_kernel_abort_call(afs_socket, call->rxcall,
|
rxrpc_kernel_abort_call(afs_socket, call->rxcall,
|
||||||
abort_code);
|
abort_code, -ret, "KIV");
|
||||||
goto do_abort;
|
goto do_abort;
|
||||||
case -ENODATA:
|
case -ENODATA:
|
||||||
case -EBADMSG:
|
case -EBADMSG:
|
||||||
|
@ -440,7 +440,7 @@ static void afs_deliver_to_call(struct afs_call *call)
|
||||||
if (call->state != AFS_CALL_AWAIT_REPLY)
|
if (call->state != AFS_CALL_AWAIT_REPLY)
|
||||||
abort_code = RXGEN_SS_UNMARSHAL;
|
abort_code = RXGEN_SS_UNMARSHAL;
|
||||||
rxrpc_kernel_abort_call(afs_socket, call->rxcall,
|
rxrpc_kernel_abort_call(afs_socket, call->rxcall,
|
||||||
abort_code);
|
abort_code, EBADMSG, "KUM");
|
||||||
goto do_abort;
|
goto do_abort;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -463,6 +463,7 @@ do_abort:
|
||||||
*/
|
*/
|
||||||
static int afs_wait_for_call_to_complete(struct afs_call *call)
|
static int afs_wait_for_call_to_complete(struct afs_call *call)
|
||||||
{
|
{
|
||||||
|
const char *abort_why;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
DECLARE_WAITQUEUE(myself, current);
|
DECLARE_WAITQUEUE(myself, current);
|
||||||
|
@ -481,9 +482,11 @@ static int afs_wait_for_call_to_complete(struct afs_call *call)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abort_why = "KWC";
|
||||||
ret = call->error;
|
ret = call->error;
|
||||||
if (call->state == AFS_CALL_COMPLETE)
|
if (call->state == AFS_CALL_COMPLETE)
|
||||||
break;
|
break;
|
||||||
|
abort_why = "KWI";
|
||||||
ret = -EINTR;
|
ret = -EINTR;
|
||||||
if (signal_pending(current))
|
if (signal_pending(current))
|
||||||
break;
|
break;
|
||||||
|
@ -497,7 +500,7 @@ static int afs_wait_for_call_to_complete(struct afs_call *call)
|
||||||
if (call->state < AFS_CALL_COMPLETE) {
|
if (call->state < AFS_CALL_COMPLETE) {
|
||||||
_debug("call incomplete");
|
_debug("call incomplete");
|
||||||
rxrpc_kernel_abort_call(afs_socket, call->rxcall,
|
rxrpc_kernel_abort_call(afs_socket, call->rxcall,
|
||||||
RX_CALL_DEAD);
|
RX_CALL_DEAD, -ret, abort_why);
|
||||||
}
|
}
|
||||||
|
|
||||||
_debug("call complete");
|
_debug("call complete");
|
||||||
|
@ -695,7 +698,7 @@ void afs_send_empty_reply(struct afs_call *call)
|
||||||
case -ENOMEM:
|
case -ENOMEM:
|
||||||
_debug("oom");
|
_debug("oom");
|
||||||
rxrpc_kernel_abort_call(afs_socket, call->rxcall,
|
rxrpc_kernel_abort_call(afs_socket, call->rxcall,
|
||||||
RX_USER_ABORT);
|
RX_USER_ABORT, ENOMEM, "KOO");
|
||||||
default:
|
default:
|
||||||
afs_end_call(call);
|
afs_end_call(call);
|
||||||
_leave(" [error]");
|
_leave(" [error]");
|
||||||
|
@ -734,7 +737,7 @@ void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len)
|
||||||
if (n == -ENOMEM) {
|
if (n == -ENOMEM) {
|
||||||
_debug("oom");
|
_debug("oom");
|
||||||
rxrpc_kernel_abort_call(afs_socket, call->rxcall,
|
rxrpc_kernel_abort_call(afs_socket, call->rxcall,
|
||||||
RX_USER_ABORT);
|
RX_USER_ABORT, ENOMEM, "KOO");
|
||||||
}
|
}
|
||||||
afs_end_call(call);
|
afs_end_call(call);
|
||||||
_leave(" [error]");
|
_leave(" [error]");
|
||||||
|
|
|
@ -35,7 +35,8 @@ int rxrpc_kernel_send_data(struct socket *, struct rxrpc_call *,
|
||||||
struct msghdr *, size_t);
|
struct msghdr *, size_t);
|
||||||
int rxrpc_kernel_recv_data(struct socket *, struct rxrpc_call *,
|
int rxrpc_kernel_recv_data(struct socket *, struct rxrpc_call *,
|
||||||
void *, size_t, size_t *, bool, u32 *);
|
void *, size_t, size_t *, bool, u32 *);
|
||||||
void rxrpc_kernel_abort_call(struct socket *, struct rxrpc_call *, u32);
|
void rxrpc_kernel_abort_call(struct socket *, struct rxrpc_call *,
|
||||||
|
u32, int, const char *);
|
||||||
void rxrpc_kernel_end_call(struct socket *, struct rxrpc_call *);
|
void rxrpc_kernel_end_call(struct socket *, struct rxrpc_call *);
|
||||||
struct rxrpc_call *rxrpc_kernel_accept_call(struct socket *, unsigned long,
|
struct rxrpc_call *rxrpc_kernel_accept_call(struct socket *, unsigned long,
|
||||||
rxrpc_notify_rx_t);
|
rxrpc_notify_rx_t);
|
||||||
|
|
|
@ -84,6 +84,35 @@ TRACE_EVENT(rxrpc_skb,
|
||||||
__entry->where)
|
__entry->where)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
TRACE_EVENT(rxrpc_abort,
|
||||||
|
TP_PROTO(const char *why, u32 cid, u32 call_id, rxrpc_seq_t seq,
|
||||||
|
int abort_code, int error),
|
||||||
|
|
||||||
|
TP_ARGS(why, cid, call_id, seq, abort_code, error),
|
||||||
|
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
__array(char, why, 4 )
|
||||||
|
__field(u32, cid )
|
||||||
|
__field(u32, call_id )
|
||||||
|
__field(rxrpc_seq_t, seq )
|
||||||
|
__field(int, abort_code )
|
||||||
|
__field(int, error )
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_fast_assign(
|
||||||
|
memcpy(__entry->why, why, 4);
|
||||||
|
__entry->cid = cid;
|
||||||
|
__entry->call_id = call_id;
|
||||||
|
__entry->abort_code = abort_code;
|
||||||
|
__entry->error = error;
|
||||||
|
__entry->seq = seq;
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_printk("%08x:%08x s=%u a=%d e=%d %s",
|
||||||
|
__entry->cid, __entry->call_id, __entry->seq,
|
||||||
|
__entry->abort_code, __entry->error, __entry->why)
|
||||||
|
);
|
||||||
|
|
||||||
#endif /* _TRACE_RXRPC_H */
|
#endif /* _TRACE_RXRPC_H */
|
||||||
|
|
||||||
/* This part must be outside protection */
|
/* This part must be outside protection */
|
||||||
|
|
|
@ -155,7 +155,8 @@ struct rxrpc_security {
|
||||||
void *);
|
void *);
|
||||||
|
|
||||||
/* verify the security on a received packet */
|
/* verify the security on a received packet */
|
||||||
int (*verify_packet)(struct rxrpc_call *, struct sk_buff *, u32 *);
|
int (*verify_packet)(struct rxrpc_call *, struct sk_buff *,
|
||||||
|
rxrpc_seq_t, u16);
|
||||||
|
|
||||||
/* issue a challenge */
|
/* issue a challenge */
|
||||||
int (*issue_challenge)(struct rxrpc_connection *);
|
int (*issue_challenge)(struct rxrpc_connection *);
|
||||||
|
@ -637,9 +638,12 @@ static inline bool rxrpc_call_completed(struct rxrpc_call *call)
|
||||||
/*
|
/*
|
||||||
* Record that a call is locally aborted.
|
* Record that a call is locally aborted.
|
||||||
*/
|
*/
|
||||||
static inline bool __rxrpc_abort_call(struct rxrpc_call *call,
|
static inline bool __rxrpc_abort_call(const char *why, struct rxrpc_call *call,
|
||||||
|
rxrpc_seq_t seq,
|
||||||
u32 abort_code, int error)
|
u32 abort_code, int error)
|
||||||
{
|
{
|
||||||
|
trace_rxrpc_abort(why, call->cid, call->call_id, seq,
|
||||||
|
abort_code, error);
|
||||||
if (__rxrpc_set_call_completion(call,
|
if (__rxrpc_set_call_completion(call,
|
||||||
RXRPC_CALL_LOCALLY_ABORTED,
|
RXRPC_CALL_LOCALLY_ABORTED,
|
||||||
abort_code, error)) {
|
abort_code, error)) {
|
||||||
|
@ -649,13 +653,13 @@ static inline bool __rxrpc_abort_call(struct rxrpc_call *call,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool rxrpc_abort_call(struct rxrpc_call *call,
|
static inline bool rxrpc_abort_call(const char *why, struct rxrpc_call *call,
|
||||||
u32 abort_code, int error)
|
rxrpc_seq_t seq, u32 abort_code, int error)
|
||||||
{
|
{
|
||||||
bool ret;
|
bool ret;
|
||||||
|
|
||||||
write_lock_bh(&call->state_lock);
|
write_lock_bh(&call->state_lock);
|
||||||
ret = __rxrpc_abort_call(call, abort_code, error);
|
ret = __rxrpc_abort_call(why, call, seq, abort_code, error);
|
||||||
write_unlock_bh(&call->state_lock);
|
write_unlock_bh(&call->state_lock);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -598,7 +598,8 @@ process_further:
|
||||||
|
|
||||||
/* secured packets must be verified and possibly decrypted */
|
/* secured packets must be verified and possibly decrypted */
|
||||||
if (call->conn->security->verify_packet(call, skb,
|
if (call->conn->security->verify_packet(call, skb,
|
||||||
_abort_code) < 0)
|
sp->hdr.seq,
|
||||||
|
sp->hdr.cksum) < 0)
|
||||||
goto protocol_error;
|
goto protocol_error;
|
||||||
|
|
||||||
rxrpc_insert_oos_packet(call, skb);
|
rxrpc_insert_oos_packet(call, skb);
|
||||||
|
@ -982,7 +983,7 @@ skip_msg_init:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (test_bit(RXRPC_CALL_EV_LIFE_TIMER, &call->events)) {
|
if (test_bit(RXRPC_CALL_EV_LIFE_TIMER, &call->events)) {
|
||||||
rxrpc_abort_call(call, RX_CALL_TIMEOUT, ETIME);
|
rxrpc_abort_call("EXP", call, 0, RX_CALL_TIMEOUT, ETIME);
|
||||||
|
|
||||||
_debug("post timeout");
|
_debug("post timeout");
|
||||||
if (rxrpc_post_message(call, RXRPC_SKB_MARK_LOCAL_ERROR,
|
if (rxrpc_post_message(call, RXRPC_SKB_MARK_LOCAL_ERROR,
|
||||||
|
@ -1005,7 +1006,7 @@ skip_msg_init:
|
||||||
case -EKEYEXPIRED:
|
case -EKEYEXPIRED:
|
||||||
case -EKEYREJECTED:
|
case -EKEYREJECTED:
|
||||||
case -EPROTO:
|
case -EPROTO:
|
||||||
rxrpc_abort_call(call, abort_code, -ret);
|
rxrpc_abort_call("PRO", call, 0, abort_code, -ret);
|
||||||
goto kill_ACKs;
|
goto kill_ACKs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -563,7 +563,7 @@ void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call)
|
||||||
|
|
||||||
if (call->state < RXRPC_CALL_COMPLETE) {
|
if (call->state < RXRPC_CALL_COMPLETE) {
|
||||||
_debug("+++ ABORTING STATE %d +++\n", call->state);
|
_debug("+++ ABORTING STATE %d +++\n", call->state);
|
||||||
__rxrpc_abort_call(call, RX_CALL_DEAD, ECONNRESET);
|
__rxrpc_abort_call("SKT", call, 0, RX_CALL_DEAD, ECONNRESET);
|
||||||
clear_bit(RXRPC_CALL_EV_ACK_FINAL, &call->events);
|
clear_bit(RXRPC_CALL_EV_ACK_FINAL, &call->events);
|
||||||
rxrpc_send_call_packet(call, RXRPC_PACKET_TYPE_ABORT);
|
rxrpc_send_call_packet(call, RXRPC_PACKET_TYPE_ABORT);
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,6 +158,11 @@ static void rxrpc_abort_calls(struct rxrpc_connection *conn,
|
||||||
lockdep_is_held(&conn->channel_lock));
|
lockdep_is_held(&conn->channel_lock));
|
||||||
if (call) {
|
if (call) {
|
||||||
rxrpc_see_call(call);
|
rxrpc_see_call(call);
|
||||||
|
if (compl == RXRPC_CALL_LOCALLY_ABORTED)
|
||||||
|
trace_rxrpc_abort("CON", call->cid,
|
||||||
|
call->call_id, 0,
|
||||||
|
abort_code, error);
|
||||||
|
|
||||||
write_lock_bh(&call->state_lock);
|
write_lock_bh(&call->state_lock);
|
||||||
if (rxrpc_set_call_completion(call, compl, abort_code,
|
if (rxrpc_set_call_completion(call, compl, abort_code,
|
||||||
error)) {
|
error)) {
|
||||||
|
@ -167,6 +172,7 @@ static void rxrpc_abort_calls(struct rxrpc_connection *conn,
|
||||||
write_unlock_bh(&call->state_lock);
|
write_unlock_bh(&call->state_lock);
|
||||||
if (queue)
|
if (queue)
|
||||||
rxrpc_queue_call(call);
|
rxrpc_queue_call(call);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -429,7 +429,7 @@ protocol_error:
|
||||||
_debug("protocol error");
|
_debug("protocol error");
|
||||||
write_lock_bh(&call->state_lock);
|
write_lock_bh(&call->state_lock);
|
||||||
protocol_error_locked:
|
protocol_error_locked:
|
||||||
if (__rxrpc_abort_call(call, RX_PROTOCOL_ERROR, EPROTO))
|
if (__rxrpc_abort_call("FPR", call, 0, RX_PROTOCOL_ERROR, EPROTO))
|
||||||
rxrpc_queue_call(call);
|
rxrpc_queue_call(call);
|
||||||
free_packet_unlock:
|
free_packet_unlock:
|
||||||
write_unlock_bh(&call->state_lock);
|
write_unlock_bh(&call->state_lock);
|
||||||
|
@ -495,9 +495,10 @@ static void rxrpc_process_jumbo_packet(struct rxrpc_call *call,
|
||||||
protocol_error:
|
protocol_error:
|
||||||
_debug("protocol error");
|
_debug("protocol error");
|
||||||
rxrpc_free_skb(part);
|
rxrpc_free_skb(part);
|
||||||
rxrpc_free_skb(jumbo);
|
if (rxrpc_abort_call("PJP", call, sp->hdr.seq,
|
||||||
if (rxrpc_abort_call(call, RX_PROTOCOL_ERROR, EPROTO))
|
RX_PROTOCOL_ERROR, EPROTO))
|
||||||
rxrpc_queue_call(call);
|
rxrpc_queue_call(call);
|
||||||
|
rxrpc_free_skb(jumbo);
|
||||||
_leave("");
|
_leave("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,31 +23,32 @@ static int none_prime_packet_security(struct rxrpc_connection *conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int none_secure_packet(struct rxrpc_call *call,
|
static int none_secure_packet(struct rxrpc_call *call,
|
||||||
struct sk_buff *skb,
|
struct sk_buff *skb,
|
||||||
size_t data_size,
|
size_t data_size,
|
||||||
void *sechdr)
|
void *sechdr)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int none_verify_packet(struct rxrpc_call *call,
|
static int none_verify_packet(struct rxrpc_call *call,
|
||||||
struct sk_buff *skb,
|
struct sk_buff *skb,
|
||||||
u32 *_abort_code)
|
rxrpc_seq_t seq,
|
||||||
|
u16 expected_cksum)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int none_respond_to_challenge(struct rxrpc_connection *conn,
|
static int none_respond_to_challenge(struct rxrpc_connection *conn,
|
||||||
struct sk_buff *skb,
|
struct sk_buff *skb,
|
||||||
u32 *_abort_code)
|
u32 *_abort_code)
|
||||||
{
|
{
|
||||||
*_abort_code = RX_PROTOCOL_ERROR;
|
*_abort_code = RX_PROTOCOL_ERROR;
|
||||||
return -EPROTO;
|
return -EPROTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int none_verify_response(struct rxrpc_connection *conn,
|
static int none_verify_response(struct rxrpc_connection *conn,
|
||||||
struct sk_buff *skb,
|
struct sk_buff *skb,
|
||||||
u32 *_abort_code)
|
u32 *_abort_code)
|
||||||
{
|
{
|
||||||
*_abort_code = RX_PROTOCOL_ERROR;
|
*_abort_code = RX_PROTOCOL_ERROR;
|
||||||
return -EPROTO;
|
return -EPROTO;
|
||||||
|
|
|
@ -316,12 +316,10 @@ static int rxkad_secure_packet(struct rxrpc_call *call,
|
||||||
/*
|
/*
|
||||||
* decrypt partial encryption on a packet (level 1 security)
|
* decrypt partial encryption on a packet (level 1 security)
|
||||||
*/
|
*/
|
||||||
static int rxkad_verify_packet_auth(const struct rxrpc_call *call,
|
static int rxkad_verify_packet_1(struct rxrpc_call *call, struct sk_buff *skb,
|
||||||
struct sk_buff *skb,
|
rxrpc_seq_t seq)
|
||||||
u32 *_abort_code)
|
|
||||||
{
|
{
|
||||||
struct rxkad_level1_hdr sechdr;
|
struct rxkad_level1_hdr sechdr;
|
||||||
struct rxrpc_skb_priv *sp;
|
|
||||||
SKCIPHER_REQUEST_ON_STACK(req, call->conn->cipher);
|
SKCIPHER_REQUEST_ON_STACK(req, call->conn->cipher);
|
||||||
struct rxrpc_crypt iv;
|
struct rxrpc_crypt iv;
|
||||||
struct scatterlist sg[16];
|
struct scatterlist sg[16];
|
||||||
|
@ -332,7 +330,10 @@ static int rxkad_verify_packet_auth(const struct rxrpc_call *call,
|
||||||
|
|
||||||
_enter("");
|
_enter("");
|
||||||
|
|
||||||
sp = rxrpc_skb(skb);
|
if (skb->len < 8) {
|
||||||
|
rxrpc_abort_call("V1H", call, seq, RXKADSEALEDINCON, EPROTO);
|
||||||
|
goto protocol_error;
|
||||||
|
}
|
||||||
|
|
||||||
/* we want to decrypt the skbuff in-place */
|
/* we want to decrypt the skbuff in-place */
|
||||||
nsg = skb_cow_data(skb, 0, &trailer);
|
nsg = skb_cow_data(skb, 0, &trailer);
|
||||||
|
@ -351,9 +352,11 @@ static int rxkad_verify_packet_auth(const struct rxrpc_call *call,
|
||||||
crypto_skcipher_decrypt(req);
|
crypto_skcipher_decrypt(req);
|
||||||
skcipher_request_zero(req);
|
skcipher_request_zero(req);
|
||||||
|
|
||||||
/* remove the decrypted packet length */
|
/* Extract the decrypted packet length */
|
||||||
if (skb_copy_bits(skb, 0, &sechdr, sizeof(sechdr)) < 0)
|
if (skb_copy_bits(skb, 0, &sechdr, sizeof(sechdr)) < 0) {
|
||||||
goto datalen_error;
|
rxrpc_abort_call("XV1", call, seq, RXKADDATALEN, EPROTO);
|
||||||
|
goto protocol_error;
|
||||||
|
}
|
||||||
if (!skb_pull(skb, sizeof(sechdr)))
|
if (!skb_pull(skb, sizeof(sechdr)))
|
||||||
BUG();
|
BUG();
|
||||||
|
|
||||||
|
@ -361,24 +364,24 @@ static int rxkad_verify_packet_auth(const struct rxrpc_call *call,
|
||||||
data_size = buf & 0xffff;
|
data_size = buf & 0xffff;
|
||||||
|
|
||||||
check = buf >> 16;
|
check = buf >> 16;
|
||||||
check ^= sp->hdr.seq ^ sp->hdr.callNumber;
|
check ^= seq ^ call->call_id;
|
||||||
check &= 0xffff;
|
check &= 0xffff;
|
||||||
if (check != 0) {
|
if (check != 0) {
|
||||||
*_abort_code = RXKADSEALEDINCON;
|
rxrpc_abort_call("V1C", call, seq, RXKADSEALEDINCON, EPROTO);
|
||||||
goto protocol_error;
|
goto protocol_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* shorten the packet to remove the padding */
|
/* shorten the packet to remove the padding */
|
||||||
if (data_size > skb->len)
|
if (data_size > skb->len) {
|
||||||
goto datalen_error;
|
rxrpc_abort_call("V1L", call, seq, RXKADDATALEN, EPROTO);
|
||||||
else if (data_size < skb->len)
|
goto protocol_error;
|
||||||
|
}
|
||||||
|
if (data_size < skb->len)
|
||||||
skb->len = data_size;
|
skb->len = data_size;
|
||||||
|
|
||||||
_leave(" = 0 [dlen=%x]", data_size);
|
_leave(" = 0 [dlen=%x]", data_size);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
datalen_error:
|
|
||||||
*_abort_code = RXKADDATALEN;
|
|
||||||
protocol_error:
|
protocol_error:
|
||||||
_leave(" = -EPROTO");
|
_leave(" = -EPROTO");
|
||||||
return -EPROTO;
|
return -EPROTO;
|
||||||
|
@ -391,13 +394,11 @@ nomem:
|
||||||
/*
|
/*
|
||||||
* wholly decrypt a packet (level 2 security)
|
* wholly decrypt a packet (level 2 security)
|
||||||
*/
|
*/
|
||||||
static int rxkad_verify_packet_encrypt(const struct rxrpc_call *call,
|
static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb,
|
||||||
struct sk_buff *skb,
|
rxrpc_seq_t seq)
|
||||||
u32 *_abort_code)
|
|
||||||
{
|
{
|
||||||
const struct rxrpc_key_token *token;
|
const struct rxrpc_key_token *token;
|
||||||
struct rxkad_level2_hdr sechdr;
|
struct rxkad_level2_hdr sechdr;
|
||||||
struct rxrpc_skb_priv *sp;
|
|
||||||
SKCIPHER_REQUEST_ON_STACK(req, call->conn->cipher);
|
SKCIPHER_REQUEST_ON_STACK(req, call->conn->cipher);
|
||||||
struct rxrpc_crypt iv;
|
struct rxrpc_crypt iv;
|
||||||
struct scatterlist _sg[4], *sg;
|
struct scatterlist _sg[4], *sg;
|
||||||
|
@ -408,7 +409,10 @@ static int rxkad_verify_packet_encrypt(const struct rxrpc_call *call,
|
||||||
|
|
||||||
_enter(",{%d}", skb->len);
|
_enter(",{%d}", skb->len);
|
||||||
|
|
||||||
sp = rxrpc_skb(skb);
|
if (skb->len < 8) {
|
||||||
|
rxrpc_abort_call("V2H", call, seq, RXKADSEALEDINCON, EPROTO);
|
||||||
|
goto protocol_error;
|
||||||
|
}
|
||||||
|
|
||||||
/* we want to decrypt the skbuff in-place */
|
/* we want to decrypt the skbuff in-place */
|
||||||
nsg = skb_cow_data(skb, 0, &trailer);
|
nsg = skb_cow_data(skb, 0, &trailer);
|
||||||
|
@ -437,9 +441,11 @@ static int rxkad_verify_packet_encrypt(const struct rxrpc_call *call,
|
||||||
if (sg != _sg)
|
if (sg != _sg)
|
||||||
kfree(sg);
|
kfree(sg);
|
||||||
|
|
||||||
/* remove the decrypted packet length */
|
/* Extract the decrypted packet length */
|
||||||
if (skb_copy_bits(skb, 0, &sechdr, sizeof(sechdr)) < 0)
|
if (skb_copy_bits(skb, 0, &sechdr, sizeof(sechdr)) < 0) {
|
||||||
goto datalen_error;
|
rxrpc_abort_call("XV2", call, seq, RXKADDATALEN, EPROTO);
|
||||||
|
goto protocol_error;
|
||||||
|
}
|
||||||
if (!skb_pull(skb, sizeof(sechdr)))
|
if (!skb_pull(skb, sizeof(sechdr)))
|
||||||
BUG();
|
BUG();
|
||||||
|
|
||||||
|
@ -447,24 +453,23 @@ static int rxkad_verify_packet_encrypt(const struct rxrpc_call *call,
|
||||||
data_size = buf & 0xffff;
|
data_size = buf & 0xffff;
|
||||||
|
|
||||||
check = buf >> 16;
|
check = buf >> 16;
|
||||||
check ^= sp->hdr.seq ^ sp->hdr.callNumber;
|
check ^= seq ^ call->call_id;
|
||||||
check &= 0xffff;
|
check &= 0xffff;
|
||||||
if (check != 0) {
|
if (check != 0) {
|
||||||
*_abort_code = RXKADSEALEDINCON;
|
rxrpc_abort_call("V2C", call, seq, RXKADSEALEDINCON, EPROTO);
|
||||||
goto protocol_error;
|
goto protocol_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* shorten the packet to remove the padding */
|
if (data_size > skb->len) {
|
||||||
if (data_size > skb->len)
|
rxrpc_abort_call("V2L", call, seq, RXKADDATALEN, EPROTO);
|
||||||
goto datalen_error;
|
goto protocol_error;
|
||||||
else if (data_size < skb->len)
|
}
|
||||||
|
if (data_size < skb->len)
|
||||||
skb->len = data_size;
|
skb->len = data_size;
|
||||||
|
|
||||||
_leave(" = 0 [dlen=%x]", data_size);
|
_leave(" = 0 [dlen=%x]", data_size);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
datalen_error:
|
|
||||||
*_abort_code = RXKADDATALEN;
|
|
||||||
protocol_error:
|
protocol_error:
|
||||||
_leave(" = -EPROTO");
|
_leave(" = -EPROTO");
|
||||||
return -EPROTO;
|
return -EPROTO;
|
||||||
|
@ -475,40 +480,30 @@ nomem:
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* verify the security on a received packet
|
* Verify the security on a received packet or subpacket (if part of a
|
||||||
|
* jumbo packet).
|
||||||
*/
|
*/
|
||||||
static int rxkad_verify_packet(struct rxrpc_call *call,
|
static int rxkad_verify_packet(struct rxrpc_call *call, struct sk_buff *skb,
|
||||||
struct sk_buff *skb,
|
rxrpc_seq_t seq, u16 expected_cksum)
|
||||||
u32 *_abort_code)
|
|
||||||
{
|
{
|
||||||
SKCIPHER_REQUEST_ON_STACK(req, call->conn->cipher);
|
SKCIPHER_REQUEST_ON_STACK(req, call->conn->cipher);
|
||||||
struct rxrpc_skb_priv *sp;
|
|
||||||
struct rxrpc_crypt iv;
|
struct rxrpc_crypt iv;
|
||||||
struct scatterlist sg;
|
struct scatterlist sg;
|
||||||
u16 cksum;
|
u16 cksum;
|
||||||
u32 x, y;
|
u32 x, y;
|
||||||
int ret;
|
|
||||||
|
|
||||||
sp = rxrpc_skb(skb);
|
|
||||||
|
|
||||||
_enter("{%d{%x}},{#%u}",
|
_enter("{%d{%x}},{#%u}",
|
||||||
call->debug_id, key_serial(call->conn->params.key), sp->hdr.seq);
|
call->debug_id, key_serial(call->conn->params.key), seq);
|
||||||
|
|
||||||
if (!call->conn->cipher)
|
if (!call->conn->cipher)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (sp->hdr.securityIndex != RXRPC_SECURITY_RXKAD) {
|
|
||||||
*_abort_code = RXKADINCONSISTENCY;
|
|
||||||
_leave(" = -EPROTO [not rxkad]");
|
|
||||||
return -EPROTO;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* continue encrypting from where we left off */
|
/* continue encrypting from where we left off */
|
||||||
memcpy(&iv, call->conn->csum_iv.x, sizeof(iv));
|
memcpy(&iv, call->conn->csum_iv.x, sizeof(iv));
|
||||||
|
|
||||||
/* validate the security checksum */
|
/* validate the security checksum */
|
||||||
x = (call->cid & RXRPC_CHANNELMASK) << (32 - RXRPC_CIDSHIFT);
|
x = (call->cid & RXRPC_CHANNELMASK) << (32 - RXRPC_CIDSHIFT);
|
||||||
x |= sp->hdr.seq & 0x3fffffff;
|
x |= seq & 0x3fffffff;
|
||||||
call->crypto_buf[0] = htonl(call->call_id);
|
call->crypto_buf[0] = htonl(call->call_id);
|
||||||
call->crypto_buf[1] = htonl(x);
|
call->crypto_buf[1] = htonl(x);
|
||||||
|
|
||||||
|
@ -524,29 +519,22 @@ static int rxkad_verify_packet(struct rxrpc_call *call,
|
||||||
if (cksum == 0)
|
if (cksum == 0)
|
||||||
cksum = 1; /* zero checksums are not permitted */
|
cksum = 1; /* zero checksums are not permitted */
|
||||||
|
|
||||||
if (sp->hdr.cksum != cksum) {
|
if (cksum != expected_cksum) {
|
||||||
*_abort_code = RXKADSEALEDINCON;
|
rxrpc_abort_call("VCK", call, seq, RXKADSEALEDINCON, EPROTO);
|
||||||
_leave(" = -EPROTO [csum failed]");
|
_leave(" = -EPROTO [csum failed]");
|
||||||
return -EPROTO;
|
return -EPROTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (call->conn->params.security_level) {
|
switch (call->conn->params.security_level) {
|
||||||
case RXRPC_SECURITY_PLAIN:
|
case RXRPC_SECURITY_PLAIN:
|
||||||
ret = 0;
|
return 0;
|
||||||
break;
|
|
||||||
case RXRPC_SECURITY_AUTH:
|
case RXRPC_SECURITY_AUTH:
|
||||||
ret = rxkad_verify_packet_auth(call, skb, _abort_code);
|
return rxkad_verify_packet_1(call, skb, seq);
|
||||||
break;
|
|
||||||
case RXRPC_SECURITY_ENCRYPT:
|
case RXRPC_SECURITY_ENCRYPT:
|
||||||
ret = rxkad_verify_packet_encrypt(call, skb, _abort_code);
|
return rxkad_verify_packet_2(call, skb, seq);
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
ret = -ENOANO;
|
return -ENOANO;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_leave(" = %d", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -454,14 +454,15 @@ static int rxrpc_sendmsg_cmsg(struct msghdr *msg,
|
||||||
/*
|
/*
|
||||||
* abort a call, sending an ABORT packet to the peer
|
* abort a call, sending an ABORT packet to the peer
|
||||||
*/
|
*/
|
||||||
static void rxrpc_send_abort(struct rxrpc_call *call, u32 abort_code)
|
static void rxrpc_send_abort(struct rxrpc_call *call, const char *why,
|
||||||
|
u32 abort_code, int error)
|
||||||
{
|
{
|
||||||
if (call->state >= RXRPC_CALL_COMPLETE)
|
if (call->state >= RXRPC_CALL_COMPLETE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
write_lock_bh(&call->state_lock);
|
write_lock_bh(&call->state_lock);
|
||||||
|
|
||||||
if (__rxrpc_abort_call(call, abort_code, ECONNABORTED)) {
|
if (__rxrpc_abort_call(why, call, 0, abort_code, error)) {
|
||||||
del_timer_sync(&call->resend_timer);
|
del_timer_sync(&call->resend_timer);
|
||||||
del_timer_sync(&call->ack_timer);
|
del_timer_sync(&call->ack_timer);
|
||||||
clear_bit(RXRPC_CALL_EV_RESEND_TIMER, &call->events);
|
clear_bit(RXRPC_CALL_EV_RESEND_TIMER, &call->events);
|
||||||
|
@ -556,7 +557,7 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
|
||||||
/* it's too late for this call */
|
/* it's too late for this call */
|
||||||
ret = -ESHUTDOWN;
|
ret = -ESHUTDOWN;
|
||||||
} else if (cmd == RXRPC_CMD_SEND_ABORT) {
|
} else if (cmd == RXRPC_CMD_SEND_ABORT) {
|
||||||
rxrpc_send_abort(call, abort_code);
|
rxrpc_send_abort(call, "CMD", abort_code, ECONNABORTED);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
} else if (cmd != RXRPC_CMD_SEND_DATA) {
|
} else if (cmd != RXRPC_CMD_SEND_DATA) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
|
@ -626,20 +627,19 @@ EXPORT_SYMBOL(rxrpc_kernel_send_data);
|
||||||
* @sock: The socket the call is on
|
* @sock: The socket the call is on
|
||||||
* @call: The call to be aborted
|
* @call: The call to be aborted
|
||||||
* @abort_code: The abort code to stick into the ABORT packet
|
* @abort_code: The abort code to stick into the ABORT packet
|
||||||
|
* @error: Local error value
|
||||||
|
* @why: 3-char string indicating why.
|
||||||
*
|
*
|
||||||
* Allow a kernel service to abort a call, if it's still in an abortable state.
|
* Allow a kernel service to abort a call, if it's still in an abortable state.
|
||||||
*/
|
*/
|
||||||
void rxrpc_kernel_abort_call(struct socket *sock, struct rxrpc_call *call,
|
void rxrpc_kernel_abort_call(struct socket *sock, struct rxrpc_call *call,
|
||||||
u32 abort_code)
|
u32 abort_code, int error, const char *why)
|
||||||
{
|
{
|
||||||
_enter("{%d},%d", call->debug_id, abort_code);
|
_enter("{%d},%d,%d,%s", call->debug_id, abort_code, error, why);
|
||||||
|
|
||||||
lock_sock(sock->sk);
|
lock_sock(sock->sk);
|
||||||
|
|
||||||
_debug("CALL %d USR %lx ST %d on CONN %p",
|
rxrpc_send_abort(call, why, abort_code, error);
|
||||||
call->debug_id, call->user_call_ID, call->state, call->conn);
|
|
||||||
|
|
||||||
rxrpc_send_abort(call, abort_code);
|
|
||||||
|
|
||||||
release_sock(sock->sk);
|
release_sock(sock->sk);
|
||||||
_leave("");
|
_leave("");
|
||||||
|
|
Загрузка…
Ссылка в новой задаче