Commit aee4eda1 authored by David S. Miller's avatar David S. Miller

Merge tag 'rxrpc-fixes-20160809' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs

David Howells says:

====================
rxrpc: Miscellaneous fixes

Here are a bunch of miscellaneous fixes to AF_RXRPC:

 (*) Fix an uninitialised pointer.

 (*) Fix error handling when we fail to connect a call.

 (*) Fix a NULL pointer dereference.

 (*) Fix two occasions where a packet is accessed again after being queued
     for someone else to deal with.

 (*) Fix a missing skb free.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 8971d8e5 992c273a
...@@ -837,6 +837,9 @@ void rxrpc_process_call(struct work_struct *work) ...@@ -837,6 +837,9 @@ void rxrpc_process_call(struct work_struct *work)
return; return;
} }
if (!call->conn)
goto skip_msg_init;
/* there's a good chance we're going to have to send a message, so set /* there's a good chance we're going to have to send a message, so set
* one up in advance */ * one up in advance */
msg.msg_name = &call->conn->params.peer->srx.transport; msg.msg_name = &call->conn->params.peer->srx.transport;
...@@ -859,6 +862,7 @@ void rxrpc_process_call(struct work_struct *work) ...@@ -859,6 +862,7 @@ void rxrpc_process_call(struct work_struct *work)
memset(iov, 0, sizeof(iov)); memset(iov, 0, sizeof(iov));
iov[0].iov_base = &whdr; iov[0].iov_base = &whdr;
iov[0].iov_len = sizeof(whdr); iov[0].iov_len = sizeof(whdr);
skip_msg_init:
/* deal with events of a final nature */ /* deal with events of a final nature */
if (test_bit(RXRPC_CALL_EV_RCVD_ERROR, &call->events)) { if (test_bit(RXRPC_CALL_EV_RCVD_ERROR, &call->events)) {
......
...@@ -275,6 +275,7 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx, ...@@ -275,6 +275,7 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx,
list_del_init(&call->link); list_del_init(&call->link);
write_unlock_bh(&rxrpc_call_lock); write_unlock_bh(&rxrpc_call_lock);
set_bit(RXRPC_CALL_RELEASED, &call->flags);
call->state = RXRPC_CALL_DEAD; call->state = RXRPC_CALL_DEAD;
rxrpc_put_call(call); rxrpc_put_call(call);
_leave(" = %d", ret); _leave(" = %d", ret);
...@@ -287,6 +288,7 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx, ...@@ -287,6 +288,7 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx,
*/ */
found_user_ID_now_present: found_user_ID_now_present:
write_unlock(&rx->call_lock); write_unlock(&rx->call_lock);
set_bit(RXRPC_CALL_RELEASED, &call->flags);
call->state = RXRPC_CALL_DEAD; call->state = RXRPC_CALL_DEAD;
rxrpc_put_call(call); rxrpc_put_call(call);
_leave(" = -EEXIST [%p]", call); _leave(" = -EEXIST [%p]", call);
...@@ -493,6 +495,7 @@ void rxrpc_release_call(struct rxrpc_call *call) ...@@ -493,6 +495,7 @@ void rxrpc_release_call(struct rxrpc_call *call)
(skb = skb_dequeue(&call->rx_oos_queue))) { (skb = skb_dequeue(&call->rx_oos_queue))) {
spin_unlock_bh(&call->lock); spin_unlock_bh(&call->lock);
sp = rxrpc_skb(skb);
_debug("- zap %s %%%u #%u", _debug("- zap %s %%%u #%u",
rxrpc_pkts[sp->hdr.type], rxrpc_pkts[sp->hdr.type],
sp->hdr.serial, sp->hdr.seq); sp->hdr.serial, sp->hdr.seq);
......
...@@ -124,11 +124,15 @@ static int rxrpc_fast_process_data(struct rxrpc_call *call, ...@@ -124,11 +124,15 @@ static int rxrpc_fast_process_data(struct rxrpc_call *call,
struct rxrpc_skb_priv *sp; struct rxrpc_skb_priv *sp;
bool terminal; bool terminal;
int ret, ackbit, ack; int ret, ackbit, ack;
u32 serial;
u8 flags;
_enter("{%u,%u},,{%u}", call->rx_data_post, call->rx_first_oos, seq); _enter("{%u,%u},,{%u}", call->rx_data_post, call->rx_first_oos, seq);
sp = rxrpc_skb(skb); sp = rxrpc_skb(skb);
ASSERTCMP(sp->call, ==, NULL); ASSERTCMP(sp->call, ==, NULL);
flags = sp->hdr.flags;
serial = sp->hdr.serial;
spin_lock(&call->lock); spin_lock(&call->lock);
...@@ -192,8 +196,8 @@ static int rxrpc_fast_process_data(struct rxrpc_call *call, ...@@ -192,8 +196,8 @@ static int rxrpc_fast_process_data(struct rxrpc_call *call,
sp->call = call; sp->call = call;
rxrpc_get_call(call); rxrpc_get_call(call);
atomic_inc(&call->skb_count); atomic_inc(&call->skb_count);
terminal = ((sp->hdr.flags & RXRPC_LAST_PACKET) && terminal = ((flags & RXRPC_LAST_PACKET) &&
!(sp->hdr.flags & RXRPC_CLIENT_INITIATED)); !(flags & RXRPC_CLIENT_INITIATED));
ret = rxrpc_queue_rcv_skb(call, skb, false, terminal); ret = rxrpc_queue_rcv_skb(call, skb, false, terminal);
if (ret < 0) { if (ret < 0) {
if (ret == -ENOMEM || ret == -ENOBUFS) { if (ret == -ENOMEM || ret == -ENOBUFS) {
...@@ -205,12 +209,13 @@ static int rxrpc_fast_process_data(struct rxrpc_call *call, ...@@ -205,12 +209,13 @@ static int rxrpc_fast_process_data(struct rxrpc_call *call,
} }
skb = NULL; skb = NULL;
sp = NULL;
_debug("post #%u", seq); _debug("post #%u", seq);
ASSERTCMP(call->rx_data_post, ==, seq); ASSERTCMP(call->rx_data_post, ==, seq);
call->rx_data_post++; call->rx_data_post++;
if (sp->hdr.flags & RXRPC_LAST_PACKET) if (flags & RXRPC_LAST_PACKET)
set_bit(RXRPC_CALL_RCVD_LAST, &call->flags); set_bit(RXRPC_CALL_RCVD_LAST, &call->flags);
/* if we've reached an out of sequence packet then we need to drain /* if we've reached an out of sequence packet then we need to drain
...@@ -226,7 +231,7 @@ static int rxrpc_fast_process_data(struct rxrpc_call *call, ...@@ -226,7 +231,7 @@ static int rxrpc_fast_process_data(struct rxrpc_call *call,
spin_unlock(&call->lock); spin_unlock(&call->lock);
atomic_inc(&call->ackr_not_idle); atomic_inc(&call->ackr_not_idle);
rxrpc_propose_ACK(call, RXRPC_ACK_DELAY, sp->hdr.serial, false); rxrpc_propose_ACK(call, RXRPC_ACK_DELAY, serial, false);
_leave(" = 0 [posted]"); _leave(" = 0 [posted]");
return 0; return 0;
...@@ -239,7 +244,7 @@ static int rxrpc_fast_process_data(struct rxrpc_call *call, ...@@ -239,7 +244,7 @@ static int rxrpc_fast_process_data(struct rxrpc_call *call,
discard_and_ack: discard_and_ack:
_debug("discard and ACK packet %p", skb); _debug("discard and ACK packet %p", skb);
__rxrpc_propose_ACK(call, ack, sp->hdr.serial, true); __rxrpc_propose_ACK(call, ack, serial, true);
discard: discard:
spin_unlock(&call->lock); spin_unlock(&call->lock);
rxrpc_free_skb(skb); rxrpc_free_skb(skb);
...@@ -247,7 +252,7 @@ static int rxrpc_fast_process_data(struct rxrpc_call *call, ...@@ -247,7 +252,7 @@ static int rxrpc_fast_process_data(struct rxrpc_call *call,
return 0; return 0;
enqueue_and_ack: enqueue_and_ack:
__rxrpc_propose_ACK(call, ack, sp->hdr.serial, true); __rxrpc_propose_ACK(call, ack, serial, true);
enqueue_packet: enqueue_packet:
_net("defer skb %p", skb); _net("defer skb %p", skb);
spin_unlock(&call->lock); spin_unlock(&call->lock);
...@@ -567,13 +572,13 @@ static void rxrpc_post_packet_to_call(struct rxrpc_call *call, ...@@ -567,13 +572,13 @@ static void rxrpc_post_packet_to_call(struct rxrpc_call *call,
* post connection-level events to the connection * post connection-level events to the connection
* - this includes challenges, responses and some aborts * - this includes challenges, responses and some aborts
*/ */
static bool rxrpc_post_packet_to_conn(struct rxrpc_connection *conn, static void rxrpc_post_packet_to_conn(struct rxrpc_connection *conn,
struct sk_buff *skb) struct sk_buff *skb)
{ {
_enter("%p,%p", conn, skb); _enter("%p,%p", conn, skb);
skb_queue_tail(&conn->rx_queue, skb); skb_queue_tail(&conn->rx_queue, skb);
return rxrpc_queue_conn(conn); rxrpc_queue_conn(conn);
} }
/* /*
...@@ -694,7 +699,6 @@ void rxrpc_data_ready(struct sock *sk) ...@@ -694,7 +699,6 @@ void rxrpc_data_ready(struct sock *sk)
rcu_read_lock(); rcu_read_lock();
retry_find_conn:
conn = rxrpc_find_connection_rcu(local, skb); conn = rxrpc_find_connection_rcu(local, skb);
if (!conn) if (!conn)
goto cant_route_call; goto cant_route_call;
...@@ -702,8 +706,7 @@ void rxrpc_data_ready(struct sock *sk) ...@@ -702,8 +706,7 @@ void rxrpc_data_ready(struct sock *sk)
if (sp->hdr.callNumber == 0) { if (sp->hdr.callNumber == 0) {
/* Connection-level packet */ /* Connection-level packet */
_debug("CONN %p {%d}", conn, conn->debug_id); _debug("CONN %p {%d}", conn, conn->debug_id);
if (!rxrpc_post_packet_to_conn(conn, skb)) rxrpc_post_packet_to_conn(conn, skb);
goto retry_find_conn;
} else { } else {
/* Call-bound packets are routed by connection channel. */ /* Call-bound packets are routed by connection channel. */
unsigned int channel = sp->hdr.cid & RXRPC_CHANNELMASK; unsigned int channel = sp->hdr.cid & RXRPC_CHANNELMASK;
...@@ -741,6 +744,8 @@ void rxrpc_data_ready(struct sock *sk) ...@@ -741,6 +744,8 @@ void rxrpc_data_ready(struct sock *sk)
if (sp->hdr.type != RXRPC_PACKET_TYPE_ABORT) { if (sp->hdr.type != RXRPC_PACKET_TYPE_ABORT) {
_debug("reject type %d",sp->hdr.type); _debug("reject type %d",sp->hdr.type);
rxrpc_reject_packet(local, skb); rxrpc_reject_packet(local, skb);
} else {
rxrpc_free_skb(skb);
} }
_leave(" [no call]"); _leave(" [no call]");
return; return;
......
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