aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/l2cap_sock.c
diff options
context:
space:
mode:
authorDaniel Borkmann <daniel@iogearbox.net>2016-07-27 14:40:14 -0400
committerMarcel Holtmann <marcel@holtmann.org>2016-08-24 10:55:04 -0400
commitdbb50887c8f619fc5c3489783ebc3122bc134a31 (patch)
tree7cb3523007a31596226b2b3e00da1b85f4e1a656 /net/bluetooth/l2cap_sock.c
parent9afee94939e3eda4c8bf239f7727cb56e158c976 (diff)
Bluetooth: split sk_filter in l2cap_sock_recv_cb
During an audit for sk_filter(), we found that rx_busy_skb handling in l2cap_sock_recv_cb() and l2cap_sock_recvmsg() looks not quite as intended. The assumption from commit e328140fdacb ("Bluetooth: Use event-driven approach for handling ERTM receive buffer") is that errors returned from sock_queue_rcv_skb() are due to receive buffer shortage. However, nothing should prevent doing a setsockopt() with SO_ATTACH_FILTER on the socket, that could drop some of the incoming skbs when handled in sock_queue_rcv_skb(). In that case sock_queue_rcv_skb() will return with -EPERM, propagated from sk_filter() and if in L2CAP_MODE_ERTM mode, wrong assumption was that we failed due to receive buffer being full. From that point onwards, due to the to-be-dropped skb being held in rx_busy_skb, we cannot make any forward progress as rx_busy_skb is never cleared from l2cap_sock_recvmsg(), due to the filter drop verdict over and over coming from sk_filter(). Meanwhile, in l2cap_sock_recv_cb() all new incoming skbs are being dropped due to rx_busy_skb being occupied. Instead, just use __sock_queue_rcv_skb() where an error really tells that there's a receive buffer issue. Split the sk_filter() and enable it for non-segmented modes at queuing time since at this point in time the skb has already been through the ERTM state machine and it has been acked, so dropping is not allowed. Instead, for ERTM and streaming mode, call sk_filter() in l2cap_data_rcv() so the packet can be dropped before the state machine sees it. Fixes: e328140fdacb ("Bluetooth: Use event-driven approach for handling ERTM receive buffer") Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Signed-off-by: Mat Martineau <mathew.j.martineau@linux.intel.com> Acked-by: Willem de Bruijn <willemb@google.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/l2cap_sock.c')
-rw-r--r--net/bluetooth/l2cap_sock.c14
1 files changed, 12 insertions, 2 deletions
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 1842141baedb..a8ba752732c9 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -1019,7 +1019,7 @@ static int l2cap_sock_recvmsg(struct socket *sock, struct msghdr *msg,
1019 goto done; 1019 goto done;
1020 1020
1021 if (pi->rx_busy_skb) { 1021 if (pi->rx_busy_skb) {
1022 if (!sock_queue_rcv_skb(sk, pi->rx_busy_skb)) 1022 if (!__sock_queue_rcv_skb(sk, pi->rx_busy_skb))
1023 pi->rx_busy_skb = NULL; 1023 pi->rx_busy_skb = NULL;
1024 else 1024 else
1025 goto done; 1025 goto done;
@@ -1270,7 +1270,17 @@ static int l2cap_sock_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
1270 goto done; 1270 goto done;
1271 } 1271 }
1272 1272
1273 err = sock_queue_rcv_skb(sk, skb); 1273 if (chan->mode != L2CAP_MODE_ERTM &&
1274 chan->mode != L2CAP_MODE_STREAMING) {
1275 /* Even if no filter is attached, we could potentially
1276 * get errors from security modules, etc.
1277 */
1278 err = sk_filter(sk, skb);
1279 if (err)
1280 goto done;
1281 }
1282
1283 err = __sock_queue_rcv_skb(sk, skb);
1274 1284
1275 /* For ERTM, handle one skb that doesn't fit into the recv 1285 /* For ERTM, handle one skb that doesn't fit into the recv
1276 * buffer. This is important to do because the data frames 1286 * buffer. This is important to do because the data frames