Bluetooth: SCO: Fix UAF on sco_sock_timeout
conn->sk maybe have been unlinked/freed while waiting for sco_conn_lock
so this checks if the conn->sk is still valid by checking if it part of
sco_sk_list.
Reported-by: syzbot+4c0d0c4cde787116d465@syzkaller.appspotmail.com
Tested-by: syzbot+4c0d0c4cde787116d465@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=4c0d0c4cde787116d465
Fixes: ba316be1b6
("Bluetooth: schedule SCO timeouts with delayed_work")
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
parent
989fa5171f
commit
1bf4470a39
@ -403,6 +403,7 @@ int bt_sock_register(int proto, const struct net_proto_family *ops);
|
||||
void bt_sock_unregister(int proto);
|
||||
void bt_sock_link(struct bt_sock_list *l, struct sock *s);
|
||||
void bt_sock_unlink(struct bt_sock_list *l, struct sock *s);
|
||||
bool bt_sock_linked(struct bt_sock_list *l, struct sock *s);
|
||||
struct sock *bt_sock_alloc(struct net *net, struct socket *sock,
|
||||
struct proto *prot, int proto, gfp_t prio, int kern);
|
||||
int bt_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
|
||||
|
@ -185,6 +185,28 @@ void bt_sock_unlink(struct bt_sock_list *l, struct sock *sk)
|
||||
}
|
||||
EXPORT_SYMBOL(bt_sock_unlink);
|
||||
|
||||
bool bt_sock_linked(struct bt_sock_list *l, struct sock *s)
|
||||
{
|
||||
struct sock *sk;
|
||||
|
||||
if (!l || !s)
|
||||
return false;
|
||||
|
||||
read_lock(&l->lock);
|
||||
|
||||
sk_for_each(sk, &l->head) {
|
||||
if (s == sk) {
|
||||
read_unlock(&l->lock);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
read_unlock(&l->lock);
|
||||
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL(bt_sock_linked);
|
||||
|
||||
void bt_accept_enqueue(struct sock *parent, struct sock *sk, bool bh)
|
||||
{
|
||||
const struct cred *old_cred;
|
||||
|
@ -76,6 +76,16 @@ struct sco_pinfo {
|
||||
#define SCO_CONN_TIMEOUT (HZ * 40)
|
||||
#define SCO_DISCONN_TIMEOUT (HZ * 2)
|
||||
|
||||
static struct sock *sco_sock_hold(struct sco_conn *conn)
|
||||
{
|
||||
if (!conn || !bt_sock_linked(&sco_sk_list, conn->sk))
|
||||
return NULL;
|
||||
|
||||
sock_hold(conn->sk);
|
||||
|
||||
return conn->sk;
|
||||
}
|
||||
|
||||
static void sco_sock_timeout(struct work_struct *work)
|
||||
{
|
||||
struct sco_conn *conn = container_of(work, struct sco_conn,
|
||||
@ -87,9 +97,7 @@ static void sco_sock_timeout(struct work_struct *work)
|
||||
sco_conn_unlock(conn);
|
||||
return;
|
||||
}
|
||||
sk = conn->sk;
|
||||
if (sk)
|
||||
sock_hold(sk);
|
||||
sk = sco_sock_hold(conn);
|
||||
sco_conn_unlock(conn);
|
||||
|
||||
if (!sk)
|
||||
@ -194,9 +202,7 @@ static void sco_conn_del(struct hci_conn *hcon, int err)
|
||||
|
||||
/* Kill socket */
|
||||
sco_conn_lock(conn);
|
||||
sk = conn->sk;
|
||||
if (sk)
|
||||
sock_hold(sk);
|
||||
sk = sco_sock_hold(conn);
|
||||
sco_conn_unlock(conn);
|
||||
|
||||
if (sk) {
|
||||
|
Loading…
Reference in New Issue
Block a user