aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2012-02-20 08:50:36 -0500
committerJohan Hedberg <johan.hedberg@intel.com>2012-02-20 08:59:11 -0500
commite0edf3733fb62f91bbb8ec3fab4a90b0ac2dd037 (patch)
tree59e8d01b911454141d53c4e08d9af9ed271abdcf /net
parent7cc2ade2cbc6f71090f0f8d0e11cb68886ddc65e (diff)
Bluetooth: Fix issue with shared SKB between HCI raw socket and driver
Any HCI raw socket gets a copy of each SKB that is either received or send via the Bluetooth subsystem. The raw socket uses SKB clones to send out data, but the problem is that it needs to add an extra packet type byte in front of it. And some drivers need to also add an extra header before submitting the packet. So far this all worked magically fine since all of the drivers and the raw sockets are adding the same byte at the same location. But that is by pure coincidence. Since the data of cloned SKBs is shared, this means that the raw socket and driver kept writing into the shared data area. To fix this the only safe way is if the HCI raw socket creates a copy of the SKB before sending it out. To not always copy all SKBs around, the copy is only created once and only after any of the HCI filter checks succeeded. Signed-off-by: Marcel Holtmann <marcel@holtmann.org> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Diffstat (limited to 'net')
-rw-r--r--net/bluetooth/hci_sock.c18
1 files changed, 14 insertions, 4 deletions
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 4dda4574db3e..cf940bd7a2b0 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -89,6 +89,7 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
89{ 89{
90 struct sock *sk; 90 struct sock *sk;
91 struct hlist_node *node; 91 struct hlist_node *node;
92 struct sk_buff *skb_copy = NULL;
92 93
93 BT_DBG("hdev %p len %d", hdev, skb->len); 94 BT_DBG("hdev %p len %d", hdev, skb->len);
94 95
@@ -131,18 +132,27 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
131 continue; 132 continue;
132 } 133 }
133 134
134 nskb = skb_clone(skb, GFP_ATOMIC); 135 if (!skb_copy) {
136 /* Create a private copy with headroom */
137 skb_copy = __pskb_copy(skb, 1, GFP_ATOMIC);
138 if (!skb_copy)
139 continue;
140
141 /* Put type byte before the data */
142 memcpy(skb_push(skb_copy, 1), &bt_cb(skb)->pkt_type, 1);
143 }
144
145 nskb = skb_clone(skb_copy, GFP_ATOMIC);
135 if (!nskb) 146 if (!nskb)
136 continue; 147 continue;
137 148
138 /* Put type byte before the data */
139 memcpy(skb_push(nskb, 1), &bt_cb(nskb)->pkt_type, 1);
140
141 if (sock_queue_rcv_skb(sk, nskb)) 149 if (sock_queue_rcv_skb(sk, nskb))
142 kfree_skb(nskb); 150 kfree_skb(nskb);
143 } 151 }
144 152
145 read_unlock(&hci_sk_list.lock); 153 read_unlock(&hci_sk_list.lock);
154
155 kfree_skb(skb_copy);
146} 156}
147 157
148/* Send frame to control socket */ 158/* Send frame to control socket */