Commit 1bc5ad16 authored by Marcel Holtmann's avatar Marcel Holtmann Committed by Johan Hedberg

Bluetooth: Fix HCI User Channel permission check in hci_sock_sendmsg

The HCI User Channel is an admin operation which enforces CAP_NET_ADMIN
when binding the socket. Problem now is that it then requires also
CAP_NET_RAW when calling into hci_sock_sendmsg. This is not intended
and just an oversight since general HCI sockets (which do not require
special permission to bind) and HCI User Channel share the same code
path here.

Remove the extra CAP_NET_RAW check for HCI User Channel write operation
since the permission check has already been enforced when binding the
socket. This also makes it possible to open HCI User Channel from a
privileged process and then hand the file descriptor to an unprivilged
process.
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
Tested-by: default avatarSamuel Ortiz <sameo@linux.intel.com>
Signed-off-by: default avatarJohan Hedberg <johan.hedberg@intel.com>
parent bd0976dd
......@@ -942,8 +942,22 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
bt_cb(skb)->pkt_type = *((unsigned char *) skb->data);
skb_pull(skb, 1);
if (hci_pi(sk)->channel == HCI_CHANNEL_RAW &&
bt_cb(skb)->pkt_type == HCI_COMMAND_PKT) {
if (hci_pi(sk)->channel == HCI_CHANNEL_USER) {
/* No permission check is needed for user channel
* since that gets enforced when binding the socket.
*
* However check that the packet type is valid.
*/
if (bt_cb(skb)->pkt_type != HCI_COMMAND_PKT &&
bt_cb(skb)->pkt_type != HCI_ACLDATA_PKT &&
bt_cb(skb)->pkt_type != HCI_SCODATA_PKT) {
err = -EINVAL;
goto drop;
}
skb_queue_tail(&hdev->raw_q, skb);
queue_work(hdev->workqueue, &hdev->tx_work);
} else if (bt_cb(skb)->pkt_type == HCI_COMMAND_PKT) {
u16 opcode = get_unaligned_le16(skb->data);
u16 ogf = hci_opcode_ogf(opcode);
u16 ocf = hci_opcode_ocf(opcode);
......@@ -974,14 +988,6 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
goto drop;
}
if (hci_pi(sk)->channel == HCI_CHANNEL_USER &&
bt_cb(skb)->pkt_type != HCI_COMMAND_PKT &&
bt_cb(skb)->pkt_type != HCI_ACLDATA_PKT &&
bt_cb(skb)->pkt_type != HCI_SCODATA_PKT) {
err = -EINVAL;
goto drop;
}
skb_queue_tail(&hdev->raw_q, skb);
queue_work(hdev->workqueue, &hdev->tx_work);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment