* [PATCH] Fix Out-of-Bounds Read in AVRCP GetFolderItems parsing
@ 2026-08-02 4:06 Elman Shahbazov
2026-08-02 6:20 ` bluez.test.bot
0 siblings, 1 reply; 3+ messages in thread
From: Elman Shahbazov @ 2026-08-02 4:06 UTC (permalink / raw)
To: linux-bluetooth; +Cc: secalert, Luiz Augusto von Dentz
[-- Attachment #1.1: Type: text/plain, Size: 4485 bytes --]
Hello BlueZ maintainers and Red Hat Security team,
This is v2 of the patch fixing an Out-of-Bounds Read vulnerability in the
AVRCP profile. The previous submission (v1) was automatically rejected by
Patchwork due to email client formatting corrupting the diff (spaces
replacing
tabs). To resolve this, the patch is now attached as a standard .patch file
generated by git format-patch.
Below is a detailed technical analysis of the vulnerability, the threat
model,
and instructions for reproducing the issue.
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)
During a source code audit of the AVRCP Browsing profile, a logical flaw was
discovered in the parsing of the GetFolderItems response.
The vulnerable functions extract the length of the media item name (namesize
or namelen) directly from the network packet (controlled by the remote
device)
and use it to copy data into a local stack buffer char name[255] via memcpy.
While the code attempts to prevent a stack-based buffer overflow by
limiting the
copy length using MIN(namesize, sizeof(name) - 1), it completely fails to
validate this extracted length against the actual size of the incoming
packet (len).
2. Root Cause Analysis
In parse_media_element, the code proceeds as follows:
if (len < 13)
return NULL;
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 buffer that might only be
14 bytes long
memcpy(name, &operands[13], namelen);
strtoutf8(name, namelen);
}
// OOB READ: 13 + 1000 = 1013. Reads far beyond the packet boundary
count = operands[13 + namesize];
If a remote device sends a packet where the namesize field is large (e.g.,
1000)
but the actual packet length (len) is very small (e.g., 14 bytes), the
memcpy
will read 254 bytes starting from &operands[13]. Since the packet is only
14 bytes
long, this results in a 253-byte Out-of-Bounds Read.
Furthermore, the subsequent access operands[13 + namesize] attempts to read
a byte
at offset 1013, which guarantees a segmentation fault if the memory is
unmapped.
A similar flaw exists in parse_media_folder where namelen is not bounded by
len:
namelen = MIN(get_be16(&operands[12]), sizeof(name) - 1);
if (namelen > 0)
memcpy(name, &operands[14], namelen); // OOB READ if len < 268
3. Impact and Threat Model
* Attack Vector: Adjacent Network (Bluetooth)
* User Interaction: Required (UI:R) - The victim must connect to the
malicious device.
* Impact: Denial of Service (DoS) / Potential Information Disclosure.
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. This results in a SIGSEGV and an immediate crash of the
Bluetooth
daemon (DoS). In certain heap configurations, the read data could be
processed and
leaked, leading to Information Disclosure.
4. Proof of Concept (PoC)
I have attached poc_avrcp_obb.c which extracts the vulnerable logic and
simulates
the attack using a 14-byte malicious packet with an inflated namesize of
1000.
To verify the vulnerability:
1. Compile with AddressSanitizer:
gcc -fsanitize=address -g -o poc_avrcp_oob poc_avrcp_obb.c
2. Run the binary:
./poc_avrcp_oob
ASan will immediately detect the out-of-bounds access and abort:
=================================================================
==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
[ 5. Proposed Fix
The attached patch ensures that the length extracted from the packet is
strictly
validated against the remaining bytes in the packet buffer (len) before
being
used in memcpy. It also adds boundary checks before accessing subsequent
offsets.
Please review the attached .patch file. I am requesting a CVE assignment for
this issue given its impact on system availability.
Best regards,
Elman Shahbazov
Security Researcher
[-- Attachment #1.2: Type: text/html, Size: 4904 bytes --]
[-- Attachment #2: 0001-Fix-Out-of-Bounds-Read-in-AVRCP-GetFolderItems-parsi.patch --]
[-- Type: text/x-patch, Size: 1351 bytes --]
From bd2dd19b299e8c79780c82621a7b0649b585bc65 Mon Sep 17 00:00:00 2001
From: Elman Shahbazov <shahbazovelman97@gmail.com>
Date: Sun, 2 Aug 2026 07:57:53 +0400
Subject: [PATCH] Fix Out-of-Bounds Read in AVRCP GetFolderItems parsing
Signed-off-by: Elman Shahbazov <shahbazovelman97@gmail.com>
---
profiles/audio/avrcp.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
index 2194a9135..19ea13c16 100644
--- a/profiles/audio/avrcp.c
+++ b/profiles/audio/avrcp.c
@@ -2625,8 +2625,12 @@ 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]);
+ namesize = MIN(get_be16(&operands[11]), len - 13);
namelen = MIN(namesize, sizeof(name) - 1);
+
+ if (len < 13 + namesize)
+ return NULL;
+
if (namelen > 0) {
memcpy(name, &operands[13], namelen);
strtoutf8(name, namelen);
@@ -2669,7 +2673,8 @@ static struct media_item *parse_media_folder(struct avrcp *session,
playable = operands[9];
memset(name, 0, sizeof(name));
- namelen = MIN(get_be16(&operands[12]), sizeof(name) - 1);
+ namelen = MIN(get_be16(&operands[12]), len - 14);
+ namelen = MIN(namelen, sizeof(name) - 1);
if (namelen > 0)
memcpy(name, &operands[14], namelen);
--
2.53.0
[-- Attachment #3: 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 related [flat|nested] 3+ messages in thread* [PATCH] Fix Out-of-Bounds Read in AVRCP GetFolderItems parsing
@ 2026-08-02 7:58 Elman Shahbazov
2026-08-02 9:14 ` bluez.test.bot
0 siblings, 1 reply; 3+ messages in thread
From: Elman Shahbazov @ 2026-08-02 7:58 UTC (permalink / raw)
To: linux-bluetooth; +Cc: secalert, luiz.dentz, Elman Shahbazov
Signed-off-by: Elman Shahbazov <shahbazovelman97@gmail.com>
---
profiles/audio/avrcp.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
index 2194a9135..19ea13c16 100644
--- a/profiles/audio/avrcp.c
+++ b/profiles/audio/avrcp.c
@@ -2625,8 +2625,12 @@ 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]);
+ namesize = MIN(get_be16(&operands[11]), len - 13);
namelen = MIN(namesize, sizeof(name) - 1);
+
+ if (len < 13 + namesize)
+ return NULL;
+
if (namelen > 0) {
memcpy(name, &operands[13], namelen);
strtoutf8(name, namelen);
@@ -2669,7 +2673,8 @@ static struct media_item *parse_media_folder(struct avrcp *session,
playable = operands[9];
memset(name, 0, sizeof(name));
- namelen = MIN(get_be16(&operands[12]), sizeof(name) - 1);
+ namelen = MIN(get_be16(&operands[12]), len - 14);
+ namelen = MIN(namelen, sizeof(name) - 1);
if (namelen > 0)
memcpy(name, &operands[14], namelen);
--
2.53.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-08-02 9:14 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-02 4:06 [PATCH] Fix Out-of-Bounds Read in AVRCP GetFolderItems parsing Elman Shahbazov
2026-08-02 6:20 ` bluez.test.bot
-- strict thread matches above, loose matches on Subject: below --
2026-08-02 7:58 [PATCH] " Elman Shahbazov
2026-08-02 9:14 ` 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