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

Commit d2a50842 authored by Chris Lew's avatar Chris Lew
Browse files

net: qrtr: Prevent stale ports from sending



The current implementation of the control port bind releases and
reacquires the port lock between allocating the port idr and resetting
the existing sockets. This creates a race condition where sockets
can send to the control port during the control port bind. Hold the
lock for the duration of the control port bind to prevent this.

In order to prevent messages from stale sockets being sent, check if
ENETRESET has been set on the socket and drop the packet.

Change-Id: Ie9abc6c51139e82d3c9ebd4d546d1acd7269875e
Signed-off-by: default avatarChris Lew <clew@codeaurora.org>
parent 0d116bcb
Loading
Loading
Loading
Loading
+18 −10
Original line number Diff line number Diff line
@@ -757,7 +757,6 @@ static int qrtr_port_assign(struct qrtr_sock *ipc, int *port)
{
	int rc;

	mutex_lock(&qrtr_port_lock);
	if (!*port) {
		rc = idr_alloc_cyclic(&qrtr_ports, ipc, QRTR_MIN_EPH_SOCKET,
				      QRTR_MAX_EPH_SOCKET + 1, GFP_ATOMIC);
@@ -773,7 +772,6 @@ static int qrtr_port_assign(struct qrtr_sock *ipc, int *port)
		if (rc >= 0)
			*port = rc;
	}
	mutex_unlock(&qrtr_port_lock);

	if (rc == -ENOSPC)
		return -EADDRINUSE;
@@ -791,7 +789,6 @@ static void qrtr_reset_ports(void)
	struct qrtr_sock *ipc;
	int id;

	mutex_lock(&qrtr_port_lock);
	idr_for_each_entry(&qrtr_ports, ipc, id) {
		/* Don't reset control port */
		if (id == 0)
@@ -802,7 +799,6 @@ static void qrtr_reset_ports(void)
		ipc->sk.sk_error_report(&ipc->sk);
		sock_put(&ipc->sk);
	}
	mutex_unlock(&qrtr_port_lock);
}

/* Bind socket to address.
@@ -821,22 +817,24 @@ static int __qrtr_bind(struct socket *sock,
	if (!zapped && addr->sq_port == ipc->us.sq_port)
		return 0;

	mutex_lock(&qrtr_port_lock);
	port = addr->sq_port;
	rc = qrtr_port_assign(ipc, &port);
	if (rc)
	if (rc) {
		mutex_unlock(&qrtr_port_lock);
		return rc;
	}
	/* Notify all open ports about the new controller */
	if (port == QRTR_PORT_CTRL)
		qrtr_reset_ports();
	mutex_unlock(&qrtr_port_lock);

	/* unbind previous, if any */
	if (!zapped)
		qrtr_port_remove(ipc);
	ipc->us.sq_port = port;

	sock_reset_flag(sk, SOCK_ZAPPED);

	/* Notify all open ports about the new controller */
	if (port == QRTR_PORT_CTRL)
		qrtr_reset_ports();

	return 0;
}

@@ -884,12 +882,22 @@ static int qrtr_local_enqueue(struct qrtr_node *node, struct sk_buff *skb,
{
	struct qrtr_sock *ipc;
	struct qrtr_cb *cb;
	struct sock *sk = skb->sk;

	ipc = qrtr_port_lookup(to->sq_port);
	if (!ipc || &ipc->sk == skb->sk) { /* do not send to self */
		kfree_skb(skb);
		return -ENODEV;
	}
	/* Keep resetting NETRESET until socket is closed */
	if (sk && sk->sk_err == ENETRESET) {
		sock_hold(sk);
		sk->sk_err = ENETRESET;
		sk->sk_error_report(sk);
		sock_put(sk);
		kfree_skb(skb);
		return 0;
	}

	cb = (struct qrtr_cb *)skb->cb;
	cb->src_node = from->sq_node;