diff -Nru bluez-5.53/debian/changelog bluez-5.53/debian/changelog --- bluez-5.53/debian/changelog 2020-04-03 06:46:35.000000000 +0000 +++ bluez-5.53/debian/changelog 2023-11-29 09:11:45.000000000 +0000 @@ -1,3 +1,90 @@ +bluez (5.53-0ubuntu3.7) focal-security; urgency=medium + + * SECURITY UPDATE: make conf compliant to HID specification + - debian/patches/CVE-2023-45866.patch: input.conf: Change default of + ClassicBondedOnly + - CVE-2023-45866 + + -- Nishit Majithia Wed, 29 Nov 2023 14:41:45 +0530 + +bluez (5.53-0ubuntu3.6) focal-security; urgency=medium + + * SECURITY UPDATE: various security improvements (LP: #1977968) + - debian/patches/avdtp-security.patch: check if capabilities are valid + before attempting to copy them in profiles/audio/avdtp.c. + - debian/patches/avdtp-security-2.patch: fix size comparison and + variable misassignment in profiles/audio/avdtp.c. + - debian/patches/avrcp-security.patch: make sure the number of bytes in + the params_len matches the remaining bytes received so the code don't + end up accessing invalid memory in profiles/audio/avrcp.c. + - No CVE numbers + + -- Marc Deslauriers Wed, 08 Jun 2022 07:09:00 -0400 + +bluez (5.53-0ubuntu3.5) focal-security; urgency=medium + + * SECURITY UPDATE: Integer overflow in gatt server protocol could lead to + a heap overflow, resulting in denial of service or potential code + execution. + - debian/patches/CVE-2022-0204.patch: add length and offset validation in + write_cb function in src/shared/gatt-server.c. + - CVE-2022-0204 + + -- Ray Veldkamp Thu, 03 Feb 2022 22:27:07 +1100 + +bluez (5.53-0ubuntu3.4) focal-security; urgency=medium + + * SECURITY UPDATE: incorrect discoverable status + - debian/patches/CVE-2021-3658.patch: fix storing discoverable setting + in src/adapter.c. + - CVE-2021-3658 + * SECURITY UPDATE: DoS via memory leak in sdp_cstate_alloc_buf + - debian/patches/CVE-2021-41229.patch: fix leaking buffers stored in + cstates cache in src/sdpd-request.c, src/sdpd-server.c, src/sdpd.h, + unit/test-sdp.c. + - CVE-2021-41229 + * SECURITY UPDATE: use-after-free when client disconnects + - debian/patches/CVE-2021-43400-pre1.patch: fix Acquire* reply handling + in src/gatt-database.c. + - debian/patches/CVE-2021-43400-pre2.patch: no multiple calls to + AcquireWrite in src/gatt-database.c. + - debian/patches/CVE-2021-43400.patch: fix not cleaning up when + disconnected in src/gatt-database.c. + - CVE-2021-43400 + + -- Marc Deslauriers Wed, 17 Nov 2021 10:19:15 -0500 + +bluez (5.53-0ubuntu3.3) focal; urgency=medium + + * debian/patches/0001-fix-reading-from-rfkill-socket.patch: + - fix reading from rfkill socket (lp: #1933221) + + -- Andy Chi Tue, 22 Jun 2021 14:27:12 +0800 + +bluez (5.53-0ubuntu3.2) focal-security; urgency=medium + + * SECURITY UPDATE: secure pairing passkey brute force + - debian/patches/CVE-2020-26558.patch: fix not properly checking for + secure flags in src/shared/att-types.h, src/shared/gatt-server.c. + - CVE-2020-26558 + * SECURITY UPDATE: DoS or code execution via double-free + - debian/patches/CVE-2020-27153.patch: fix possible crash on disconnect + in src/shared/att.c. + - CVE-2020-27153 + * SECURITY UPDATE: info disclosure via out of bounds read + - debian/patches/CVE-2021-3588.patch: when client features is read + check if the offset is within the cli_feat bounds in + src/gatt-database.c. + - CVE-2021-3588 + + -- Marc Deslauriers Wed, 09 Jun 2021 11:06:38 -0400 + +bluez (5.53-0ubuntu3.1) focal; urgency=medium + + * Add support for the pi 400 (LP: #1903048) + + -- William 'jawn-smith' Wilson Mon, 15 Mar 2021 19:25:22 +0000 + bluez (5.53-0ubuntu3) focal; urgency=medium * debian/patches/ubuntu_error_restart.patch: diff -Nru bluez-5.53/debian/patches/0001-fix-reading-from-rfkill-socket.patch bluez-5.53/debian/patches/0001-fix-reading-from-rfkill-socket.patch --- bluez-5.53/debian/patches/0001-fix-reading-from-rfkill-socket.patch 1970-01-01 00:00:00.000000000 +0000 +++ bluez-5.53/debian/patches/0001-fix-reading-from-rfkill-socket.patch 2021-06-22 06:27:12.000000000 +0000 @@ -0,0 +1,86 @@ +From linux-bluetooth Mon May 03 13:12:10 2021 +From: Benjamin Berg +Date: Mon, 03 May 2021 13:12:10 +0000 +To: linux-bluetooth +Subject: [PATCH] rfkill: Fix reading from rfkill socket +Message-Id: <20210503131210.90066-1-benjamin () sipsolutions ! net> +X-MARC-Message: https://marc.info/?l=linux-bluetooth&m=162004753229953 + +From: Benjamin Berg + +The kernel will always send exactly one event, but the size of the +passed struct will depend on the length of the submitted read() and the +kernel version. i.e. the interface can be extended and we need to expect +for a read to be longer than expected if we ask for it. + +Fix this by only requesting the needed length and explicitly check the +length against the V1 version of the structure to make the code a bit +more future proof in case the internal copy of the struct is updated to +contain new fields. +--- + src/rfkill.c | 24 +++++++++++------------- + 1 file changed, 11 insertions(+), 13 deletions(-) + +Index: bluez/src/rfkill.c +=================================================================== +--- bluez.orig/src/rfkill.c ++++ bluez/src/rfkill.c +@@ -66,12 +66,12 @@ struct rfkill_event { + uint8_t soft; + uint8_t hard; + }; ++#define RFKILL_EVENT_SIZE_V1 8 + + static gboolean rfkill_event(GIOChannel *chan, + GIOCondition cond, gpointer data) + { +- unsigned char buf[32]; +- struct rfkill_event *event = (void *) buf; ++ struct rfkill_event event = { 0 }; + struct btd_adapter *adapter; + char sysname[PATH_MAX]; + ssize_t len; +@@ -82,34 +82,32 @@ static gboolean rfkill_event(GIOChannel + + fd = g_io_channel_unix_get_fd(chan); + +- memset(buf, 0, sizeof(buf)); +- +- len = read(fd, buf, sizeof(buf)); ++ len = read(fd, &event, sizeof(event)); + if (len < 0) { + if (errno == EAGAIN) + return TRUE; + return FALSE; + } + +- if (len != sizeof(struct rfkill_event)) ++ if (len < RFKILL_EVENT_SIZE_V1) + return TRUE; + + DBG("RFKILL event idx %u type %u op %u soft %u hard %u", +- event->idx, event->type, event->op, +- event->soft, event->hard); ++ event.idx, event.type, event.op, ++ event.soft, event.hard); + +- if (event->soft || event->hard) ++ if (event.soft || event.hard) + return TRUE; + +- if (event->op != RFKILL_OP_CHANGE) ++ if (event.op != RFKILL_OP_CHANGE) + return TRUE; + +- if (event->type != RFKILL_TYPE_BLUETOOTH && +- event->type != RFKILL_TYPE_ALL) ++ if (event.type != RFKILL_TYPE_BLUETOOTH && ++ event.type != RFKILL_TYPE_ALL) + return TRUE; + + snprintf(sysname, sizeof(sysname) - 1, +- "/sys/class/rfkill/rfkill%u/name", event->idx); ++ "/sys/class/rfkill/rfkill%u/name", event.idx); + + fd = open(sysname, O_RDONLY); + if (fd < 0) diff -Nru bluez-5.53/debian/patches/CVE-2020-26558.patch bluez-5.53/debian/patches/CVE-2020-26558.patch --- bluez-5.53/debian/patches/CVE-2020-26558.patch 1970-01-01 00:00:00.000000000 +0000 +++ bluez-5.53/debian/patches/CVE-2020-26558.patch 2021-06-09 15:04:51.000000000 +0000 @@ -0,0 +1,88 @@ +Backport of: + +From 00da0fb4972cf59e1c075f313da81ea549cb8738 Mon Sep 17 00:00:00 2001 +From: Luiz Augusto von Dentz +Date: Tue, 2 Mar 2021 11:38:33 -0800 +Subject: shared/gatt-server: Fix not properly checking for secure flags + +When passing the mask to check_permissions all valid permissions for +the operation must be set including BT_ATT_PERM_SECURE flags. +--- + src/shared/att-types.h | 8 ++++++++ + src/shared/gatt-server.c | 25 +++++++------------------ + 2 files changed, 15 insertions(+), 18 deletions(-) + +--- a/src/shared/att-types.h ++++ b/src/shared/att-types.h +@@ -134,6 +134,14 @@ struct bt_att_pdu_error_rsp { + #define BT_ATT_PERM_WRITE_SECURE 0x0200 + #define BT_ATT_PERM_SECURE (BT_ATT_PERM_READ_SECURE | \ + BT_ATT_PERM_WRITE_SECURE) ++#define BT_ATT_PERM_READ_MASK (BT_ATT_PERM_READ | \ ++ BT_ATT_PERM_READ_AUTHEN | \ ++ BT_ATT_PERM_READ_ENCRYPT | \ ++ BT_ATT_PERM_READ_SECURE) ++#define BT_ATT_PERM_WRITE_MASK (BT_ATT_PERM_WRITE | \ ++ BT_ATT_PERM_WRITE_AUTHEN | \ ++ BT_ATT_PERM_WRITE_ENCRYPT | \ ++ BT_ATT_PERM_WRITE_SECURE) + + /* GATT Characteristic Properties Bitfield values */ + #define BT_GATT_CHRC_PROP_BROADCAST 0x01 +--- a/src/shared/gatt-server.c ++++ b/src/shared/gatt-server.c +@@ -459,9 +459,7 @@ static void process_read_by_type(struct + return; + } + +- ecode = check_permissions(server, attr, BT_ATT_PERM_READ | +- BT_ATT_PERM_READ_AUTHEN | +- BT_ATT_PERM_READ_ENCRYPT); ++ ecode = check_permissions(server, attr, BT_ATT_PERM_READ_MASK); + if (ecode) + goto error; + +@@ -828,9 +826,7 @@ static void write_cb(uint8_t opcode, con + (opcode == BT_ATT_OP_WRITE_REQ) ? "Req" : "Cmd", + handle); + +- ecode = check_permissions(server, attr, BT_ATT_PERM_WRITE | +- BT_ATT_PERM_WRITE_AUTHEN | +- BT_ATT_PERM_WRITE_ENCRYPT); ++ ecode = check_permissions(server, attr, BT_ATT_PERM_WRITE_MASK); + if (ecode) + goto error; + +@@ -938,9 +934,7 @@ static void handle_read_req(struct bt_ga + opcode == BT_ATT_OP_READ_BLOB_REQ ? "Blob " : "", + handle); + +- ecode = check_permissions(server, attr, BT_ATT_PERM_READ | +- BT_ATT_PERM_READ_AUTHEN | +- BT_ATT_PERM_READ_ENCRYPT); ++ ecode = check_permissions(server, attr, BT_ATT_PERM_READ_MASK); + if (ecode) + goto error; + +@@ -1035,9 +1029,7 @@ static void read_multiple_complete_cb(st + return; + } + +- ecode = check_permissions(data->server, attr, BT_ATT_PERM_READ | +- BT_ATT_PERM_READ_AUTHEN | +- BT_ATT_PERM_READ_ENCRYPT); ++ ecode = check_permissions(data->server, attr, BT_ATT_PERM_READ_MASK); + if (ecode) { + bt_att_send_error_rsp(data->server->att, + BT_ATT_OP_READ_MULT_REQ, handle, ecode); +@@ -1300,9 +1292,7 @@ static void prep_write_cb(uint8_t opcode + util_debug(server->debug_callback, server->debug_data, + "Prep Write Req - handle: 0x%04x", handle); + +- ecode = check_permissions(server, attr, BT_ATT_PERM_WRITE | +- BT_ATT_PERM_WRITE_AUTHEN | +- BT_ATT_PERM_WRITE_ENCRYPT); ++ ecode = check_permissions(server, attr, BT_ATT_PERM_WRITE_MASK); + if (ecode) + goto error; + diff -Nru bluez-5.53/debian/patches/CVE-2020-27153.patch bluez-5.53/debian/patches/CVE-2020-27153.patch --- bluez-5.53/debian/patches/CVE-2020-27153.patch 1970-01-01 00:00:00.000000000 +0000 +++ bluez-5.53/debian/patches/CVE-2020-27153.patch 2021-06-09 15:06:23.000000000 +0000 @@ -0,0 +1,141 @@ +Backport of: + +From 1cd644db8c23a2f530ddb93cebed7dacc5f5721a Mon Sep 17 00:00:00 2001 +From: Luiz Augusto von Dentz +Date: Wed, 15 Jul 2020 18:25:37 -0700 +Subject: [PATCH] shared/att: Fix possible crash on disconnect + +If there are pending request while disconnecting they would be notified +but clients may endup being freed in the proccess which will then be +calling bt_att_cancel to cancal its requests causing the following +trace: + +Invalid read of size 4 + at 0x1D894C: enable_ccc_callback (gatt-client.c:1627) + by 0x1D247B: disc_att_send_op (att.c:417) + by 0x1CCC17: queue_remove_all (queue.c:354) + by 0x1D47B7: disconnect_cb (att.c:635) + by 0x1E0707: watch_callback (io-glib.c:170) + by 0x48E963B: g_main_context_dispatch (in /usr/lib/libglib-2.0.so.0.6400.4) + by 0x48E9AC7: ??? (in /usr/lib/libglib-2.0.so.0.6400.4) + by 0x48E9ECF: g_main_loop_run (in /usr/lib/libglib-2.0.so.0.6400.4) + by 0x1E0E97: mainloop_run (mainloop-glib.c:79) + by 0x1E13B3: mainloop_run_with_signal (mainloop-notify.c:201) + by 0x12BC3B: main (main.c:770) + Address 0x7d40a28 is 24 bytes inside a block of size 32 free'd + at 0x484A2E0: free (vg_replace_malloc.c:540) + by 0x1CCC17: queue_remove_all (queue.c:354) + by 0x1CCC83: queue_destroy (queue.c:73) + by 0x1D7DD7: bt_gatt_client_free (gatt-client.c:2209) + by 0x16497B: batt_free (battery.c:77) + by 0x16497B: batt_remove (battery.c:286) + by 0x1A0013: service_remove (service.c:176) + by 0x1A9B7B: device_remove_gatt_service (device.c:3691) + by 0x1A9B7B: gatt_service_removed (device.c:3805) + by 0x1CC90B: queue_foreach (queue.c:220) + by 0x1DE27B: notify_service_changed.isra.0.part.0 (gatt-db.c:369) + by 0x1DE387: notify_service_changed (gatt-db.c:361) + by 0x1DE387: gatt_db_service_destroy (gatt-db.c:385) + by 0x1DE3EF: gatt_db_remove_service (gatt-db.c:519) + by 0x1D674F: discovery_op_complete (gatt-client.c:388) + by 0x1D6877: discover_primary_cb (gatt-client.c:1260) + by 0x1E220B: discovery_op_complete (gatt-helpers.c:628) + by 0x1E249B: read_by_grp_type_cb (gatt-helpers.c:730) + by 0x1D247B: disc_att_send_op (att.c:417) + by 0x1CCC17: queue_remove_all (queue.c:354) + by 0x1D47B7: disconnect_cb (att.c:635) +--- + src/shared/att.c | 46 ++++++++++++++++++++++++++++++++++++++++------ + 1 file changed, 40 insertions(+), 6 deletions(-) + +--- a/src/shared/att.c ++++ b/src/shared/att.c +@@ -62,6 +62,7 @@ struct bt_att { + struct queue *ind_queue; /* Queued ATT protocol indications */ + struct att_send_op *pending_ind; + struct queue *write_queue; /* Queue of PDUs ready to send */ ++ bool in_disc; /* Cleanup queues on disconnect_cb */ + bool writer_active; + + struct queue *notify_list; /* List of registered callbacks */ +@@ -211,8 +212,10 @@ static void destroy_att_send_op(void *da + free(op); + } + +-static void cancel_att_send_op(struct att_send_op *op) ++static void cancel_att_send_op(void *data) + { ++ struct att_send_op *op = data; ++ + if (op->destroy) + op->destroy(op->user_data); + +@@ -572,11 +575,6 @@ static bool disconnect_cb(struct io *io, + att->io = NULL; + att->fd = -1; + +- /* Notify request callbacks */ +- queue_remove_all(att->req_queue, NULL, NULL, disc_att_send_op); +- queue_remove_all(att->ind_queue, NULL, NULL, disc_att_send_op); +- queue_remove_all(att->write_queue, NULL, NULL, disc_att_send_op); +- + if (att->pending_req) { + disc_att_send_op(att->pending_req); + att->pending_req = NULL; +@@ -589,6 +587,15 @@ static bool disconnect_cb(struct io *io, + + bt_att_ref(att); + ++ att->in_disc = true; ++ ++ /* Notify request callbacks */ ++ queue_remove_all(att->req_queue, NULL, NULL, disc_att_send_op); ++ queue_remove_all(att->ind_queue, NULL, NULL, disc_att_send_op); ++ queue_remove_all(att->write_queue, NULL, NULL, disc_att_send_op); ++ ++ att->in_disc = false; ++ + queue_foreach(att->disconn_list, disconn_handler, INT_TO_PTR(err)); + + bt_att_unregister_all(att); +@@ -1306,6 +1313,30 @@ static bool match_op_id(const void *a, c + return op->id == id; + } + ++static bool bt_att_disc_cancel(struct bt_att *att, unsigned int id) ++{ ++ struct att_send_op *op; ++ ++ op = queue_find(att->req_queue, match_op_id, UINT_TO_PTR(id)); ++ if (op) ++ goto done; ++ ++ op = queue_find(att->ind_queue, match_op_id, UINT_TO_PTR(id)); ++ if (op) ++ goto done; ++ ++ op = queue_find(att->write_queue, match_op_id, UINT_TO_PTR(id)); ++ ++done: ++ if (!op) ++ return false; ++ ++ /* Just cancel since disconnect_cb will be cleaning up */ ++ cancel_att_send_op(op); ++ ++ return true; ++} ++ + bool bt_att_cancel(struct bt_att *att, unsigned int id) + { + struct att_send_op *op; +@@ -1325,6 +1356,9 @@ bool bt_att_cancel(struct bt_att *att, u + return true; + } + ++ if (att->in_disc) ++ return bt_att_disc_cancel(att, id); ++ + op = queue_remove_if(att->req_queue, match_op_id, UINT_TO_PTR(id)); + if (op) + goto done; diff -Nru bluez-5.53/debian/patches/CVE-2021-3588.patch bluez-5.53/debian/patches/CVE-2021-3588.patch --- bluez-5.53/debian/patches/CVE-2021-3588.patch 1970-01-01 00:00:00.000000000 +0000 +++ bluez-5.53/debian/patches/CVE-2021-3588.patch 2021-06-09 15:06:31.000000000 +0000 @@ -0,0 +1,27 @@ +From 3a40bef49305f8327635b81ac8be52a3ca063d5a Mon Sep 17 00:00:00 2001 +From: Luiz Augusto von Dentz +Date: Mon, 4 Jan 2021 10:38:31 -0800 +Subject: gatt: Fix potential buffer out-of-bound + +When client features is read check if the offset is within the cli_feat +bounds. + +Fixes: https://github.com/bluez/bluez/issues/70 +--- + src/gatt-database.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/src/gatt-database.c ++++ b/src/gatt-database.c +@@ -1083,6 +1083,11 @@ static void cli_feat_read_cb(struct gatt + goto done; + } + ++ if (offset >= sizeof(state->cli_feat)) { ++ ecode = BT_ATT_ERROR_INVALID_OFFSET; ++ goto done; ++ } ++ + len = sizeof(state->cli_feat) - offset; + value = len ? &state->cli_feat[offset] : NULL; + diff -Nru bluez-5.53/debian/patches/CVE-2021-3658.patch bluez-5.53/debian/patches/CVE-2021-3658.patch --- bluez-5.53/debian/patches/CVE-2021-3658.patch 1970-01-01 00:00:00.000000000 +0000 +++ bluez-5.53/debian/patches/CVE-2021-3658.patch 2021-11-17 15:16:57.000000000 +0000 @@ -0,0 +1,89 @@ +Backport of: + +From b497b5942a8beb8f89ca1c359c54ad67ec843055 Mon Sep 17 00:00:00 2001 +From: Luiz Augusto von Dentz +Date: Thu, 24 Jun 2021 16:32:04 -0700 +Subject: adapter: Fix storing discoverable setting + +discoverable setting shall only be store when changed via Discoverable +property and not when discovery client set it as that be considered +temporary just for the lifetime of the discovery. +--- + src/adapter.c | 35 ++++++++++++++++++++++------------- + 1 file changed, 22 insertions(+), 13 deletions(-) + +--- a/src/adapter.c ++++ b/src/adapter.c +@@ -565,7 +565,11 @@ static void settings_changed(struct btd_ + if (changed_mask & MGMT_SETTING_DISCOVERABLE) { + g_dbus_emit_property_changed(dbus_conn, adapter->path, + ADAPTER_INTERFACE, "Discoverable"); +- store_adapter_info(adapter); ++ /* Only persist discoverable setting if it was not set ++ * temporarily by discovery. ++ */ ++ if (!adapter->discovery_discoverable) ++ store_adapter_info(adapter); + btd_adv_manager_refresh(adapter->adv_manager); + } + +@@ -2136,8 +2140,6 @@ static bool filters_equal(struct mgmt_cp + static int update_discovery_filter(struct btd_adapter *adapter) + { + struct mgmt_cp_start_service_discovery *sd_cp; +- GSList *l; +- + + DBG(""); + +@@ -2147,17 +2149,24 @@ static int update_discovery_filter(struc + return -ENOMEM; + } + +- for (l = adapter->discovery_list; l; l = g_slist_next(l)) { +- struct watch_client *client = l->data; ++ /* Only attempt to overwrite current discoverable setting when not ++ * discoverable. ++ */ ++ if (!(adapter->current_settings & MGMT_OP_SET_DISCOVERABLE)) { ++ GSList *l; + +- if (!client->discovery_filter) +- continue; ++ for (l = adapter->discovery_list; l; l = g_slist_next(l)) { ++ struct watch_client *client = l->data; + +- if (client->discovery_filter->discoverable) +- break; +- } ++ if (!client->discovery_filter) ++ continue; + +- set_discovery_discoverable(adapter, l ? true : false); ++ if (client->discovery_filter->discoverable) { ++ set_discovery_discoverable(adapter, true); ++ break; ++ } ++ } ++ } + + /* + * If filters are equal, then don't update scan, except for when +@@ -2190,8 +2199,7 @@ static int discovery_stop(struct watch_c + return 0; + } + +- if (adapter->discovery_discoverable) +- set_discovery_discoverable(adapter, false); ++ set_discovery_discoverable(adapter, false); + + /* + * In the idle phase of a discovery, there is no need to stop it +@@ -6430,6 +6438,7 @@ static void adapter_stop(struct btd_adap + g_free(adapter->current_discovery_filter); + adapter->current_discovery_filter = NULL; + ++ set_discovery_discoverable(adapter, false); + adapter->discovering = false; + + while (adapter->connections) { diff -Nru bluez-5.53/debian/patches/CVE-2021-41229.patch bluez-5.53/debian/patches/CVE-2021-41229.patch --- bluez-5.53/debian/patches/CVE-2021-41229.patch 1970-01-01 00:00:00.000000000 +0000 +++ bluez-5.53/debian/patches/CVE-2021-41229.patch 2021-11-17 15:17:29.000000000 +0000 @@ -0,0 +1,451 @@ +From e79417ed7185b150a056d4eb3a1ab528b91d2fc0 Mon Sep 17 00:00:00 2001 +From: Luiz Augusto von Dentz +Date: Thu, 15 Jul 2021 11:01:20 -0700 +Subject: sdpd: Fix leaking buffers stored in cstates cache + +These buffer shall only be keep in cache for as long as they are +needed so this would cleanup any client cstates in the following +conditions: + + - There is no cstate on the response + - No continuation can be found for cstate + - Different request opcode + - Respond with an error + - Client disconnect + +Fixes: https://github.com/bluez/bluez/security/advisories/GHSA-3fqg-r8j5-f5xq +--- + src/sdpd-request.c | 170 ++++++++++++++++++++++++++++++++++++++--------------- + src/sdpd-server.c | 20 +++---- + src/sdpd.h | 3 + + unit/test-sdp.c | 2 +- + 4 files changed, 135 insertions(+), 60 deletions(-) + +--- a/src/sdpd-request.c ++++ b/src/sdpd-request.c +@@ -55,48 +55,78 @@ typedef struct { + + #define MIN(x, y) ((x) < (y)) ? (x): (y) + +-typedef struct _sdp_cstate_list sdp_cstate_list_t; ++typedef struct sdp_cont_info sdp_cont_info_t; + +-struct _sdp_cstate_list { +- sdp_cstate_list_t *next; ++struct sdp_cont_info { ++ int sock; ++ uint8_t opcode; + uint32_t timestamp; + sdp_buf_t buf; + }; + +-static sdp_cstate_list_t *cstates; ++static sdp_list_t *cstates; + +-/* FIXME: should probably remove it when it's found */ +-static sdp_buf_t *sdp_get_cached_rsp(sdp_cont_state_t *cstate) ++static int cstate_match(const void *data, const void *user_data) + { +- sdp_cstate_list_t *p; ++ const sdp_cont_info_t *cinfo = data; ++ const sdp_cont_state_t *cstate = user_data; + +- for (p = cstates; p; p = p->next) { +- /* Check timestamp */ +- if (p->timestamp != cstate->timestamp) +- continue; ++ /* Check timestamp */ ++ return cinfo->timestamp - cstate->timestamp; ++} ++ ++static void sdp_cont_info_free(sdp_cont_info_t *cinfo) ++{ ++ if (!cinfo) ++ return; ++ ++ cstates = sdp_list_remove(cstates, cinfo); ++ free(cinfo->buf.data); ++ free(cinfo); ++} ++ ++static sdp_cont_info_t *sdp_get_cont_info(sdp_req_t *req, ++ sdp_cont_state_t *cstate) ++{ ++ sdp_list_t *list; ++ ++ list = sdp_list_find(cstates, cstate, cstate_match); ++ if (list) { ++ sdp_cont_info_t *cinfo = list->data; + +- /* Check if requesting more than available */ +- if (cstate->cStateValue.maxBytesSent < p->buf.data_size) +- return &p->buf; ++ if (cinfo->opcode == req->opcode) ++ return cinfo; ++ ++ /* Cleanup continuation if the opcode doesn't match since its ++ * response buffer shall only be valid for the original requests ++ */ ++ sdp_cont_info_free(cinfo); ++ return NULL; + } + +- return 0; ++ /* Cleanup cstates if no continuation info could be found */ ++ sdp_cstate_cleanup(req->sock); ++ ++ return NULL; + } + +-static uint32_t sdp_cstate_alloc_buf(sdp_buf_t *buf) ++static uint32_t sdp_cstate_alloc_buf(sdp_req_t *req, sdp_buf_t *buf) + { +- sdp_cstate_list_t *cstate = malloc(sizeof(sdp_cstate_list_t)); ++ sdp_cont_info_t *cinfo = malloc(sizeof(sdp_cont_info_t)); + uint8_t *data = malloc(buf->data_size); + + memcpy(data, buf->data, buf->data_size); +- memset((char *)cstate, 0, sizeof(sdp_cstate_list_t)); +- cstate->buf.data = data; +- cstate->buf.data_size = buf->data_size; +- cstate->buf.buf_size = buf->data_size; +- cstate->timestamp = sdp_get_time(); +- cstate->next = cstates; +- cstates = cstate; +- return cstate->timestamp; ++ memset(cinfo, 0, sizeof(sdp_cont_info_t)); ++ cinfo->buf.data = data; ++ cinfo->buf.data_size = buf->data_size; ++ cinfo->buf.buf_size = buf->data_size; ++ cinfo->timestamp = sdp_get_time(); ++ cinfo->sock = req->sock; ++ cinfo->opcode = req->opcode; ++ ++ cstates = sdp_list_append(cstates, cinfo); ++ ++ return cinfo->timestamp; + } + + /* Additional values for checking datatype (not in spec) */ +@@ -287,14 +317,16 @@ static int sdp_set_cstate_pdu(sdp_buf_t + return length; + } + +-static int sdp_cstate_get(uint8_t *buffer, size_t len, +- sdp_cont_state_t **cstate) ++static int sdp_cstate_get(sdp_req_t *req, uint8_t *buffer, size_t len, ++ sdp_cont_state_t **cstate, sdp_cont_info_t **cinfo) + { + uint8_t cStateSize = *buffer; + + SDPDBG("Continuation State size : %d", cStateSize); + + if (cStateSize == 0) { ++ /* Cleanup cstates if request doesn't contain a cstate */ ++ sdp_cstate_cleanup(req->sock); + *cstate = NULL; + return 0; + } +@@ -319,6 +351,8 @@ static int sdp_cstate_get(uint8_t *buffe + SDPDBG("Cstate TS : 0x%x", (*cstate)->timestamp); + SDPDBG("Bytes sent : %d", (*cstate)->cStateValue.maxBytesSent); + ++ *cinfo = sdp_get_cont_info(req, *cstate); ++ + return 0; + } + +@@ -373,6 +407,7 @@ static int service_search_req(sdp_req_t + uint16_t expected, actual, rsp_count = 0; + uint8_t dtd; + sdp_cont_state_t *cstate = NULL; ++ sdp_cont_info_t *cinfo = NULL; + uint8_t *pCacheBuffer = NULL; + int handleSize = 0; + uint32_t cStateId = 0; +@@ -412,9 +447,9 @@ static int service_search_req(sdp_req_t + + /* + * Check if continuation state exists, if yes attempt +- * to get rsp remainder from cache, else send error ++ * to get rsp remainder from continuation info, else send error + */ +- if (sdp_cstate_get(pdata, data_left, &cstate) < 0) { ++ if (sdp_cstate_get(req, pdata, data_left, &cstate, &cinfo) < 0) { + status = SDP_INVALID_SYNTAX; + goto done; + } +@@ -464,7 +499,7 @@ static int service_search_req(sdp_req_t + + if (rsp_count > actual) { + /* cache the rsp and generate a continuation state */ +- cStateId = sdp_cstate_alloc_buf(buf); ++ cStateId = sdp_cstate_alloc_buf(req, buf); + /* + * subtract handleSize since we now send only + * a subset of handles +@@ -472,6 +507,7 @@ static int service_search_req(sdp_req_t + buf->data_size -= handleSize; + } else { + /* NULL continuation state */ ++ sdp_cont_info_free(cinfo); + sdp_set_cstate_pdu(buf, NULL); + } + } +@@ -481,13 +517,15 @@ static int service_search_req(sdp_req_t + short lastIndex = 0; + + if (cstate) { +- /* +- * Get the previous sdp_cont_state_t and obtain +- * the cached rsp +- */ +- sdp_buf_t *pCache = sdp_get_cached_rsp(cstate); +- if (pCache) { +- pCacheBuffer = pCache->data; ++ if (cinfo) { ++ /* Check if requesting more than available */ ++ if (cstate->cStateValue.maxBytesSent >= ++ cinfo->buf.data_size) { ++ status = SDP_INVALID_CSTATE; ++ goto done; ++ } ++ ++ pCacheBuffer = cinfo->buf.data; + /* get the rsp_count from the cached buffer */ + rsp_count = get_be16(pCacheBuffer); + +@@ -531,6 +569,7 @@ static int service_search_req(sdp_req_t + if (i == rsp_count) { + /* set "null" continuationState */ + sdp_set_cstate_pdu(buf, NULL); ++ sdp_cont_info_free(cinfo); + } else { + /* + * there's more: set lastIndexSent to +@@ -553,6 +592,7 @@ static int service_search_req(sdp_req_t + + done: + free(cstate); ++ + if (pattern) + sdp_list_free(pattern, free); + +@@ -632,15 +672,21 @@ static int extract_attrs(sdp_record_t *r + } + + /* Build cstate response */ +-static int sdp_cstate_rsp(sdp_cont_state_t *cstate, sdp_buf_t *buf, +- uint16_t max) ++static int sdp_cstate_rsp(sdp_cont_info_t *cinfo, sdp_cont_state_t *cstate, ++ sdp_buf_t *buf, uint16_t max) + { +- /* continuation State exists -> get from cache */ +- sdp_buf_t *cache = sdp_get_cached_rsp(cstate); ++ sdp_buf_t *cache; + uint16_t sent; + +- if (!cache) ++ if (!cinfo) ++ return 0; ++ ++ if (cstate->cStateValue.maxBytesSent >= cinfo->buf.data_size) { ++ sdp_cont_info_free(cinfo); + return 0; ++ } ++ ++ cache = &cinfo->buf; + + sent = MIN(max, cache->data_size - cstate->cStateValue.maxBytesSent); + memcpy(buf->data, cache->data + cstate->cStateValue.maxBytesSent, sent); +@@ -650,8 +696,10 @@ static int sdp_cstate_rsp(sdp_cont_state + SDPDBG("Response size : %d sending now : %d bytes sent so far : %d", + cache->data_size, sent, cstate->cStateValue.maxBytesSent); + +- if (cstate->cStateValue.maxBytesSent == cache->data_size) ++ if (cstate->cStateValue.maxBytesSent == cache->data_size) { ++ sdp_cont_info_free(cinfo); + return sdp_set_cstate_pdu(buf, NULL); ++ } + + return sdp_set_cstate_pdu(buf, cstate); + } +@@ -665,6 +713,7 @@ static int sdp_cstate_rsp(sdp_cont_state + static int service_attr_req(sdp_req_t *req, sdp_buf_t *buf) + { + sdp_cont_state_t *cstate = NULL; ++ sdp_cont_info_t *cinfo = NULL; + short cstate_size = 0; + sdp_list_t *seq = NULL; + uint8_t dtd = 0; +@@ -721,7 +770,7 @@ static int service_attr_req(sdp_req_t *r + * if continuation state exists, attempt + * to get rsp remainder from cache, else send error + */ +- if (sdp_cstate_get(pdata, data_left, &cstate) < 0) { ++ if (sdp_cstate_get(req, pdata, data_left, &cstate, &cinfo) < 0) { + status = SDP_INVALID_SYNTAX; + goto done; + } +@@ -750,7 +799,7 @@ static int service_attr_req(sdp_req_t *r + buf->buf_size -= sizeof(uint16_t); + + if (cstate) { +- cstate_size = sdp_cstate_rsp(cstate, buf, max_rsp_size); ++ cstate_size = sdp_cstate_rsp(cinfo, cstate, buf, max_rsp_size); + if (!cstate_size) { + status = SDP_INVALID_CSTATE; + error("NULL cache buffer and non-NULL continuation state"); +@@ -762,7 +811,7 @@ static int service_attr_req(sdp_req_t *r + sdp_cont_state_t newState; + + memset((char *)&newState, 0, sizeof(sdp_cont_state_t)); +- newState.timestamp = sdp_cstate_alloc_buf(buf); ++ newState.timestamp = sdp_cstate_alloc_buf(req, buf); + /* + * Reset the buffer size to the maximum expected and + * set the sdp_cont_state_t +@@ -806,6 +855,7 @@ static int service_search_attr_req(sdp_r + int scanned, rsp_count = 0; + sdp_list_t *pattern = NULL, *seq = NULL, *svcList; + sdp_cont_state_t *cstate = NULL; ++ sdp_cont_info_t *cinfo = NULL; + short cstate_size = 0; + uint8_t dtd = 0; + sdp_buf_t tmpbuf; +@@ -865,7 +915,7 @@ static int service_search_attr_req(sdp_r + * if continuation state exists attempt + * to get rsp remainder from cache, else send error + */ +- if (sdp_cstate_get(pdata, data_left, &cstate) < 0) { ++ if (sdp_cstate_get(req, pdata, data_left, &cstate, &cinfo) < 0) { + status = SDP_INVALID_SYNTAX; + goto done; + } +@@ -919,7 +969,7 @@ static int service_search_attr_req(sdp_r + sdp_cont_state_t newState; + + memset((char *)&newState, 0, sizeof(sdp_cont_state_t)); +- newState.timestamp = sdp_cstate_alloc_buf(buf); ++ newState.timestamp = sdp_cstate_alloc_buf(req, buf); + /* + * Reset the buffer size to the maximum expected and + * set the sdp_cont_state_t +@@ -930,7 +980,7 @@ static int service_search_attr_req(sdp_r + } else + cstate_size = sdp_set_cstate_pdu(buf, NULL); + } else { +- cstate_size = sdp_cstate_rsp(cstate, buf, max); ++ cstate_size = sdp_cstate_rsp(cinfo, cstate, buf, max); + if (!cstate_size) { + status = SDP_INVALID_CSTATE; + SDPDBG("Non-null continuation state, but null cache buffer"); +@@ -987,6 +1037,9 @@ static void process_request(sdp_req_t *r + status = SDP_INVALID_PDU_SIZE; + goto send_rsp; + } ++ ++ req->opcode = reqhdr->pdu_id; ++ + switch (reqhdr->pdu_id) { + case SDP_SVC_SEARCH_REQ: + SDPDBG("Got a svc srch req"); +@@ -1033,6 +1086,8 @@ static void process_request(sdp_req_t *r + + send_rsp: + if (status) { ++ /* Cleanup cstates on error */ ++ sdp_cstate_cleanup(req->sock); + rsphdr->pdu_id = SDP_ERROR_RSP; + put_be16(status, rsp.data); + rsp.data_size = sizeof(uint16_t); +@@ -1121,3 +1176,20 @@ void handle_request(int sk, uint8_t *dat + + process_request(&req); + } ++ ++void sdp_cstate_cleanup(int sock) ++{ ++ sdp_list_t *list; ++ ++ /* Remove any cinfo for the client */ ++ for (list = cstates; list;) { ++ sdp_cont_info_t *cinfo = list->data; ++ ++ list = list->next; ++ ++ if (cinfo->sock != sock) ++ continue; ++ ++ sdp_cont_info_free(cinfo); ++ } ++} +--- a/src/sdpd-server.c ++++ b/src/sdpd-server.c +@@ -159,16 +159,12 @@ static gboolean io_session_event(GIOChan + + sk = g_io_channel_unix_get_fd(chan); + +- if (cond & (G_IO_HUP | G_IO_ERR)) { +- sdp_svcdb_collect_all(sk); +- return FALSE; +- } ++ if (cond & (G_IO_HUP | G_IO_ERR)) ++ goto cleanup; + + len = recv(sk, &hdr, sizeof(sdp_pdu_hdr_t), MSG_PEEK); +- if (len < 0 || (unsigned int) len < sizeof(sdp_pdu_hdr_t)) { +- sdp_svcdb_collect_all(sk); +- return FALSE; +- } ++ if (len < 0 || (unsigned int) len < sizeof(sdp_pdu_hdr_t)) ++ goto cleanup; + + size = sizeof(sdp_pdu_hdr_t) + ntohs(hdr.plen); + buf = malloc(size); +@@ -181,14 +177,18 @@ static gboolean io_session_event(GIOChan + * inside handle_request() in order to produce ErrorResponse. + */ + if (len <= 0) { +- sdp_svcdb_collect_all(sk); + free(buf); +- return FALSE; ++ goto cleanup; + } + + handle_request(sk, buf, len); + + return TRUE; ++ ++cleanup: ++ sdp_svcdb_collect_all(sk); ++ sdp_cstate_cleanup(sk); ++ return FALSE; + } + + static gboolean io_accept_event(GIOChannel *chan, GIOCondition cond, gpointer data) +--- a/src/sdpd.h ++++ b/src/sdpd.h +@@ -40,8 +40,11 @@ typedef struct request { + int flags; + uint8_t *buf; + int len; ++ uint8_t opcode; + } sdp_req_t; + ++void sdp_cstate_cleanup(int sock); ++ + void handle_internal_request(int sk, int mtu, void *data, int len); + void handle_request(int sk, uint8_t *data, int len); + +--- a/unit/test-sdp.c ++++ b/unit/test-sdp.c +@@ -248,7 +248,7 @@ static gboolean client_handler(GIOChanne + tester_monitor('>', 0x0000, 0x0001, buf, len); + + g_assert(len > 0); +- g_assert((size_t) len == rsp_pdu->raw_size + rsp_pdu->cont_len); ++ g_assert_cmpuint(len, ==, rsp_pdu->raw_size + rsp_pdu->cont_len); + + g_assert(memcmp(buf, rsp_pdu->raw_data, rsp_pdu->raw_size) == 0); + diff -Nru bluez-5.53/debian/patches/CVE-2021-43400-pre1.patch bluez-5.53/debian/patches/CVE-2021-43400-pre1.patch --- bluez-5.53/debian/patches/CVE-2021-43400-pre1.patch 1970-01-01 00:00:00.000000000 +0000 +++ bluez-5.53/debian/patches/CVE-2021-43400-pre1.patch 2021-11-17 15:19:15.000000000 +0000 @@ -0,0 +1,35 @@ +From f64f05a5156e67ae586da765e2b0a67d0a942d88 Mon Sep 17 00:00:00 2001 +From: Luiz Augusto von Dentz +Date: Wed, 1 Apr 2020 16:27:33 -0700 +Subject: [PATCH] gatt: Fix Acquire* reply handling + +Originally these operation did not set any owner_queue which caused +them to crash if the attribute is freed before the respose, to fix that +the reply will now check if owner_queue was reset to NULL which means +the attribute is no longer available but the owner_queue was never set +in the first place so this ensures they are now setup properly. +--- + src/gatt-database.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/src/gatt-database.c ++++ b/src/gatt-database.c +@@ -2437,8 +2437,8 @@ static struct pending_op *acquire_write( + { + struct pending_op *op; + +- op = pending_write_new(device, NULL, attrib, id, value, len, 0, +- link_type, false, false); ++ op = pending_write_new(device, chrc->pending_writes, attrib, id, value, ++ len, 0, link_type, false, false); + + if (g_dbus_proxy_method_call(chrc->proxy, "AcquireWrite", + acquire_write_setup, +@@ -2558,6 +2558,7 @@ static uint8_t ccc_write_cb(struct pendi + if (g_dbus_proxy_get_property(chrc->proxy, "NotifyAcquired", &iter)) { + op->data.iov_base = (void *) chrc; + op->data.iov_len = sizeof(chrc); ++ op->owner_queue = chrc->pending_writes; + if (g_dbus_proxy_method_call(chrc->proxy, "AcquireNotify", + acquire_notify_setup, + acquire_notify_reply, diff -Nru bluez-5.53/debian/patches/CVE-2021-43400-pre2.patch bluez-5.53/debian/patches/CVE-2021-43400-pre2.patch --- bluez-5.53/debian/patches/CVE-2021-43400-pre2.patch 1970-01-01 00:00:00.000000000 +0000 +++ bluez-5.53/debian/patches/CVE-2021-43400-pre2.patch 2021-11-17 15:19:15.000000000 +0000 @@ -0,0 +1,94 @@ +From 6278a71040ef070f2a15e07a43b449ce5035287a Mon Sep 17 00:00:00 2001 +From: Sebastian Urban +Date: Sat, 12 Jun 2021 11:56:01 +0200 +Subject: [PATCH] gatt-database: No multiple calls to AcquireWrite + +This checks if an outstanding call to AcquireWrite is already in +progress. If so, the write request is placed into the queue, but +AcquireWrite is not called again. When a response to AcquireWrite is +received, acquire_write_reply sends all queued writes over the acquired +socket. + +Making multiple simultaneous calls to AcquireWrite makes no sense, +as this would open multiple socket pairs and only the last returned +socket would be used for further writes. +--- + src/gatt-database.c | 41 +++++++++++++++++++++++++++++++++-------- + 1 file changed, 33 insertions(+), 8 deletions(-) + +--- a/src/gatt-database.c ++++ b/src/gatt-database.c +@@ -2303,6 +2303,26 @@ static struct pending_op *send_write(str + return NULL; + } + ++static void flush_pending_write(void *data, void *user_data) ++{ ++ GDBusProxy *proxy = user_data; ++ struct pending_op *op = data; ++ ++ if (g_dbus_proxy_method_call(proxy, "WriteValue", write_setup_cb, ++ write_reply_cb, ++ op, pending_op_free) == TRUE) ++ return; ++ ++ pending_op_free(op); ++} ++ ++static void flush_pending_writes(GDBusProxy *proxy, ++ struct queue *owner_queue) ++{ ++ queue_foreach(owner_queue, flush_pending_write, proxy); ++ queue_remove_all(owner_queue, NULL, NULL, NULL); ++} ++ + static bool sock_hup(struct io *io, void *user_data) + { + struct external_chrc *chrc = user_data; +@@ -2397,18 +2417,19 @@ static void acquire_write_reply(DBusMess + + chrc->write_io = sock_io_new(fd, chrc); + +- if (sock_io_send(chrc->write_io, op->data.iov_base, +- op->data.iov_len) < 0) +- goto retry; ++ while ((op = queue_peek_head(chrc->pending_writes)) != NULL) { ++ if (sock_io_send(chrc->write_io, op->data.iov_base, ++ op->data.iov_len) < 0) ++ goto retry; + +- gatt_db_attribute_write_result(op->attrib, op->id, 0); ++ gatt_db_attribute_write_result(op->attrib, op->id, 0); ++ pending_op_free(op); ++ } + + return; + + retry: +- send_write(op->device, op->attrib, chrc->proxy, NULL, op->id, +- op->data.iov_base, op->data.iov_len, 0, +- op->link_type, false, false); ++ flush_pending_writes(chrc->proxy, chrc->pending_writes); + } + + static void acquire_write_setup(DBusMessageIter *iter, void *user_data) +@@ -2436,14 +2457,18 @@ static struct pending_op *acquire_write( + uint8_t link_type) + { + struct pending_op *op; ++ bool acquiring = !queue_isempty(chrc->pending_writes); + + op = pending_write_new(device, chrc->pending_writes, attrib, id, value, + len, 0, link_type, false, false); + ++ if (acquiring) ++ return op; ++ + if (g_dbus_proxy_method_call(chrc->proxy, "AcquireWrite", + acquire_write_setup, + acquire_write_reply, +- op, pending_op_free)) ++ op, NULL)) + return op; + + pending_op_free(op); diff -Nru bluez-5.53/debian/patches/CVE-2021-43400.patch bluez-5.53/debian/patches/CVE-2021-43400.patch --- bluez-5.53/debian/patches/CVE-2021-43400.patch 1970-01-01 00:00:00.000000000 +0000 +++ bluez-5.53/debian/patches/CVE-2021-43400.patch 2021-11-17 15:19:15.000000000 +0000 @@ -0,0 +1,319 @@ +From 838c0dc7641e1c991c0f3027bf94bee4606012f8 Mon Sep 17 00:00:00 2001 +From: Bernie Conrad +Date: Tue, 28 Sep 2021 16:00:15 -0700 +Subject: gatt: Fix not cleaning up when disconnected + +There is a current use after free possible on a gatt server if a client +disconnects while a WriteValue call is being processed with dbus. + +This patch includes the addition of a pending disconnect callback to handle +cleanup better if a disconnect occurs during a write, an acquire write +or read operation using bt_att_register_disconnect with the cb. +--- + src/gatt-database.c | 128 ++++++++++++++++++++++++++++++---------------------- + 1 file changed, 74 insertions(+), 54 deletions(-) + +--- a/src/gatt-database.c ++++ b/src/gatt-database.c +@@ -154,8 +154,9 @@ struct external_desc { + }; + + struct pending_op { +- struct btd_device *device; ++ struct bt_att *att; + unsigned int id; ++ unsigned int disconn_id; + uint16_t offset; + uint8_t link_type; + struct gatt_db_attribute *attrib; +@@ -925,6 +926,26 @@ static struct btd_device *att_get_device + return btd_adapter_find_device(adapter, &dst, dst_type); + } + ++ ++static void pending_op_free(void *data) ++{ ++ struct pending_op *op = data; ++ ++ if (op->owner_queue) ++ queue_remove(op->owner_queue, op); ++ ++ bt_att_unregister_disconnect(op->att, op->disconn_id); ++ bt_att_unref(op->att); ++ free(op); ++} ++ ++static void pending_disconnect_cb(int err, void *user_data) ++{ ++ struct pending_op *op = user_data; ++ ++ op->owner_queue = NULL; ++} ++ + static struct pending_op *pending_ccc_new(struct bt_att *att, + struct gatt_db_attribute *attrib, + uint16_t value, +@@ -944,21 +965,16 @@ static struct pending_op *pending_ccc_ne + op->data.iov_base = UINT_TO_PTR(value); + op->data.iov_len = sizeof(value); + +- op->device = device; ++ op->att = bt_att_ref(att); + op->attrib = attrib; + op->link_type = link_type; + +- return op; +-} ++ bt_att_register_disconnect(att, ++ pending_disconnect_cb, ++ op, ++ NULL); + +-static void pending_op_free(void *data) +-{ +- struct pending_op *op = data; +- +- if (op->owner_queue) +- queue_remove(op->owner_queue, op); +- +- free(op); ++ return op; + } + + static void gatt_ccc_write_cb(struct gatt_db_attribute *attrib, +@@ -2077,31 +2093,35 @@ done: + gatt_db_attribute_read_result(op->attrib, op->id, ecode, value, len); + } + +-static struct pending_op *pending_read_new(struct btd_device *device, ++ ++static struct pending_op *pending_read_new(struct bt_att *att, + struct queue *owner_queue, + struct gatt_db_attribute *attrib, +- unsigned int id, uint16_t offset, +- uint8_t link_type) ++ unsigned int id, uint16_t offset) + { + struct pending_op *op; + + op = new0(struct pending_op, 1); + + op->owner_queue = owner_queue; +- op->device = device; ++ op->att = bt_att_ref(att); + op->attrib = attrib; + op->id = id; + op->offset = offset; +- op->link_type = link_type; ++ op->link_type = bt_att_get_link_type(att); + queue_push_tail(owner_queue, op); + ++ op->disconn_id = bt_att_register_disconnect(att, pending_disconnect_cb, ++ op, NULL); ++ + return op; + } + + static void append_options(DBusMessageIter *iter, void *user_data) + { + struct pending_op *op = user_data; +- const char *path = device_get_path(op->device); ++ struct btd_device *device = att_get_device(op->att); ++ const char *path = device_get_path(device); + struct bt_gatt_server *server; + const char *link; + uint16_t mtu; +@@ -2128,7 +2148,7 @@ static void append_options(DBusMessageIt + dict_append_entry(iter, "prepare-authorize", DBUS_TYPE_BOOLEAN, + &op->prep_authorize); + +- server = btd_device_get_gatt_server(op->device); ++ server = btd_device_get_gatt_server(device); + mtu = bt_gatt_server_get_mtu(server); + + dict_append_entry(iter, "mtu", DBUS_TYPE_UINT16, &mtu); +@@ -2151,18 +2171,16 @@ static void read_setup_cb(DBusMessageIte + dbus_message_iter_close_container(iter, &dict); + } + +-static struct pending_op *send_read(struct btd_device *device, ++static struct pending_op *send_read(struct bt_att *att, + struct gatt_db_attribute *attrib, + GDBusProxy *proxy, + struct queue *owner_queue, + unsigned int id, +- uint16_t offset, +- uint8_t link_type) ++ uint16_t offset) + { + struct pending_op *op; + +- op = pending_read_new(device, owner_queue, attrib, id, offset, +- link_type); ++ op = pending_read_new(att, owner_queue, attrib, id, offset); + + if (g_dbus_proxy_method_call(proxy, "ReadValue", read_setup_cb, + read_reply_cb, op, pending_op_free) == TRUE) +@@ -2245,15 +2263,17 @@ static void write_reply_cb(DBusMessage * + } + + done: +- gatt_db_attribute_write_result(op->attrib, op->id, ecode); ++ /* Make sure that only reply if the device is connected */ ++ if (!bt_att_get_fd(op->att)) ++ gatt_db_attribute_write_result(op->attrib, op->id, ecode); + } + +-static struct pending_op *pending_write_new(struct btd_device *device, ++static struct pending_op *pending_write_new(struct bt_att *att, + struct queue *owner_queue, + struct gatt_db_attribute *attrib, + unsigned int id, + const uint8_t *value, size_t len, +- uint16_t offset, uint8_t link_type, ++ uint16_t offset, + bool is_characteristic, + bool prep_authorize) + { +@@ -2264,33 +2284,37 @@ static struct pending_op *pending_write_ + op->data.iov_base = (uint8_t *) value; + op->data.iov_len = len; + +- op->device = device; ++ op->att = bt_att_ref(att); + op->owner_queue = owner_queue; + op->attrib = attrib; + op->id = id; + op->offset = offset; +- op->link_type = link_type; ++ op->link_type = bt_att_get_link_type(att); + op->is_characteristic = is_characteristic; + op->prep_authorize = prep_authorize; + queue_push_tail(owner_queue, op); + ++ bt_att_register_disconnect(att, ++ pending_disconnect_cb, ++ op, NULL); ++ + return op; + } + +-static struct pending_op *send_write(struct btd_device *device, ++static struct pending_op *send_write(struct bt_att *att, + struct gatt_db_attribute *attrib, + GDBusProxy *proxy, + struct queue *owner_queue, + unsigned int id, + const uint8_t *value, size_t len, +- uint16_t offset, uint8_t link_type, ++ uint16_t offset, + bool is_characteristic, + bool prep_authorize) + { + struct pending_op *op; + +- op = pending_write_new(device, owner_queue, attrib, id, value, len, +- offset, link_type, is_characteristic, ++ op = pending_write_new(att, owner_queue, attrib, id, value, len, ++ offset, is_characteristic, + prep_authorize); + + if (g_dbus_proxy_method_call(proxy, "WriteValue", write_setup_cb, +@@ -2450,17 +2474,16 @@ static void acquire_write_setup(DBusMess + } + + static struct pending_op *acquire_write(struct external_chrc *chrc, +- struct btd_device *device, ++ struct bt_att *att, + struct gatt_db_attribute *attrib, + unsigned int id, +- const uint8_t *value, size_t len, +- uint8_t link_type) ++ const uint8_t *value, size_t len) + { + struct pending_op *op; + bool acquiring = !queue_isempty(chrc->pending_writes); + +- op = pending_write_new(device, chrc->pending_writes, attrib, id, value, +- len, 0, link_type, false, false); ++ op = pending_write_new(att, chrc->pending_writes, attrib, id, value, ++ len, 0, false, false); + + if (acquiring) + return op; +@@ -2730,8 +2753,8 @@ static void desc_read_cb(struct gatt_db_ + goto fail; + } + +- if (send_read(device, attrib, desc->proxy, desc->pending_reads, id, +- offset, bt_att_get_link_type(att))) ++ if (send_read(att, attrib, desc->proxy, desc->pending_reads, id, ++ offset)) + return; + + fail: +@@ -2762,10 +2785,9 @@ static void desc_write_cb(struct gatt_db + if (opcode == BT_ATT_OP_PREP_WRITE_REQ) { + if (!device_is_trusted(device) && !desc->prep_authorized && + desc->req_prep_authorization) +- send_write(device, attrib, desc->proxy, ++ send_write(att, attrib, desc->proxy, + desc->pending_writes, id, value, len, +- offset, bt_att_get_link_type(att), +- false, true); ++ offset, false, true); + else + gatt_db_attribute_write_result(attrib, id, 0); + +@@ -2775,9 +2797,8 @@ static void desc_write_cb(struct gatt_db + if (opcode == BT_ATT_OP_EXEC_WRITE_REQ) + desc->prep_authorized = false; + +- if (send_write(device, attrib, desc->proxy, desc->pending_writes, id, +- value, len, offset, bt_att_get_link_type(att), false, +- false)) ++ if (send_write(att, attrib, desc->proxy, desc->pending_writes, id, ++ value, len, offset, false, false)) + return; + + fail: +@@ -2856,8 +2877,8 @@ static void chrc_read_cb(struct gatt_db_ + goto fail; + } + +- if (send_read(device, attrib, chrc->proxy, chrc->pending_reads, id, +- offset, bt_att_get_link_type(att))) ++ if (send_read(att, attrib, chrc->proxy, chrc->pending_reads, id, ++ offset)) + return; + + fail: +@@ -2895,9 +2916,9 @@ static void chrc_write_cb(struct gatt_db + if (opcode == BT_ATT_OP_PREP_WRITE_REQ) { + if (!device_is_trusted(device) && !chrc->prep_authorized && + chrc->req_prep_authorization) +- send_write(device, attrib, chrc->proxy, queue, ++ send_write(att, attrib, chrc->proxy, queue, + id, value, len, offset, +- bt_att_get_link_type(att), true, true); ++ true, true); + else + gatt_db_attribute_write_result(attrib, id, 0); + +@@ -2918,13 +2939,12 @@ static void chrc_write_cb(struct gatt_db + } + + if (g_dbus_proxy_get_property(chrc->proxy, "WriteAcquired", &iter)) { +- if (acquire_write(chrc, device, attrib, id, value, len, +- bt_att_get_link_type(att))) ++ if (acquire_write(chrc, att, attrib, id, value, len)) + return; + } + +- if (send_write(device, attrib, chrc->proxy, queue, id, value, len, +- offset, bt_att_get_link_type(att), false, false)) ++ if (send_write(att, attrib, chrc->proxy, queue, id, value, len, ++ offset, false, false)) + return; + + fail: diff -Nru bluez-5.53/debian/patches/CVE-2022-0204.patch bluez-5.53/debian/patches/CVE-2022-0204.patch --- bluez-5.53/debian/patches/CVE-2022-0204.patch 1970-01-01 00:00:00.000000000 +0000 +++ bluez-5.53/debian/patches/CVE-2022-0204.patch 2022-02-03 11:26:18.000000000 +0000 @@ -0,0 +1,59 @@ +From 591c546c536b42bef696d027f64aa22434f8c3f0 Mon Sep 17 00:00:00 2001 +From: Luiz Augusto von Dentz +Date: Tue, 8 Jun 2021 16:46:49 -0700 +Subject: [PATCH] shared/gatt-server: Fix heap overflow when appending prepare + writes + +The code shall check if the prepare writes would append more the +allowed maximum attribute length. + +Fixes https://github.com/bluez/bluez/security/advisories/GHSA-479m-xcq5-9g2q +--- + src/shared/gatt-server.c | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +--- a/src/shared/gatt-server.c ++++ b/src/shared/gatt-server.c +@@ -796,6 +796,20 @@ static uint8_t authorize_req(struct bt_g + server->authorize_data); + } + ++static uint8_t check_length(uint16_t length, uint16_t offset) ++{ ++ if (length > BT_ATT_MAX_VALUE_LEN) ++ return BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN; ++ ++ if (offset > BT_ATT_MAX_VALUE_LEN) ++ return BT_ATT_ERROR_INVALID_OFFSET; ++ ++ if (length + offset > BT_ATT_MAX_VALUE_LEN) ++ return BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN; ++ ++ return 0; ++} ++ + static void write_cb(uint8_t opcode, const void *pdu, + uint16_t length, void *user_data) + { +@@ -826,6 +840,10 @@ static void write_cb(uint8_t opcode, con + (opcode == BT_ATT_OP_WRITE_REQ) ? "Req" : "Cmd", + handle); + ++ ecode = check_length(length, 0); ++ if (ecode) ++ goto error; ++ + ecode = check_permissions(server, attr, BT_ATT_PERM_WRITE_MASK); + if (ecode) + goto error; +@@ -1292,6 +1310,10 @@ static void prep_write_cb(uint8_t opcode + util_debug(server->debug_callback, server->debug_data, + "Prep Write Req - handle: 0x%04x", handle); + ++ ecode = check_length(length, offset); ++ if (ecode) ++ goto error; ++ + ecode = check_permissions(server, attr, BT_ATT_PERM_WRITE_MASK); + if (ecode) + goto error; diff -Nru bluez-5.53/debian/patches/CVE-2023-45866.patch bluez-5.53/debian/patches/CVE-2023-45866.patch --- bluez-5.53/debian/patches/CVE-2023-45866.patch 1970-01-01 00:00:00.000000000 +0000 +++ bluez-5.53/debian/patches/CVE-2023-45866.patch 2023-11-29 08:58:15.000000000 +0000 @@ -0,0 +1,45 @@ +From 25a471a83e02e1effb15d5a488b3f0085eaeb675 Mon Sep 17 00:00:00 2001 +From: Luiz Augusto von Dentz +Date: Tue, 10 Oct 2023 13:03:12 -0700 +Subject: input.conf: Change default of ClassicBondedOnly + +This changes the default of ClassicBondedOnly since defaulting to false +is not inline with HID specification which mandates the of Security Mode +4: + +BLUETOOTH SPECIFICATION Page 84 of 123 +Human Interface Device (HID) Profile: + + 5.4.3.4.2 Security Modes + Bluetooth HID Hosts shall use Security Mode 4 when interoperating with + Bluetooth HID devices that are compliant to the Bluetooth Core + Specification v2.1+EDR[6]. +--- + profiles/input/device.c | 2 +- + profiles/input/input.conf | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +(limited to 'profiles/input') + +--- bluez-5.53.orig/profiles/input/device.c ++++ bluez-5.53/profiles/input/device.c +@@ -92,7 +92,7 @@ struct input_device { + + static int idle_timeout = 0; + static bool uhid_enabled = false; +-static bool classic_bonded_only = false; ++static bool classic_bonded_only = true; + + void input_set_idle_timeout(int timeout) + { +--- bluez-5.53.orig/profiles/input/input.conf ++++ bluez-5.53/profiles/input/input.conf +@@ -17,7 +17,7 @@ + # platforms may want to make sure that input connections only come from bonded + # device connections. Several older mice have been known for not supporting + # pairing/encryption. +-# Defaults to false to maximize device compatibility. ++# Defaults to true for security. + #ClassicBondedOnly=true + + # LE upgrade security diff -Nru bluez-5.53/debian/patches/avdtp-security-2.patch bluez-5.53/debian/patches/avdtp-security-2.patch --- bluez-5.53/debian/patches/avdtp-security-2.patch 1970-01-01 00:00:00.000000000 +0000 +++ bluez-5.53/debian/patches/avdtp-security-2.patch 2022-06-08 11:09:00.000000000 +0000 @@ -0,0 +1,35 @@ +From 0388794dc5fdb73a4ea88bcf148de0a12b4364d4 Mon Sep 17 00:00:00 2001 +From: Archie Pusaka +Date: Thu, 17 Jun 2021 08:53:34 +0800 +Subject: avdtp: Fix parsing capabilities + +This patch fixes size comparison and variable misassignment. + +Reviewed-by: Alain Michaud +Reviewed-by: Michael Sun +--- + profiles/audio/avdtp.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +(limited to 'profiles/audio/avdtp.c') + +--- a/profiles/audio/avdtp.c ++++ b/profiles/audio/avdtp.c +@@ -1271,7 +1271,7 @@ static GSList *caps_to_list(uint8_t *dat + + cap = (struct avdtp_service_capability *)data; + +- if (sizeof(*cap) + cap->length >= size) { ++ if (sizeof(*cap) + cap->length > size) { + error("Invalid capability data in getcap resp"); + break; + } +@@ -1293,7 +1293,7 @@ static GSList *caps_to_list(uint8_t *dat + switch (cap->category) { + case AVDTP_MEDIA_CODEC: + if (codec) +- *codec = cap; ++ *codec = cpy; + break; + case AVDTP_DELAY_REPORTING: + if (delay_reporting) diff -Nru bluez-5.53/debian/patches/avdtp-security.patch bluez-5.53/debian/patches/avdtp-security.patch --- bluez-5.53/debian/patches/avdtp-security.patch 1970-01-01 00:00:00.000000000 +0000 +++ bluez-5.53/debian/patches/avdtp-security.patch 2022-06-08 11:08:45.000000000 +0000 @@ -0,0 +1,102 @@ +From 7a80d2096f1b7125085e21448112aa02f49f5e9a Mon Sep 17 00:00:00 2001 +From: Luiz Augusto von Dentz +Date: Thu, 29 Apr 2021 17:10:50 -0700 +Subject: avdtp: Fix accepting invalid/malformed capabilities + +Check if capabilities are valid before attempting to copy them. +--- + profiles/audio/avdtp.c | 56 ++++++++++++++++++++++++++++++++------------------ + 1 file changed, 36 insertions(+), 20 deletions(-) + +--- a/profiles/audio/avdtp.c ++++ b/profiles/audio/avdtp.c +@@ -1253,43 +1253,53 @@ struct avdtp_remote_sep *avdtp_find_remo + return NULL; + } + +-static GSList *caps_to_list(uint8_t *data, int size, ++static GSList *caps_to_list(uint8_t *data, size_t size, + struct avdtp_service_capability **codec, + gboolean *delay_reporting) + { ++ struct avdtp_service_capability *cap; + GSList *caps; +- int processed; + + if (delay_reporting) + *delay_reporting = FALSE; + +- for (processed = 0, caps = NULL; processed + 2 <= size;) { +- struct avdtp_service_capability *cap; +- uint8_t length, category; ++ if (size < sizeof(*cap)) ++ return NULL; + +- category = data[0]; +- length = data[1]; ++ for (caps = NULL; size >= sizeof(*cap);) { ++ struct avdtp_service_capability *cpy; + +- if (processed + 2 + length > size) { ++ cap = (struct avdtp_service_capability *)data; ++ ++ if (sizeof(*cap) + cap->length >= size) { + error("Invalid capability data in getcap resp"); + break; + } + +- cap = g_malloc(sizeof(struct avdtp_service_capability) + +- length); +- memcpy(cap, data, 2 + length); +- +- processed += 2 + length; +- data += 2 + length; +- +- caps = g_slist_append(caps, cap); +- +- if (category == AVDTP_MEDIA_CODEC && +- length >= +- sizeof(struct avdtp_media_codec_capability)) +- *codec = cap; +- else if (category == AVDTP_DELAY_REPORTING && delay_reporting) +- *delay_reporting = TRUE; ++ if (cap->category == AVDTP_MEDIA_CODEC && ++ cap->length < sizeof(**codec)) { ++ error("Invalid codec data in getcap resp"); ++ break; ++ } ++ ++ cpy = btd_malloc(sizeof(*cpy) + cap->length); ++ memcpy(cpy, cap, sizeof(*cap) + cap->length); ++ ++ size -= sizeof(*cap) + cap->length; ++ data += sizeof(*cap) + cap->length; ++ ++ caps = g_slist_append(caps, cpy); ++ ++ switch (cap->category) { ++ case AVDTP_MEDIA_CODEC: ++ if (codec) ++ *codec = cap; ++ break; ++ case AVDTP_DELAY_REPORTING: ++ if (delay_reporting) ++ *delay_reporting = TRUE; ++ break; ++ } + } + + return caps; +@@ -1486,6 +1496,12 @@ static gboolean avdtp_setconf_cmd(struct + &stream->codec, + &stream->delay_reporting); + ++ if (!stream->caps || !stream->codec) { ++ err = AVDTP_UNSUPPORTED_CONFIGURATION; ++ category = 0x00; ++ goto failed_stream; ++ } ++ + /* Verify that the Media Transport capability's length = 0. Reject otherwise */ + for (l = stream->caps; l != NULL; l = g_slist_next(l)) { + struct avdtp_service_capability *cap = l->data; diff -Nru bluez-5.53/debian/patches/avrcp-security.patch bluez-5.53/debian/patches/avrcp-security.patch --- bluez-5.53/debian/patches/avrcp-security.patch 1970-01-01 00:00:00.000000000 +0000 +++ bluez-5.53/debian/patches/avrcp-security.patch 2022-06-08 11:08:55.000000000 +0000 @@ -0,0 +1,29 @@ +From e2b0f0d8d63e1223bb714a9efb37e2257818268b Mon Sep 17 00:00:00 2001 +From: Luiz Augusto von Dentz +Date: Thu, 29 Apr 2021 18:18:57 -0700 +Subject: avrcp: Fix not checking if params_len match number of received bytes + +This makes sure the number of bytes in the params_len matches the +remaining bytes received so the code don't end up accessing invalid +memory. +--- + profiles/audio/avrcp.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/profiles/audio/avrcp.c ++++ b/profiles/audio/avrcp.c +@@ -1845,6 +1845,14 @@ static size_t handle_vendordep_pdu(struc + goto err_metadata; + } + ++ operands += sizeof(*pdu); ++ operand_count -= sizeof(*pdu); ++ ++ if (pdu->params_len != operand_count) { ++ DBG("AVRCP PDU parameters length don't match"); ++ pdu->params_len = operand_count; ++ } ++ + for (handler = session->control_handlers; handler->pdu_id; handler++) { + if (handler->pdu_id == pdu->pdu_id) + break; diff -Nru bluez-5.53/debian/patches/raspi-bcm43xx-3wire.patch bluez-5.53/debian/patches/raspi-bcm43xx-3wire.patch --- bluez-5.53/debian/patches/raspi-bcm43xx-3wire.patch 1970-01-01 00:00:00.000000000 +0000 +++ bluez-5.53/debian/patches/raspi-bcm43xx-3wire.patch 2021-03-15 19:25:22.000000000 +0000 @@ -0,0 +1,20 @@ +Author: Simon Long +Forwarded: https://patchwork.kernel.org/project/bluetooth/patch/20201218190609.107898-2-dave.jones@canonical.com/ +Last-Update: 2017-04-05 +Description: Patches to add BCM43xx 3-wire variant + This patch adds the bcm43xx-3wire variant to the hciattach tool; this is + for use when the mini-UART (which lacks flow-control) is used instead of the + PL011 UART to drive the bluetooth module + +--- a/tools/hciattach.c ++++ b/tools/hciattach.c +@@ -1091,6 +1091,9 @@ + { "bcm43xx", 0x0000, 0x0000, HCI_UART_H4, 115200, 3000000, + FLOW_CTL, DISABLE_PM, NULL, bcm43xx, NULL }, + ++ { "bcm43xx-3wire", 0x0000, 0x0000, HCI_UART_3WIRE, 115200, 3000000, ++ 0, DISABLE_PM, NULL, bcm43xx, NULL }, ++ + { "ath3k", 0x0000, 0x0000, HCI_UART_ATH3K, 115200, 115200, + FLOW_CTL, DISABLE_PM, NULL, ath3k_ps, ath3k_pm }, + diff -Nru bluez-5.53/debian/patches/raspi-bcm43xx-load-firmware.patch bluez-5.53/debian/patches/raspi-bcm43xx-load-firmware.patch --- bluez-5.53/debian/patches/raspi-bcm43xx-load-firmware.patch 1970-01-01 00:00:00.000000000 +0000 +++ bluez-5.53/debian/patches/raspi-bcm43xx-load-firmware.patch 2021-03-15 19:25:22.000000000 +0000 @@ -0,0 +1,31 @@ +Author: Simon Long +Forwarded: https://patchwork.kernel.org/project/bluetooth/patch/20201218190609.107898-4-dave.jones@canonical.com/ +Last-Update: 2020-12-18 +Description: Patches for loading the bcm43xx firmware + This patch corrects the location of the firmware from /etc/firmware to + /lib/firmware, and disables setting the UART interface speed *before* loading + the firmware (a later call sets the speed of the interface as requested). It + also introduces a short wait after the firmware load before the module is + reset. + +--- a/tools/hciattach_bcm43xx.c ++++ b/tools/hciattach_bcm43xx.c +@@ -44,7 +44,7 @@ + #include "hciattach.h" + + #ifndef FIRMWARE_DIR +-#define FIRMWARE_DIR "/etc/firmware" ++#define FIRMWARE_DIR "/lib/firmware" + #endif + + #define FW_EXT ".hcd" +@@ -369,9 +369,6 @@ + if (bcm43xx_locate_patch(FIRMWARE_DIR, chip_name, fw_path)) { + fprintf(stderr, "Patch not found, continue anyway\n"); + } else { +- if (bcm43xx_set_speed(fd, ti, speed)) +- return -1; +- + if (bcm43xx_load_firmware(fd, fw_path)) + return -1; + diff -Nru bluez-5.53/debian/patches/raspi-cypress-305-bdaddr.patch bluez-5.53/debian/patches/raspi-cypress-305-bdaddr.patch --- bluez-5.53/debian/patches/raspi-cypress-305-bdaddr.patch 1970-01-01 00:00:00.000000000 +0000 +++ bluez-5.53/debian/patches/raspi-cypress-305-bdaddr.patch 2021-03-15 19:25:22.000000000 +0000 @@ -0,0 +1,23 @@ +From: Phil Elwell +Forwarded: https://patchwork.kernel.org/project/bluetooth/patch/20201218190609.107898-3-dave.jones@canonical.com/ +Subject: Patch Cypress 305 devices to behave as Broadcom devices + +--- + tools/bdaddr.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/tools/bdaddr.c b/tools/bdaddr.c +index 952e99077..55fad4b46 100644 +--- a/tools/bdaddr.c ++++ b/tools/bdaddr.c +@@ -316,6 +316,7 @@ static struct { + { 48, st_write_bd_addr, generic_reset_device }, + { 57, ericsson_write_bd_addr, generic_reset_device }, + { 72, mrvl_write_bd_addr, generic_reset_device }, ++ { 305, bcm_write_bd_addr, generic_reset_device }, + { 65535, NULL, NULL }, + }; + +-- +2.25.1 + diff -Nru bluez-5.53/debian/patches/series bluez-5.53/debian/patches/series --- bluez-5.53/debian/patches/series 2020-04-03 06:43:11.000000000 +0000 +++ bluez-5.53/debian/patches/series 2023-11-29 08:57:59.000000000 +0000 @@ -16,3 +16,20 @@ CVE-2020-0556-3.patch CVE-2020-0556-4.patch ubuntu_error_restart.patch +raspi-bcm43xx-3wire.patch +raspi-bcm43xx-load-firmware.patch +raspi-cypress-305-bdaddr.patch +CVE-2020-26558.patch +CVE-2020-27153.patch +CVE-2021-3588.patch +0001-fix-reading-from-rfkill-socket.patch +CVE-2021-3658.patch +CVE-2021-41229.patch +CVE-2021-43400-pre1.patch +CVE-2021-43400-pre2.patch +CVE-2021-43400.patch +CVE-2022-0204.patch +avdtp-security.patch +avdtp-security-2.patch +avrcp-security.patch +CVE-2023-45866.patch