Skip to content

Commit e53f529

Browse files
committed
Merge tag 'for-net-2022-07-26' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth
Luiz Augusto von Dentz says: ==================== bluetooth pull request for net: - Fix early wakeup after suspend - Fix double free on error - Fix use-after-free on l2cap_chan_put * tag 'for-net-2022-07-26' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth: Bluetooth: L2CAP: Fix use-after-free caused by l2cap_chan_put Bluetooth: Always set event mask on suspend Bluetooth: mgmt: Fix double free on error path ==================== Link: https://lore.kernel.org/r/20220726221328.423714-1-luiz.dentz@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2 parents aa40d5a + d0be834 commit e53f529

File tree

4 files changed

+52
-17
lines changed

4 files changed

+52
-17
lines changed

include/net/bluetooth/l2cap.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -847,6 +847,7 @@ enum {
847847
};
848848

849849
void l2cap_chan_hold(struct l2cap_chan *c);
850+
struct l2cap_chan *l2cap_chan_hold_unless_zero(struct l2cap_chan *c);
850851
void l2cap_chan_put(struct l2cap_chan *c);
851852

852853
static inline void l2cap_chan_lock(struct l2cap_chan *chan)

net/bluetooth/hci_sync.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4973,6 +4973,9 @@ int hci_suspend_sync(struct hci_dev *hdev)
49734973
return err;
49744974
}
49754975

4976+
/* Update event mask so only the allowed event can wakeup the host */
4977+
hci_set_event_mask_sync(hdev);
4978+
49764979
/* Only configure accept list if disconnect succeeded and wake
49774980
* isn't being prevented.
49784981
*/
@@ -4984,9 +4987,6 @@ int hci_suspend_sync(struct hci_dev *hdev)
49844987
/* Unpause to take care of updating scanning params */
49854988
hdev->scanning_paused = false;
49864989

4987-
/* Update event mask so only the allowed event can wakeup the host */
4988-
hci_set_event_mask_sync(hdev);
4989-
49904990
/* Enable event filter for paired devices */
49914991
hci_update_event_filter_sync(hdev);
49924992

net/bluetooth/l2cap_core.c

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -111,23 +111,28 @@ static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn,
111111
}
112112

113113
/* Find channel with given SCID.
114-
* Returns locked channel. */
114+
* Returns a reference locked channel.
115+
*/
115116
static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn,
116117
u16 cid)
117118
{
118119
struct l2cap_chan *c;
119120

120121
mutex_lock(&conn->chan_lock);
121122
c = __l2cap_get_chan_by_scid(conn, cid);
122-
if (c)
123-
l2cap_chan_lock(c);
123+
if (c) {
124+
/* Only lock if chan reference is not 0 */
125+
c = l2cap_chan_hold_unless_zero(c);
126+
if (c)
127+
l2cap_chan_lock(c);
128+
}
124129
mutex_unlock(&conn->chan_lock);
125130

126131
return c;
127132
}
128133

129134
/* Find channel with given DCID.
130-
* Returns locked channel.
135+
* Returns a reference locked channel.
131136
*/
132137
static struct l2cap_chan *l2cap_get_chan_by_dcid(struct l2cap_conn *conn,
133138
u16 cid)
@@ -136,8 +141,12 @@ static struct l2cap_chan *l2cap_get_chan_by_dcid(struct l2cap_conn *conn,
136141

137142
mutex_lock(&conn->chan_lock);
138143
c = __l2cap_get_chan_by_dcid(conn, cid);
139-
if (c)
140-
l2cap_chan_lock(c);
144+
if (c) {
145+
/* Only lock if chan reference is not 0 */
146+
c = l2cap_chan_hold_unless_zero(c);
147+
if (c)
148+
l2cap_chan_lock(c);
149+
}
141150
mutex_unlock(&conn->chan_lock);
142151

143152
return c;
@@ -162,8 +171,12 @@ static struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn,
162171

163172
mutex_lock(&conn->chan_lock);
164173
c = __l2cap_get_chan_by_ident(conn, ident);
165-
if (c)
166-
l2cap_chan_lock(c);
174+
if (c) {
175+
/* Only lock if chan reference is not 0 */
176+
c = l2cap_chan_hold_unless_zero(c);
177+
if (c)
178+
l2cap_chan_lock(c);
179+
}
167180
mutex_unlock(&conn->chan_lock);
168181

169182
return c;
@@ -497,6 +510,16 @@ void l2cap_chan_hold(struct l2cap_chan *c)
497510
kref_get(&c->kref);
498511
}
499512

513+
struct l2cap_chan *l2cap_chan_hold_unless_zero(struct l2cap_chan *c)
514+
{
515+
BT_DBG("chan %p orig refcnt %u", c, kref_read(&c->kref));
516+
517+
if (!kref_get_unless_zero(&c->kref))
518+
return NULL;
519+
520+
return c;
521+
}
522+
500523
void l2cap_chan_put(struct l2cap_chan *c)
501524
{
502525
BT_DBG("chan %p orig refcnt %u", c, kref_read(&c->kref));
@@ -1968,7 +1991,10 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm,
19681991
src_match = !bacmp(&c->src, src);
19691992
dst_match = !bacmp(&c->dst, dst);
19701993
if (src_match && dst_match) {
1971-
l2cap_chan_hold(c);
1994+
c = l2cap_chan_hold_unless_zero(c);
1995+
if (!c)
1996+
continue;
1997+
19721998
read_unlock(&chan_list_lock);
19731999
return c;
19742000
}
@@ -1983,7 +2009,7 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm,
19832009
}
19842010

19852011
if (c1)
1986-
l2cap_chan_hold(c1);
2012+
c1 = l2cap_chan_hold_unless_zero(c1);
19872013

19882014
read_unlock(&chan_list_lock);
19892015

@@ -4463,6 +4489,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
44634489

44644490
unlock:
44654491
l2cap_chan_unlock(chan);
4492+
l2cap_chan_put(chan);
44664493
return err;
44674494
}
44684495

@@ -4577,6 +4604,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
45774604

45784605
done:
45794606
l2cap_chan_unlock(chan);
4607+
l2cap_chan_put(chan);
45804608
return err;
45814609
}
45824610

@@ -5304,6 +5332,7 @@ static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
53045332
l2cap_send_move_chan_rsp(chan, result);
53055333

53065334
l2cap_chan_unlock(chan);
5335+
l2cap_chan_put(chan);
53075336

53085337
return 0;
53095338
}
@@ -5396,6 +5425,7 @@ static void l2cap_move_continue(struct l2cap_conn *conn, u16 icid, u16 result)
53965425
}
53975426

53985427
l2cap_chan_unlock(chan);
5428+
l2cap_chan_put(chan);
53995429
}
54005430

54015431
static void l2cap_move_fail(struct l2cap_conn *conn, u8 ident, u16 icid,
@@ -5425,6 +5455,7 @@ static void l2cap_move_fail(struct l2cap_conn *conn, u8 ident, u16 icid,
54255455
l2cap_send_move_chan_cfm(chan, L2CAP_MC_UNCONFIRMED);
54265456

54275457
l2cap_chan_unlock(chan);
5458+
l2cap_chan_put(chan);
54285459
}
54295460

54305461
static int l2cap_move_channel_rsp(struct l2cap_conn *conn,
@@ -5488,6 +5519,7 @@ static int l2cap_move_channel_confirm(struct l2cap_conn *conn,
54885519
l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid);
54895520

54905521
l2cap_chan_unlock(chan);
5522+
l2cap_chan_put(chan);
54915523

54925524
return 0;
54935525
}
@@ -5523,6 +5555,7 @@ static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
55235555
}
55245556

55255557
l2cap_chan_unlock(chan);
5558+
l2cap_chan_put(chan);
55265559

55275560
return 0;
55285561
}
@@ -5895,12 +5928,11 @@ static inline int l2cap_le_credits(struct l2cap_conn *conn,
58955928
if (credits > max_credits) {
58965929
BT_ERR("LE credits overflow");
58975930
l2cap_send_disconn_req(chan, ECONNRESET);
5898-
l2cap_chan_unlock(chan);
58995931

59005932
/* Return 0 so that we don't trigger an unnecessary
59015933
* command reject packet.
59025934
*/
5903-
return 0;
5935+
goto unlock;
59045936
}
59055937

59065938
chan->tx_credits += credits;
@@ -5911,7 +5943,9 @@ static inline int l2cap_le_credits(struct l2cap_conn *conn,
59115943
if (chan->tx_credits)
59125944
chan->ops->resume(chan);
59135945

5946+
unlock:
59145947
l2cap_chan_unlock(chan);
5948+
l2cap_chan_put(chan);
59155949

59165950
return 0;
59175951
}
@@ -7597,6 +7631,7 @@ static void l2cap_data_channel(struct l2cap_conn *conn, u16 cid,
75977631

75987632
done:
75997633
l2cap_chan_unlock(chan);
7634+
l2cap_chan_put(chan);
76007635
}
76017636

76027637
static void l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm,
@@ -8085,7 +8120,7 @@ static struct l2cap_chan *l2cap_global_fixed_chan(struct l2cap_chan *c,
80858120
if (src_type != c->src_type)
80868121
continue;
80878122

8088-
l2cap_chan_hold(c);
8123+
c = l2cap_chan_hold_unless_zero(c);
80898124
read_unlock(&chan_list_lock);
80908125
return c;
80918126
}

net/bluetooth/mgmt.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4723,7 +4723,6 @@ static int __add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
47234723
else
47244724
status = MGMT_STATUS_FAILED;
47254725

4726-
mgmt_pending_remove(cmd);
47274726
goto unlock;
47284727
}
47294728

0 commit comments

Comments
 (0)