Skip to content

Commit 814e353

Browse files
committed
bap: Fix not checking if request fits when grouping
When grouping requests with the same opcode the code was queueing them without attempt to check that that would fit in the ATT MTU causing the following trace: stack-buffer-overflow on address 0x7fffdba951f0 at pc 0x7fc15fc49d21 bp 0x7fffdba95020 sp 0x7fffdba947d0 WRITE of size 9 at 0x7fffdba951f0 thread T0 #0 0x7fc15fc49d20 in __interceptor_memcpy (/lib64/libasan.so.8+0x49d20) ruundii#1 0x71f698 in util_iov_push_mem src/shared/util.c:266 bluez#2 0x7b9312 in append_group src/shared/bap.c:3424 bluez#3 0x71ba01 in queue_foreach src/shared/queue.c:207 bluez#4 0x7b9b66 in bap_send src/shared/bap.c:3459 bluez#5 0x7ba594 in bap_process_queue src/shared/bap.c:351 Fixes: bluez#457 (comment)
1 parent 8aed9db commit 814e353

File tree

1 file changed

+34
-7
lines changed

1 file changed

+34
-7
lines changed

src/shared/bap.c

+34-7
Original file line numberDiff line numberDiff line change
@@ -3425,27 +3425,44 @@ static void append_group(void *data, void *user_data)
34253425
req->iov[i].iov_base);
34263426
}
34273427

3428+
static uint16_t bap_req_len(struct bt_bap_req *req)
3429+
{
3430+
uint16_t len = 0;
3431+
size_t i;
3432+
const struct queue_entry *e;
3433+
3434+
for (i = 0; i < req->len; i++)
3435+
len += req->iov[i].iov_len;
3436+
3437+
e = queue_get_entries(req->group);
3438+
for (; e; e = e->next)
3439+
len += bap_req_len(e->data);
3440+
3441+
return len;
3442+
}
3443+
34283444
static bool bap_send(struct bt_bap *bap, struct bt_bap_req *req)
34293445
{
34303446
struct bt_ascs *ascs = bap_get_ascs(bap);
34313447
int ret;
34323448
uint16_t handle;
3433-
uint8_t buf[64];
34343449
struct bt_ascs_ase_hdr hdr;
3435-
struct iovec iov = {
3436-
.iov_base = buf,
3437-
.iov_len = 0,
3438-
};
3450+
struct iovec iov;
34393451
size_t i;
34403452

3441-
DBG(bap, "req %p", req);
3453+
iov.iov_len = sizeof(hdr) + bap_req_len(req);
3454+
3455+
DBG(bap, "req %p len %u", req, iov.iov_len);
34423456

34433457
if (!gatt_db_attribute_get_char_data(ascs->ase_cp, NULL, &handle,
34443458
NULL, NULL, NULL)) {
34453459
DBG(bap, "Unable to find Control Point");
34463460
return false;
34473461
}
34483462

3463+
iov.iov_base = alloca(iov.iov_len);
3464+
iov.iov_len = 0;
3465+
34493466
hdr.op = req->op;
34503467
hdr.num = 1 + queue_length(req->group);
34513468

@@ -3531,9 +3548,19 @@ static bool bap_queue_req(struct bt_bap *bap, struct bt_bap_req *req)
35313548
{
35323549
struct bt_bap_req *pend;
35333550
struct queue *queue;
3551+
struct bt_att *att = bt_bap_get_att(bap);
3552+
uint16_t mtu = bt_att_get_mtu(att);
3553+
uint16_t len = 2 + bap_req_len(req);
3554+
3555+
if (len > mtu) {
3556+
DBG(bap, "Unable to queue request: req len %u > %u mtu", len,
3557+
mtu);
3558+
return false;
3559+
}
35343560

35353561
pend = queue_find(bap->reqs, match_req, req);
3536-
if (pend) {
3562+
/* Check if req can be grouped together and it fits in the MTU */
3563+
if (pend && (bap_req_len(pend) + len < mtu)) {
35373564
if (!pend->group)
35383565
pend->group = queue_new();
35393566
/* Group requests with the same opcode */

0 commit comments

Comments
 (0)