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

Commit 1c1a551a authored by Allan Stephens's avatar Allan Stephens Committed by Paul Gortmaker
Browse files

tipc: Reject connection protocol message sent to unconnected port



Restructures the logic used in tipc_port_recv_proto_msg() to ensure
that incoming connection protocol messages are handled properly. The
routine now uses a two-stage process that first ensures the message
applies on an existing connection and then processes the request.
This corrects a loophole that allowed a connection probe request to
be processed if it was sent to an unconnected port that had no names
bound to it.

Signed-off-by: default avatarAllan Stephens <allan.stephens@windriver.com>
Signed-off-by: default avatarPaul Gortmaker <paul.gortmaker@windriver.com>
parent e244a915
Loading
Loading
Loading
Loading
+40 −39
Original line number Diff line number Diff line
@@ -526,62 +526,63 @@ static struct sk_buff *port_build_peer_abort_msg(struct tipc_port *p_ptr, u32 er
void tipc_port_recv_proto_msg(struct sk_buff *buf)
{
	struct tipc_msg *msg = buf_msg(buf);
	struct tipc_port *p_ptr = tipc_port_lock(msg_destport(msg));
	u32 err = TIPC_OK;
	struct tipc_port *p_ptr;
	struct sk_buff *r_buf = NULL;
	struct sk_buff *abort_buf = NULL;

	if (!p_ptr) {
		err = TIPC_ERR_NO_PORT;
	} else if (p_ptr->connected) {
		if ((port_peernode(p_ptr) != msg_orignode(msg)) ||
		    (port_peerport(p_ptr) != msg_origport(msg))) {
			err = TIPC_ERR_NO_PORT;
		} else if (msg_type(msg) == CONN_ACK) {
			int wakeup = tipc_port_congested(p_ptr) &&
				     p_ptr->congested &&
				     p_ptr->wakeup;
			p_ptr->acked += msg_msgcnt(msg);
			if (tipc_port_congested(p_ptr))
				goto exit;
			p_ptr->congested = 0;
			if (!wakeup)
				goto exit;
			p_ptr->wakeup(p_ptr);
			goto exit;
		}
	} else if (p_ptr->published) {
		err = TIPC_ERR_NO_PORT;
	}
	if (err) {
		r_buf = port_build_proto_msg(msg_origport(msg),
					     msg_orignode(msg),
					     msg_destport(msg),
	u32 orignode = msg_orignode(msg);
	u32 origport = msg_origport(msg);
	u32 destport = msg_destport(msg);
	int wakeable;

	/* Validate connection */

	p_ptr = tipc_port_lock(destport);
	if (!p_ptr || !p_ptr->connected ||
	    (port_peernode(p_ptr) != orignode) ||
	    (port_peerport(p_ptr) != origport)) {
		r_buf = port_build_proto_msg(origport,
					     orignode,
					     destport,
					     tipc_own_addr,
					     TIPC_HIGH_IMPORTANCE,
					     TIPC_CONN_MSG,
					     err,
					     TIPC_ERR_NO_PORT,
					     0);
		if (p_ptr)
			tipc_port_unlock(p_ptr);
		goto exit;
	}

	/* All is fine */
	if (msg_type(msg) == CONN_PROBE) {
		r_buf = port_build_proto_msg(msg_origport(msg),
					     msg_orignode(msg),
					     msg_destport(msg),
	/* Process protocol message sent by peer */

	switch (msg_type(msg)) {
	case CONN_ACK:
		wakeable = tipc_port_congested(p_ptr) && p_ptr->congested &&
			p_ptr->wakeup;
		p_ptr->acked += msg_msgcnt(msg);
		if (!tipc_port_congested(p_ptr)) {
			p_ptr->congested = 0;
			if (wakeable)
				p_ptr->wakeup(p_ptr);
		}
		break;
	case CONN_PROBE:
		r_buf = port_build_proto_msg(origport,
					     orignode,
					     destport,
					     tipc_own_addr,
					     CONN_MANAGER,
					     CONN_PROBE_REPLY,
					     TIPC_OK,
					     0);
		break;
	default:
		/* CONN_PROBE_REPLY or unrecognized - no action required */
		break;
	}
	p_ptr->probing_state = CONFIRMED;
exit:
	if (p_ptr)
	tipc_port_unlock(p_ptr);
exit:
	tipc_net_route_msg(r_buf);
	tipc_net_route_msg(abort_buf);
	buf_discard(buf);
}