linux-next: manual merge of the ipvs-next tree with the origin tree

Mark Brown posted 1 patch 2 days, 15 hours ago
linux-next: manual merge of the ipvs-next tree with the origin tree
Posted by Mark Brown 2 days, 15 hours ago
Hi all,

Today's linux-next merge of the ipvs-next tree got a conflict in:

  net/bluetooth/l2cap_core.c

between commit:

  9dbd84990394c5 ("Bluetooth: L2CAP: fix chan ref leak in l2cap_chan_timeout() on !conn")

from the origin tree and commit:

  06528e2f5fc933 ("Bluetooth: L2CAP: Fix UAF in channel timeout by holding conn ref")

from the ipvs-next tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --combined net/bluetooth/l2cap_core.c
index c4ccfbda9d7890,62133eef9d2fea..00000000000000
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@@ -1,3 -1,4 +1,4 @@@
+ // SPDX-License-Identifier: GPL-2.0
  /*
     BlueZ - Bluetooth protocol stack for Linux
     Copyright (C) 2000-2001 Qualcomm Incorporated
@@@ -8,10 -9,6 +9,6 @@@
  
     Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
  
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License version 2 as
-    published by the Free Software Foundation;
- 
     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
@@@ -411,7 -408,7 +408,7 @@@ static void l2cap_chan_timeout(struct w
  
  	BT_DBG("chan %p state %s", chan, state_to_string(chan->state));
  
- 	if (!conn) {
+ 	if (test_bit(FLAG_DEL, &chan->flags)) {
  		l2cap_chan_put(chan);
  		return;
  	}
@@@ -422,6 -419,9 +419,9 @@@
  	 */
  	l2cap_chan_lock(chan);
  
+ 	if (test_bit(FLAG_DEL, &chan->flags))
+ 		goto unlock;
+ 
  	if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
  		reason = ECONNREFUSED;
  	else if (chan->state == BT_CONNECT &&
@@@ -434,10 -434,10 +434,10 @@@
  
  	chan->ops->close(chan);
  
+ unlock:
  	l2cap_chan_unlock(chan);
- 	l2cap_chan_put(chan);
- 
  	mutex_unlock(&conn->lock);
+ 	l2cap_chan_put(chan);
  }
  
  struct l2cap_chan *l2cap_chan_create(void)
@@@ -490,6 -490,9 +490,9 @@@ static void l2cap_chan_destroy(struct k
  	list_del(&chan->global_l);
  	write_unlock(&chan_list_lock);
  
+ 	if (chan->conn)
+ 		l2cap_conn_put(chan->conn);
+ 
  	kfree(chan);
  }
  
@@@ -593,7 -596,7 +596,7 @@@ void __l2cap_chan_add(struct l2cap_con
  
  	conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
  
- 	chan->conn = conn;
+ 	chan->conn = l2cap_conn_get(conn);
  
  	switch (chan->chan_type) {
  	case L2CAP_CHAN_CONN_ORIENTED:
@@@ -648,30 -651,26 +651,26 @@@ void l2cap_chan_add(struct l2cap_conn *
  
  void l2cap_chan_del(struct l2cap_chan *chan, int err)
  {
- 	struct l2cap_conn *conn = chan->conn;
- 
  	__clear_chan_timer(chan);
  
- 	BT_DBG("chan %p, conn %p, err %d, state %s", chan, conn, err,
+ 	BT_DBG("chan %p, err %d, state %s", chan, err,
  	       state_to_string(chan->state));
  
  	chan->ops->teardown(chan, err);
  
- 	if (conn) {
+ 	if (!test_and_set_bit(FLAG_DEL, &chan->flags)) {
  		/* Delete from channel list */
  		list_del(&chan->list);
  
  		l2cap_chan_put(chan);
  
- 		chan->conn = NULL;
- 
  		/* Reference was only held for non-fixed channels or
  		 * fixed channels that explicitly requested it using the
  		 * FLAG_HOLD_HCI_CONN flag.
  		 */
  		if (chan->chan_type != L2CAP_CHAN_FIXED ||
  		    test_bit(FLAG_HOLD_HCI_CONN, &chan->flags))
- 			hci_conn_drop(conn->hcon);
+ 			hci_conn_drop(chan->conn->hcon);
  	}
  
  	if (test_bit(CONF_NOT_COMPLETE, &chan->conf_state))
@@@ -1903,7 -1902,7 +1902,7 @@@ static void l2cap_monitor_timeout(struc
  
  	l2cap_chan_lock(chan);
  
- 	if (!chan->conn) {
+ 	if (test_bit(FLAG_DEL, &chan->flags)) {
  		l2cap_chan_unlock(chan);
  		l2cap_chan_put(chan);
  		return;
@@@ -1924,7 -1923,7 +1923,7 @@@ static void l2cap_retrans_timeout(struc
  
  	l2cap_chan_lock(chan);
  
- 	if (!chan->conn) {
+ 	if (test_bit(FLAG_DEL, &chan->flags)) {
  		l2cap_chan_unlock(chan);
  		l2cap_chan_put(chan);
  		return;
@@@ -2565,7 -2564,7 +2564,7 @@@ int l2cap_chan_send(struct l2cap_chan *
  	int err;
  	struct sk_buff_head seg_queue;
  
- 	if (!chan->conn)
+ 	if (test_bit(FLAG_DEL, &chan->flags))
  		return -ENOTCONN;
  
  	/* Connectionless channel */
@@@ -3160,12 -3159,16 +3159,16 @@@ static void l2cap_ack_timeout(struct wo
  
  	l2cap_chan_lock(chan);
  
+ 	if (test_bit(FLAG_DEL, &chan->flags))
+ 		goto unlock;
+ 
  	frames_to_ack = __seq_offset(chan, chan->buffer_seq,
  				     chan->last_acked_seq);
  
  	if (frames_to_ack)
  		l2cap_send_rr_or_rnr(chan, 0);
  
+ unlock:
  	l2cap_chan_unlock(chan);
  	l2cap_chan_put(chan);
  }
@@@ -7026,6 -7029,11 +7029,11 @@@ static void l2cap_recv_frame(struct l2c
  		break;
  
  	case L2CAP_CID_CONN_LESS:
+ 		if (skb->len < L2CAP_PSMLEN_SIZE) {
+ 			kfree_skb(skb);
+ 			break;
+ 		}
+ 
  		psm = get_unaligned((__le16 *) skb->data);
  		skb_pull(skb, L2CAP_PSMLEN_SIZE);
  		l2cap_conless_channel(conn, psm, skb);