Skip to content
Snippets Groups Projects
Commit 87eebd7d authored by Sylvain Beucler's avatar Sylvain Beucler Committed by Vignesh Raman
Browse files

Import Debian changes 5.50-1.2~deb10u3

parent 142c5e39
Branches debian/buster-security
Tags debian/5.50-1.2_deb10u3
3 merge requests!35Merge changes from apertis/v2021-security into apertis/v2021,!34Update from debian/buster-security for apertis/v2021-security,!33Draft: Update from debian/buster-backports for apertis/v2021-updates
Pipeline #432449 failed
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.
......
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");
}
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;
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);
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:
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;
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;
......@@ -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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment