From 87eebd7d6834b431af8961094a1bfce26312262c Mon Sep 17 00:00:00 2001
From: Sylvain Beucler <beuc@debian.org>
Date: Sat, 22 Oct 2022 18:39:32 +0200
Subject: [PATCH] Import Debian changes 5.50-1.2~deb10u3

---
 debian/changelog                              |  34 ++
 debian/patches/CVE-2019-8921.patch            | 144 ++++++
 debian/patches/CVE-2019-8922.patch            |  39 ++
 debian/patches/CVE-2021-41229.patch           | 463 ++++++++++++++++++
 debian/patches/CVE-2021-43400.patch           | 347 +++++++++++++
 debian/patches/CVE-2022-0204.patch            |  64 +++
 .../CVE-2022-39176,CVE-2022-39177.patch       | 166 +++++++
 debian/patches/series                         |   7 +
 8 files changed, 1264 insertions(+)
 create mode 100644 debian/patches/CVE-2019-8921.patch
 create mode 100644 debian/patches/CVE-2019-8922.patch
 create mode 100644 debian/patches/CVE-2021-41229.patch
 create mode 100644 debian/patches/CVE-2021-43400.patch
 create mode 100644 debian/patches/CVE-2022-0204.patch
 create mode 100644 debian/patches/CVE-2022-39176,CVE-2022-39177.patch

diff --git a/debian/changelog b/debian/changelog
index 5e2f153..60c8328 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,37 @@
+bluez (5.50-1.2~deb10u3) buster-security; urgency=high
+
+  * Non-maintainer upload by the LTS Security Team.
+  * CVE-2019-8921: SDP infoleak, the vulnerability lies in the handling of
+    a SVC_ATTR_REQ by the SDP implementation of BlueZ. By crafting a
+    malicious CSTATE, it is possible to trick the server into returning
+    more bytes than the buffer actually holds, resulting in leaking
+    arbitrary heap data.
+  * CVE-2019-8922: SDP Heap Overflow; this vulnerability lies in the SDP
+    protocol handling of attribute requests as well. By requesting a huge
+    number of attributes at the same time, an attacker can overflow the
+    static buffer provided to hold the response.
+  * CVE-2021-41229: sdp_cstate_alloc_buf allocates memory which will
+    always be hung in the singly linked list of cstates and will not be
+    freed. This will cause a memory leak over time. The data can be a very
+    large object, which can be caused by an attacker continuously sending
+    sdp packets and this may cause the service of the target device to
+    crash. (Closes: #1000262)
+  * CVE-2021-43400: a use-after-free in gatt-database.c can occur when a
+    client disconnects during D-Bus processing of a WriteValue
+    call. (Closes: #998626)
+  * CVE-2022-0204: a heap overflow vulnerability was found in bluez. An
+    attacker with local network access could pass specially crafted files
+    causing an application to halt or crash, leading to a denial of
+    service. (Closes: #1003712)
+  * CVE-2022-39176: BlueZ allows physically proximate attackers to obtain
+    sensitive information because profiles/audio/avrcp.c does not validate
+    params_len.
+  * CVE-2022-39177: BlueZ allows physically proximate attackers to cause a
+    denial of service because malformed and invalid capabilities can be
+    processed in profiles/audio/avdtp.c.
+
+ -- Sylvain Beucler <beuc@debian.org>  Sat, 22 Oct 2022 18:39:32 +0200
+
 bluez (5.50-1.2~deb10u2) buster-security; urgency=high
 
   * Non-maintainer upload by the Security Team.
diff --git a/debian/patches/CVE-2019-8921.patch b/debian/patches/CVE-2019-8921.patch
new file mode 100644
index 0000000..7810635
--- /dev/null
+++ b/debian/patches/CVE-2019-8921.patch
@@ -0,0 +1,144 @@
+Origin: https://git.kernel.org/pub/scm/bluetooth/bluez.git/commit/?id=7bf67b32709d828fafa26256b4c78331760c6e93
+Reviewed-by: Sylvain Beucler <beuc@debian.org>
+Last-Update: 2022-10-18
+
+From 7bf67b32709d828fafa26256b4c78331760c6e93 Mon Sep 17 00:00:00 2001
+From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Date: Fri, 28 Sep 2018 15:04:42 +0300
+Subject: sdp: Fix not checking if cstate length
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+cstate length should be smaller than cached length otherwise the
+request shall be considered invalid as the data is not within the
+cached buffer.
+
+An independent security researcher, Julian Rauchberger, has reported
+this vulnerability to Beyond Security’s SecuriTeam Secure Disclosure
+program.
+---
+ src/sdpd-request.c | 74 ++++++++++++++++++++++++++++--------------------------
+ 1 file changed, 39 insertions(+), 35 deletions(-)
+
+Index: bluez-5.50/src/sdpd-request.c
+===================================================================
+--- bluez-5.50.orig/src/sdpd-request.c
++++ bluez-5.50/src/sdpd-request.c
+@@ -70,9 +70,16 @@ static sdp_buf_t *sdp_get_cached_rsp(sdp
+ {
+ 	sdp_cstate_list_t *p;
+ 
+-	for (p = cstates; p; p = p->next)
+-		if (p->timestamp == cstate->timestamp)
++	for (p = cstates; p; p = p->next) {
++		/* Check timestamp */
++		if (p->timestamp != cstate->timestamp)
++			continue;
++
++		/* Check if requesting more than available */
++		if (cstate->cStateValue.maxBytesSent < p->buf.data_size)
+ 			return &p->buf;
++	}
++
+ 	return 0;
+ }
+ 
+@@ -624,6 +631,31 @@ static int extract_attrs(sdp_record_t *r
+ 	return 0;
+ }
+ 
++/* Build cstate response */
++static int sdp_cstate_rsp(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);
++	uint16_t sent;
++
++	if (!cache)
++		return 0;
++
++	sent = MIN(max, cache->data_size - cstate->cStateValue.maxBytesSent);
++	memcpy(buf->data, cache->data + cstate->cStateValue.maxBytesSent, sent);
++	buf->data_size += sent;
++	cstate->cStateValue.maxBytesSent += sent;
++
++	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)
++		return sdp_set_cstate_pdu(buf, NULL);
++
++	return sdp_set_cstate_pdu(buf, cstate);
++}
++
+ /*
+  * A request for the attributes of a service record.
+  * First check if the service record (specified by
+@@ -633,7 +665,6 @@ static int extract_attrs(sdp_record_t *r
+ static int service_attr_req(sdp_req_t *req, sdp_buf_t *buf)
+ {
+ 	sdp_cont_state_t *cstate = NULL;
+-	uint8_t *pResponse = NULL;
+ 	short cstate_size = 0;
+ 	sdp_list_t *seq = NULL;
+ 	uint8_t dtd = 0;
+@@ -719,24 +750,8 @@ static int service_attr_req(sdp_req_t *r
+ 	buf->buf_size -= sizeof(uint16_t);
+ 
+ 	if (cstate) {
+-		sdp_buf_t *pCache = sdp_get_cached_rsp(cstate);
+-
+-		SDPDBG("Obtained cached rsp : %p", pCache);
+-
+-		if (pCache) {
+-			short sent = MIN(max_rsp_size, pCache->data_size - cstate->cStateValue.maxBytesSent);
+-			pResponse = pCache->data;
+-			memcpy(buf->data, pResponse + cstate->cStateValue.maxBytesSent, sent);
+-			buf->data_size += sent;
+-			cstate->cStateValue.maxBytesSent += sent;
+-
+-			SDPDBG("Response size : %d sending now : %d bytes sent so far : %d",
+-				pCache->data_size, sent, cstate->cStateValue.maxBytesSent);
+-			if (cstate->cStateValue.maxBytesSent == pCache->data_size)
+-				cstate_size = sdp_set_cstate_pdu(buf, NULL);
+-			else
+-				cstate_size = sdp_set_cstate_pdu(buf, cstate);
+-		} else {
++		cstate_size = sdp_cstate_rsp(cstate, buf, max_rsp_size);
++		if (!cstate_size) {
+ 			status = SDP_INVALID_CSTATE;
+ 			error("NULL cache buffer and non-NULL continuation state");
+ 		}
+@@ -786,7 +801,7 @@ done:
+ static int service_search_attr_req(sdp_req_t *req, sdp_buf_t *buf)
+ {
+ 	int status = 0, plen, totscanned;
+-	uint8_t *pdata, *pResponse = NULL;
++	uint8_t *pdata;
+ 	unsigned int max;
+ 	int scanned, rsp_count = 0;
+ 	sdp_list_t *pattern = NULL, *seq = NULL, *svcList;
+@@ -915,19 +930,8 @@ static int service_search_attr_req(sdp_r
+ 		} else
+ 			cstate_size = sdp_set_cstate_pdu(buf, NULL);
+ 	} else {
+-		/* continuation State exists -> get from cache */
+-		sdp_buf_t *pCache = sdp_get_cached_rsp(cstate);
+-		if (pCache && cstate->cStateValue.maxBytesSent < pCache->data_size) {
+-			uint16_t sent = MIN(max, pCache->data_size - cstate->cStateValue.maxBytesSent);
+-			pResponse = pCache->data;
+-			memcpy(buf->data, pResponse + cstate->cStateValue.maxBytesSent, sent);
+-			buf->data_size += sent;
+-			cstate->cStateValue.maxBytesSent += sent;
+-			if (cstate->cStateValue.maxBytesSent == pCache->data_size)
+-				cstate_size = sdp_set_cstate_pdu(buf, NULL);
+-			else
+-				cstate_size = sdp_set_cstate_pdu(buf, cstate);
+-		} else {
++		cstate_size = sdp_cstate_rsp(cstate, buf, max);
++		if (!cstate_size) {
+ 			status = SDP_INVALID_CSTATE;
+ 			SDPDBG("Non-null continuation state, but null cache buffer");
+ 		}
diff --git a/debian/patches/CVE-2019-8922.patch b/debian/patches/CVE-2019-8922.patch
new file mode 100644
index 0000000..2564f0c
--- /dev/null
+++ b/debian/patches/CVE-2019-8922.patch
@@ -0,0 +1,39 @@
+Origin: https://git.kernel.org/pub/scm/bluetooth/bluez.git/commit/?id=6c7243fb6ab90b7b855cead98c66394fedea135f
+Reviewed-by: Sylvain Beucler <beuc@debian.org>
+Last-Update: 2022-10-18
+
+From 6c7243fb6ab90b7b855cead98c66394fedea135f Mon Sep 17 00:00:00 2001
+From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Date: Fri, 28 Sep 2018 16:08:32 +0300
+Subject: sdp: Fix buffer overflow
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+sdp_append_buf shall check if there is enough space to store the data
+before copying it.
+
+An independent security researcher, Julian Rauchberger, has reported
+this vulnerability to Beyond Security’s SecuriTeam Secure Disclosure
+program.
+---
+ lib/sdp.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+Index: bluez-5.50/lib/sdp.c
+===================================================================
+--- bluez-5.50.orig/lib/sdp.c
++++ bluez-5.50/lib/sdp.c
+@@ -2834,6 +2834,12 @@ void sdp_append_to_buf(sdp_buf_t *dst, u
+ 	SDPDBG("Append src size: %d", len);
+ 	SDPDBG("Append dst size: %d", dst->data_size);
+ 	SDPDBG("Dst buffer size: %d", dst->buf_size);
++
++	if (dst->data_size + len > dst->buf_size) {
++		SDPERR("Cannot append");
++		return;
++	}
++
+ 	if (dst->data_size == 0 && dtd == 0) {
+ 		/* create initial sequence */
+ 		*p = SDP_SEQ8;
diff --git a/debian/patches/CVE-2021-41229.patch b/debian/patches/CVE-2021-41229.patch
new file mode 100644
index 0000000..f8c3714
--- /dev/null
+++ b/debian/patches/CVE-2021-41229.patch
@@ -0,0 +1,463 @@
+Origin: https://git.kernel.org/pub/scm/bluetooth/bluez.git/commit/?id=e79417ed7185b150a056d4eb3a1ab528b91d2fc0
+Reviewed-by: Sylvain Beucler <beuc@debian.org>
+Last-Update: 2022-10-18
+
+From e79417ed7185b150a056d4eb3a1ab528b91d2fc0 Mon Sep 17 00:00:00 2001
+From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+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(-)
+
+Index: bluez-5.50/src/sdpd-request.c
+===================================================================
+--- bluez-5.50.orig/src/sdpd-request.c
++++ bluez-5.50/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);
++	}
++}
+Index: bluez-5.50/src/sdpd-server.c
+===================================================================
+--- bluez-5.50.orig/src/sdpd-server.c
++++ bluez-5.50/src/sdpd-server.c
+@@ -158,16 +158,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);
+@@ -180,14 +176,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)
+Index: bluez-5.50/src/sdpd.h
+===================================================================
+--- bluez-5.50.orig/src/sdpd.h
++++ bluez-5.50/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);
+ 
+Index: bluez-5.50/unit/test-sdp.c
+===================================================================
+--- bluez-5.50.orig/unit/test-sdp.c
++++ bluez-5.50/unit/test-sdp.c
+@@ -257,7 +257,7 @@ static gboolean client_handler(GIOChanne
+ 	util_hexdump('>', buf, len, sdp_debug, "SDP: ");
+ 
+ 	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 --git a/debian/patches/CVE-2021-43400.patch b/debian/patches/CVE-2021-43400.patch
new file mode 100644
index 0000000..1f97f2d
--- /dev/null
+++ b/debian/patches/CVE-2021-43400.patch
@@ -0,0 +1,347 @@
+Origin: https://git.kernel.org/pub/scm/bluetooth/bluez.git/commit/?id=838c0dc7641e1c991c0f3027bf94bee4606012f8
+Reviewed-by: Sylvain Beucler <beuc@debian.org>
+Last-Update: 2022-10-22
+
+From 838c0dc7641e1c991c0f3027bf94bee4606012f8 Mon Sep 17 00:00:00 2001
+From: Bernie Conrad <bernie@allthenticate.net>
+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(-)
+
+Index: bluez-5.50/src/gatt-database.c
+===================================================================
+--- bluez-5.50.orig/src/gatt-database.c
++++ bluez-5.50/src/gatt-database.c
+@@ -151,8 +151,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;
+@@ -911,6 +912,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,
+@@ -930,21 +951,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;
+-}
+-
+-static void pending_op_free(void *data)
+-{
+-	struct pending_op *op = data;
+-
+-	if (op->owner_queue)
+-		queue_remove(op->owner_queue, op);
++	bt_att_register_disconnect(att,
++				   pending_disconnect_cb,
++				   op,
++				   NULL);
+ 
+-	free(op);
++	return op;
+ }
+ 
+ static void gatt_ccc_write_cb(struct gatt_db_attribute *attrib,
+@@ -1907,31 +1923,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);
+ 	const char *link;
+ 
+ 	switch (op->link_type) {
+@@ -1974,18 +1994,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)
+@@ -2068,15 +2086,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)
+ {
+@@ -2087,33 +2107,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,
+@@ -2225,9 +2249,9 @@ static void acquire_write_reply(DBusMess
+ 	return;
+ 
+ retry:
+-	send_write(op->device, op->attrib, chrc->proxy, NULL, op->id,
++	send_write(op->att, op->attrib, chrc->proxy, NULL, op->id,
+ 				op->data.iov_base, op->data.iov_len, 0,
+-				op->link_type, false, false);
++				false, false);
+ }
+ 
+ static void acquire_write_setup(DBusMessageIter *iter, void *user_data)
+@@ -2246,7 +2270,8 @@ static void acquire_write_setup(DBusMess
+ 
+ 	append_options(&dict, op);
+ 
+-	server = btd_device_get_gatt_server(op->device);
++	struct btd_device *device = att_get_device(op->att);
++	server = btd_device_get_gatt_server(device);
+ 
+ 	mtu = bt_gatt_server_get_mtu(server);
+ 
+@@ -2256,16 +2281,15 @@ 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;
+ 
+-	op = pending_write_new(device, NULL, attrib, id, value, len, 0,
+-						link_type, false, false);
++	op = pending_write_new(att, NULL, attrib, id, value, len, 0,
++						false, false);
+ 
+ 	if (g_dbus_proxy_method_call(chrc->proxy, "AcquireWrite",
+ 					acquire_write_setup,
+@@ -2332,7 +2356,8 @@ static void acquire_notify_setup(DBusMes
+ 
+ 	append_options(&dict, op);
+ 
+-	server = btd_device_get_gatt_server(op->device);
++	struct btd_device *device = att_get_device(op->att);
++	server = btd_device_get_gatt_server(device);
+ 
+ 	mtu = bt_gatt_server_get_mtu(server);
+ 
+@@ -2539,8 +2564,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:
+@@ -2571,10 +2596,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);
+ 
+@@ -2584,9 +2608,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:
+@@ -2636,8 +2659,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:
+@@ -2675,9 +2698,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);
+ 
+@@ -2698,13 +2721,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 --git a/debian/patches/CVE-2022-0204.patch b/debian/patches/CVE-2022-0204.patch
new file mode 100644
index 0000000..d1e9fcc
--- /dev/null
+++ b/debian/patches/CVE-2022-0204.patch
@@ -0,0 +1,64 @@
+Origin: https://git.kernel.org/pub/scm/bluetooth/bluez.git/commit/?id=591c546c536b42bef696d027f64aa22434f8c3f0
+Reviewed-by: Sylvain Beucler <beuc@debian.org>
+Last-Update: 2022-10-22
+
+From 591c546c536b42bef696d027f64aa22434f8c3f0 Mon Sep 17 00:00:00 2001
+From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Date: Tue, 8 Jun 2021 16:46:49 -0700
+Subject: 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(+)
+
+Index: bluez-5.50/src/shared/gatt-server.c
+===================================================================
+--- bluez-5.50.orig/src/shared/gatt-server.c
++++ bluez-5.50/src/shared/gatt-server.c
+@@ -783,6 +783,20 @@ static void write_complete_cb(struct gat
+ 	async_write_op_destroy(op);
+ }
+ 
++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)
+ {
+@@ -809,6 +823,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;
+@@ -1271,6 +1289,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 --git a/debian/patches/CVE-2022-39176,CVE-2022-39177.patch b/debian/patches/CVE-2022-39176,CVE-2022-39177.patch
new file mode 100644
index 0000000..cc3a03d
--- /dev/null
+++ b/debian/patches/CVE-2022-39176,CVE-2022-39177.patch
@@ -0,0 +1,166 @@
+Origin: https://git.kernel.org/pub/scm/bluetooth/bluez.git/commit/?id=e2b0f0d8d63e1223bb714a9efb37e2257818268b
+Origin: https://git.kernel.org/pub/scm/bluetooth/bluez.git/commit/?id=7a80d2096f1b7125085e21448112aa02f49f5e9a
+Origin: https://git.kernel.org/pub/scm/bluetooth/bluez.git/commit/?id=0388794dc5fdb73a4ea88bcf148de0a12b4364d4
+Origin: https://git.kernel.org/pub/scm/bluetooth/bluez.git/commit/?id=e21680c9355a0f9d5ef6d4a5ae032de274e87b37
+Reviewed-by: Sylvain Beucler <beuc@debian.org>
+Last-Update: 2022-10-22
+
+From e2b0f0d8d63e1223bb714a9efb37e2257818268b Mon Sep 17 00:00:00 2001
+From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+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.
+
+
+From 7a80d2096f1b7125085e21448112aa02f49f5e9a Mon Sep 17 00:00:00 2001
+From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+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.
+
+
+From 0388794dc5fdb73a4ea88bcf148de0a12b4364d4 Mon Sep 17 00:00:00 2001
+From: Archie Pusaka <apusaka@chromium.org>
+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 <alainm@chromium.org>
+Reviewed-by: Michael Sun <michaelfsun@google.com>
+
+
+From e21680c9355a0f9d5ef6d4a5ae032de274e87b37 Mon Sep 17 00:00:00 2001
+From: Marijn Suijten <marijn.suijten@somainline.org>
+Date: Sun, 8 Aug 2021 16:35:26 +0200
+Subject: audio/avrcp: Use host/network order as appropriate for
+ pdu->params_len
+
+When comparing against or writing to pdu->params_len to enforce matching
+length with total packet length, take into account that pdu->params_len
+is in network order (big endian) while packet size (operand_count) is in
+host order (usually little endian).
+
+This silently breaks a number of AVRCP commands that perform a quick
+length check based on params_len and bail if it doesn't match exactly.
+
+Fixes: e2b0f0d8d ("avrcp: Fix not checking if params_len match number of received bytes")
+
+
+Index: bluez-5.50/profiles/audio/avrcp.c
+===================================================================
+--- bluez-5.50.orig/profiles/audio/avrcp.c
++++ bluez-5.50/profiles/audio/avrcp.c
+@@ -1844,6 +1844,14 @@ static size_t handle_vendordep_pdu(struc
+ 		goto err_metadata;
+ 	}
+ 
++	operands += sizeof(*pdu);
++	operand_count -= sizeof(*pdu);
++
++	if (ntohs(pdu->params_len) != operand_count) {
++		DBG("AVRCP PDU parameters length don't match");
++		pdu->params_len = htons(operand_count);
++	}
++
+ 	for (handler = session->control_handlers; handler->pdu_id; handler++) {
+ 		if (handler->pdu_id == pdu->pdu_id)
+ 			break;
+Index: bluez-5.50/profiles/audio/avdtp.c
+===================================================================
+--- bluez-5.50.orig/profiles/audio/avdtp.c
++++ bluez-5.50/profiles/audio/avdtp.c
+@@ -1250,43 +1250,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 = cpy;
++			break;
++		case AVDTP_DELAY_REPORTING:
++			if (delay_reporting)
++				*delay_reporting = TRUE;
++			break;
++		}
+ 	}
+ 
+ 	return caps;
+@@ -1483,6 +1493,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 --git a/debian/patches/series b/debian/patches/series
index dde95b8..d75777c 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -15,3 +15,10 @@ input-hog-Attempt-to-set-security-level-if-not-bonde.patch
 input-Add-LEAutoSecurity-setting-to-input.conf.patch
 shared-att-Fix-possible-crash-on-disconnect.patch
 shared-gatt-server-Fix-not-properly-checking-for-sec.patch
+
+CVE-2019-8921.patch
+CVE-2019-8922.patch
+CVE-2021-41229.patch
+CVE-2021-43400.patch
+CVE-2022-0204.patch
+CVE-2022-39176,CVE-2022-39177.patch
-- 
GitLab