Commit 498444e3 authored by David S. Miller's avatar David S. Miller
Browse files


Luiz Augusto von Dentz says:

====================
bluetooth pull request for net:

 - Add encryption key size check when acting as peripheral
 - Shut up false-positive build warning
 - Send reject if L2CAP command request is corrupted
 - Fix Use-After-Free in bt_sock_recvmsg
 - Fix not notifying when connection encryption changes
 - Fix not checking if HCI_OP_INQUIRY has been sent
 - Fix address type send over to the MGMT interface
 - Fix deadlock in vhci_send_frame
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 8353c2ab 2e07e834
Loading
Loading
Loading
Loading
+6 −4
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <asm/unaligned.h>

#include <linux/atomic.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -44,6 +45,7 @@ struct vhci_data {
	bool wakeup;
	__u16 msft_opcode;
	bool aosp_capable;
	atomic_t initialized;
};

static int vhci_open_dev(struct hci_dev *hdev)
@@ -75,10 +77,9 @@ static int vhci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)

	memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);

	mutex_lock(&data->open_mutex);
	skb_queue_tail(&data->readq, skb);
	mutex_unlock(&data->open_mutex);

	if (atomic_read(&data->initialized))
		wake_up_interruptible(&data->read_wait);
	return 0;
}
@@ -464,7 +465,8 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode)
	skb_put_u8(skb, 0xff);
	skb_put_u8(skb, opcode);
	put_unaligned_le16(hdev->id, skb_put(skb, 2));
	skb_queue_tail(&data->readq, skb);
	skb_queue_head(&data->readq, skb);
	atomic_inc(&data->initialized);

	wake_up_interruptible(&data->read_wait);
	return 0;
+7 −2
Original line number Diff line number Diff line
@@ -189,6 +189,7 @@ struct blocked_key {
struct smp_csrk {
	bdaddr_t bdaddr;
	u8 bdaddr_type;
	u8 link_type;
	u8 type;
	u8 val[16];
};
@@ -198,6 +199,7 @@ struct smp_ltk {
	struct rcu_head rcu;
	bdaddr_t bdaddr;
	u8 bdaddr_type;
	u8 link_type;
	u8 authenticated;
	u8 type;
	u8 enc_size;
@@ -212,6 +214,7 @@ struct smp_irk {
	bdaddr_t rpa;
	bdaddr_t bdaddr;
	u8 addr_type;
	u8 link_type;
	u8 val[16];
};

@@ -219,6 +222,8 @@ struct link_key {
	struct list_head list;
	struct rcu_head rcu;
	bdaddr_t bdaddr;
	u8 bdaddr_type;
	u8 link_type;
	u8 type;
	u8 val[HCI_LINK_KEY_SIZE];
	u8 pin_len;
@@ -1227,11 +1232,11 @@ static inline struct hci_conn *hci_conn_hash_lookup_cis(struct hci_dev *hdev,
			continue;

		/* Match CIG ID if set */
		if (cig != BT_ISO_QOS_CIG_UNSET && cig != c->iso_qos.ucast.cig)
		if (cig != c->iso_qos.ucast.cig)
			continue;

		/* Match CIS ID if set */
		if (id != BT_ISO_QOS_CIS_UNSET && id != c->iso_qos.ucast.cis)
		if (id != c->iso_qos.ucast.cis)
			continue;

		/* Match destination address if set */
+6 −1
Original line number Diff line number Diff line
@@ -309,11 +309,14 @@ int bt_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
	if (flags & MSG_OOB)
		return -EOPNOTSUPP;

	lock_sock(sk);

	skb = skb_recv_datagram(sk, flags, &err);
	if (!skb) {
		if (sk->sk_shutdown & RCV_SHUTDOWN)
			return 0;
			err = 0;

		release_sock(sk);
		return err;
	}

@@ -343,6 +346,8 @@ int bt_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,

	skb_free_datagram(sk, skb);

	release_sock(sk);

	if (flags & MSG_TRUNC)
		copied = skblen;

+21 −9
Original line number Diff line number Diff line
@@ -516,6 +516,9 @@ static u8 hci_cc_read_class_of_dev(struct hci_dev *hdev, void *data,
{
	struct hci_rp_read_class_of_dev *rp = data;

	if (WARN_ON(!hdev))
		return HCI_ERROR_UNSPECIFIED;

	bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);

	if (rp->status)
@@ -747,9 +750,23 @@ static u8 hci_cc_read_enc_key_size(struct hci_dev *hdev, void *data,
	} else {
		conn->enc_key_size = rp->key_size;
		status = 0;

		if (conn->enc_key_size < hdev->min_enc_key_size) {
			/* As slave role, the conn->state has been set to
			 * BT_CONNECTED and l2cap conn req might not be received
			 * yet, at this moment the l2cap layer almost does
			 * nothing with the non-zero status.
			 * So we also clear encrypt related bits, and then the
			 * handler of l2cap conn req will get the right secure
			 * state at a later time.
			 */
			status = HCI_ERROR_AUTH_FAILURE;
			clear_bit(HCI_CONN_ENCRYPT, &conn->flags);
			clear_bit(HCI_CONN_AES_CCM, &conn->flags);
		}
	}

	hci_encrypt_cfm(conn, 0);
	hci_encrypt_cfm(conn, status);

done:
	hci_dev_unlock(hdev);
@@ -820,8 +837,6 @@ static u8 hci_cc_write_auth_payload_timeout(struct hci_dev *hdev, void *data,
	if (!rp->status)
		conn->auth_payload_timeout = get_unaligned_le16(sent + 2);

	hci_encrypt_cfm(conn, 0);

unlock:
	hci_dev_unlock(hdev);

@@ -2304,6 +2319,7 @@ static void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
		return;
	}

	if (hci_sent_cmd_data(hdev, HCI_OP_INQUIRY))
		set_bit(HCI_INQUIRY, &hdev->flags);
}

@@ -3683,12 +3699,8 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, void *data,
		cp.handle = cpu_to_le16(conn->handle);
		cp.timeout = cpu_to_le16(hdev->auth_payload_timeout);
		if (hci_send_cmd(conn->hdev, HCI_OP_WRITE_AUTH_PAYLOAD_TO,
				 sizeof(cp), &cp)) {
				 sizeof(cp), &cp))
			bt_dev_err(hdev, "write auth payload timeout failed");
			goto notify;
		}

		goto unlock;
	}

notify:
+15 −6
Original line number Diff line number Diff line
@@ -6492,6 +6492,14 @@ static inline void l2cap_le_sig_channel(struct l2cap_conn *conn,
	kfree_skb(skb);
}

static inline void l2cap_sig_send_rej(struct l2cap_conn *conn, u16 ident)
{
	struct l2cap_cmd_rej_unk rej;

	rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
	l2cap_send_cmd(conn, ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
}

static inline void l2cap_sig_channel(struct l2cap_conn *conn,
				     struct sk_buff *skb)
{
@@ -6517,23 +6525,24 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn,

		if (len > skb->len || !cmd->ident) {
			BT_DBG("corrupted command");
			l2cap_sig_send_rej(conn, cmd->ident);
			break;
		}

		err = l2cap_bredr_sig_cmd(conn, cmd, len, skb->data);
		if (err) {
			struct l2cap_cmd_rej_unk rej;

			BT_ERR("Wrong link type (%d)", err);

			rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
			l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
				       sizeof(rej), &rej);
			l2cap_sig_send_rej(conn, cmd->ident);
		}

		skb_pull(skb, len);
	}

	if (skb->len > 0) {
		BT_DBG("corrupted command");
		l2cap_sig_send_rej(conn, 0);
	}

drop:
	kfree_skb(skb);
}
Loading