Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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


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
Loading
Loading
Loading
Loading
+4 −0
Original line number Original line Diff line number Diff line
@@ -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)
	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)) {
+3 −0
Original line number Original line Diff line number Diff line
@@ -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,
	 */
	 */
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)
		       (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);
+16 −11
Original line number Original line Diff line number Diff line
@@ -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,
	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,
	}
	}


	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,


	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,


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,
	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,
 * 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)


	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)
	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)
	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;