Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit d01cb2da authored by Alexander Grund's avatar Alexander Grund
Browse files

Bluetooth: fix kernel oops in store_pending_adv_report

Fix kernel oops observed when an ext adv data is larger than 31 bytes.

This can be reproduced by setting up an advertiser with advertisement
larger than 31 bytes.  The issue is not sensitive to the advertisement
content.  In particular, this was reproduced with an advertisement of
229 bytes filled with 'A'.  See stack trace below.

This is fixed by not catching ext_adv as legacy adv are only cached to
be able to concatenate a scanable adv with its scan response before
sending it up through mgmt.

With ext_adv, this is no longer necessary.

Taken from https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git/commit/?id=a2ec905d1e160a33b2e210e45ad30445ef26ce0e
By Linus Torvalds <torvalds@linux-foundation.org>

Change-Id: Iad1e016df8e034318c9bd197aaeae4ba712cc99f
parent 1bf50de9
Loading
Loading
Loading
Loading
+17 −6
Original line number Diff line number Diff line
@@ -1133,6 +1133,9 @@ static void store_pending_adv_report(struct hci_dev *hdev, bdaddr_t *bdaddr,
{
	struct discovery_state *d = &hdev->discovery;

	if (len > HCI_MAX_AD_LENGTH)
		return;

	bacpy(&d->last_adv_addr, bdaddr);
	d->last_adv_addr_type = bdaddr_type;
	d->last_adv_rssi = rssi;
@@ -4743,7 +4746,8 @@ static struct hci_conn *check_pending_le_conn(struct hci_dev *hdev,

static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
			       u8 bdaddr_type, bdaddr_t *direct_addr,
			       u8 direct_addr_type, s8 rssi, u8 *data, u8 len)
			       u8 direct_addr_type, s8 rssi, u8 *data, u8 len,
			       bool ext_adv)
{
	struct discovery_state *d = &hdev->discovery;
	struct smp_irk *irk;
@@ -4752,6 +4756,11 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
	u32 flags;
	u8 *ptr, real_len;

	if (!ext_adv && len > HCI_MAX_AD_LENGTH) {
		bt_dev_err_ratelimited(hdev, "legacy adv larger than 31 bytes");
		return;
	}

	/* Find the end of the data in case the report contains padded zero
	 * bytes at the end causing an invalid length value.
	 *
@@ -4812,7 +4821,7 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
	 */
	conn = check_pending_le_conn(hdev, bdaddr, bdaddr_type, type,
								direct_addr);
	if (conn && type == LE_ADV_IND) {
	if (!ext_adv && conn && type == LE_ADV_IND && len <= HCI_MAX_AD_LENGTH) {
		/* Store report for later inclusion by
		 * mgmt_device_connected
		 */
@@ -4866,7 +4875,7 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
	 * event or send an immediate device found event if the data
	 * should not be stored for later.
	 */
	if (!has_pending_adv_report(hdev)) {
	if (!ext_adv &&	!has_pending_adv_report(hdev)) {
		/* If the report will trigger a SCAN_REQ store it for
		 * later merging.
		 */
@@ -4901,7 +4910,8 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
		/* If the new report will trigger a SCAN_REQ store it for
		 * later merging.
		 */
		if (type == LE_ADV_IND || type == LE_ADV_SCAN_IND) {
		if (!ext_adv && (type == LE_ADV_IND ||
				 type == LE_ADV_SCAN_IND)) {
			store_pending_adv_report(hdev, bdaddr, bdaddr_type,
						 rssi, flags, data, len);
			return;
@@ -4940,7 +4950,7 @@ static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
		rssi = ev->data[ev->length];
		process_adv_report(hdev, ev->evt_type, &ev->bdaddr,
				   ev->bdaddr_type, NULL, 0, rssi,
				   ev->data, ev->length);
				   ev->data, ev->length, false);

		ptr += sizeof(*ev) + ev->length + 1;
	}
@@ -5137,7 +5147,8 @@ static void hci_le_direct_adv_report_evt(struct hci_dev *hdev,

		process_adv_report(hdev, ev->evt_type, &ev->bdaddr,
				   ev->bdaddr_type, &ev->direct_addr,
				   ev->direct_addr_type, ev->rssi, NULL, 0);
				   ev->direct_addr_type, ev->rssi, NULL, 0,
				   false);

		ptr += sizeof(*ev);
	}