On Mon, May 01, 2023 at 02:05:35AM +0800, Ruihan Li wrote: > The hci_conn_unlink function is being called by hci_conn_del, which means > it should not call hci_conn_del with the input parameter conn again. If it > does, conn may have already been released when hci_conn_unlink returns, > leading to potential UAF and double-free issues. > > This patch resolves the problem by modifying hci_conn_unlink to release > only conn's child links when necessary, but never release conn itself. Syzbot also found this bug several days ago (but it does not email linux-bluetooth until today). Reported-by: syzbot+690b90b14f14f43f4688@xxxxxxxxxxxxxxxxxxxxxxxxx Closes: https://syzkaller.appspot.com/bug?extid=690b90b14f14f43f4688 > Fixes: 06149746e720 ("Bluetooth: hci_conn: Add support for linking multiple hcon") > Signed-off-by: Ruihan Li <lrh2000@xxxxxxxxxx> > --- > Changes since v1: > * CI complains that there are some merge conflicts. This is because > void hci_conn_del(struct hci_conn *conn) > this completely unrelated line makes the patch dependent on another fix: > https://lore.kernel.org/linux-bluetooth/20230430171847.156825-1-lrh2000@xxxxxxxxxx/ > But actually, deleting that line makes the two patches independent of > each other, and everything still works. > > net/bluetooth/hci_conn.c | 21 ++++++++++++--------- > 1 file changed, 12 insertions(+), 9 deletions(-) > > diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c > index 85c34c837..5f388202f 100644 > --- a/net/bluetooth/hci_conn.c > +++ b/net/bluetooth/hci_conn.c > @@ -1083,8 +1083,18 @@ static void hci_conn_unlink(struct hci_conn *conn) > if (!conn->parent) { > struct hci_link *link, *t; > > - list_for_each_entry_safe(link, t, &conn->link_list, list) > - hci_conn_unlink(link->conn); > + list_for_each_entry_safe(link, t, &conn->link_list, list) { > + struct hci_conn *child = link->conn; > + > + hci_conn_unlink(child); > + > + /* Due to race, SCO connection might be not established > + * yet at this point. Delete it now, otherwise it is > + * possible for it to be stuck and can't be deleted. > + */ > + if (child->handle == HCI_CONN_HANDLE_UNSET) > + hci_conn_del(child); > + } > > return; > } > @@ -1100,12 +1110,5 @@ static void hci_conn_unlink(struct hci_conn *conn) > > kfree(conn->link); > conn->link = NULL; > - > - /* Due to race, SCO connection might be not established > - * yet at this point. Delete it now, otherwise it is > - * possible for it to be stuck and can't be deleted. > - */ > - if (conn->handle == HCI_CONN_HANDLE_UNSET) > - hci_conn_del(conn); > } > > -- > 2.40.0 Thanks, Ruihan Li