* [BlueZ, v2 0/3] avrcp: Fix Out-of-Bounds Read in AVRCP GetFolderItems parsing
@ 2026-08-04 14:23 Bastien Nocera
2026-08-04 14:23 ` [BlueZ, v2 1/3] avrcp: Split off name parsing from parse_*_element() Bastien Nocera
` (2 more replies)
0 siblings, 3 replies; 12+ messages in thread
From: Bastien Nocera @ 2026-08-04 14:23 UTC (permalink / raw)
To: linux-bluetooth
Changes since v1:
- Add missing inttypes.h include to split-off parsing functions
Bastien Nocera (2):
avrcp: Split off name parsing from parse_*_element()
unit: Adapt poc_*_oob.c test into a new test
Elman Shahbazov (1):
avrcp: Fix Out-of-Bounds Read in AVRCP GetFolderItems parsing
Makefile.am | 9 +++++
Makefile.plugins | 1 +
profiles/audio/avrcp-parse.c | 52 ++++++++++++++++++++++++
profiles/audio/avrcp-parse.h | 19 +++++++++
profiles/audio/avrcp.c | 26 +++---------
unit/test-avrcp-sec.c | 76 ++++++++++++++++++++++++++++++++++++
6 files changed, 163 insertions(+), 20 deletions(-)
create mode 100644 profiles/audio/avrcp-parse.c
create mode 100644 profiles/audio/avrcp-parse.h
create mode 100644 unit/test-avrcp-sec.c
--
2.55.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* [BlueZ, v2 1/3] avrcp: Split off name parsing from parse_*_element()
2026-08-04 14:23 [BlueZ, v2 0/3] avrcp: Fix Out-of-Bounds Read in AVRCP GetFolderItems parsing Bastien Nocera
@ 2026-08-04 14:23 ` Bastien Nocera
2026-08-04 16:27 ` avrcp: Fix Out-of-Bounds Read in AVRCP GetFolderItems parsing bluez.test.bot
2026-08-05 17:12 ` [BlueZ, v2 1/3] avrcp: Split off name parsing from parse_*_element() Luiz Augusto von Dentz
2026-08-04 14:23 ` [BlueZ, v2 2/3] unit: Adapt poc_*_oob.c test into a new test Bastien Nocera
2026-08-04 14:23 ` [BlueZ, v2 3/3] avrcp: Fix Out-of-Bounds Read in AVRCP GetFolderItems parsing Bastien Nocera
2 siblings, 2 replies; 12+ messages in thread
From: Bastien Nocera @ 2026-08-04 14:23 UTC (permalink / raw)
To: linux-bluetooth
This will allow us to use the name extraction code in
parse_media_element() and parse_folder_element() separately, such
as in tests.
---
Makefile.plugins | 1 +
profiles/audio/avrcp-parse.c | 47 ++++++++++++++++++++++++++++++++++++
profiles/audio/avrcp-parse.h | 19 +++++++++++++++
profiles/audio/avrcp.c | 26 +++++---------------
4 files changed, 73 insertions(+), 20 deletions(-)
create mode 100644 profiles/audio/avrcp-parse.c
create mode 100644 profiles/audio/avrcp-parse.h
diff --git a/Makefile.plugins b/Makefile.plugins
index ac667beda847..a505fcd6691f 100644
--- a/Makefile.plugins
+++ b/Makefile.plugins
@@ -37,6 +37,7 @@ builtin_modules += avrcp
builtin_sources += profiles/audio/control.h profiles/audio/control.c \
profiles/audio/avctp.h profiles/audio/avctp.c \
profiles/audio/avrcp.h profiles/audio/avrcp.c \
+ profiles/audio/avrcp-parse.h profiles/audio/avrcp-parse.c \
profiles/audio/avrcp-player.c
endif
diff --git a/profiles/audio/avrcp-parse.c b/profiles/audio/avrcp-parse.c
new file mode 100644
index 000000000000..d3d0a070a4da
--- /dev/null
+++ b/profiles/audio/avrcp-parse.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2026 Red Hat Inc.
+ *
+ *
+ */
+
+#include "avrcp-parse.h"
+#include "src/shared/util.h"
+
+gboolean parse_media_element_name(uint8_t *operands, uint16_t len,
+ char *name, uint16_t *namesize)
+{
+ uint16_t namelen;
+
+ if (len < 13)
+ return FALSE;
+
+ memset(name, 0, NAME_MAX_LEN);
+ *namesize = get_be16(&operands[11]);
+ namelen = MIN(*namesize, NAME_MAX_LEN - 1);
+ if (namelen > 0) {
+ memcpy(name, &operands[13], namelen);
+ strtoutf8(name, namelen);
+ }
+
+ return TRUE;
+}
+
+gboolean parse_media_folder_name(uint8_t *operands, uint16_t len,
+ char *name)
+{
+ uint16_t namelen;
+
+ if (len < 12)
+ return FALSE;
+
+ memset(name, 0, NAME_MAX_LEN);
+ namelen = MIN(get_be16(&operands[12]), NAME_MAX_LEN - 1);
+ if (namelen > 0)
+ memcpy(name, &operands[14], namelen);
+
+ return TRUE;
+}
diff --git a/profiles/audio/avrcp-parse.h b/profiles/audio/avrcp-parse.h
new file mode 100644
index 000000000000..f7a33c854442
--- /dev/null
+++ b/profiles/audio/avrcp-parse.h
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2026 Red Hat Inc.
+ *
+ *
+ */
+
+#include <glib.h>
+#include <inttypes.h>
+
+#define NAME_MAX_LEN 255
+
+gboolean parse_media_element_name(uint8_t *operands, uint16_t len,
+ char *name, uint16_t *namesize);
+gboolean parse_media_folder_name(uint8_t *operands, uint16_t len,
+ char *name);
diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
index 2194a913580f..af3c72174764 100644
--- a/profiles/audio/avrcp.c
+++ b/profiles/audio/avrcp.c
@@ -52,6 +52,7 @@
#include "avctp.h"
#include "avrcp.h"
+#include "avrcp-parse.h"
#include "control.h"
#include "media.h"
#include "player.h"
@@ -2614,24 +2615,15 @@ static struct media_item *parse_media_element(struct avrcp *session,
struct avrcp_player *player;
struct media_player *mp;
struct media_item *item;
- uint16_t namelen, namesize;
- char name[255];
+ uint16_t namesize;
+ char name[NAME_MAX_LEN];
uint64_t uid;
uint8_t count;
- if (len < 13)
+ if (!parse_media_element_name(operands, len, name, &namesize))
return NULL;
uid = get_be64(&operands[0]);
-
- memset(name, 0, sizeof(name));
- namesize = get_be16(&operands[11]);
- namelen = MIN(namesize, sizeof(name) - 1);
- if (namelen > 0) {
- memcpy(name, &operands[13], namelen);
- strtoutf8(name, namelen);
- }
-
count = operands[13 + namesize];
player = session->controller->player;
@@ -2655,24 +2647,18 @@ static struct media_item *parse_media_folder(struct avrcp *session,
struct avrcp_player *player = session->controller->player;
struct media_player *mp = player->user_data;
struct media_item *item;
- uint16_t namelen;
- char name[255];
+ char name[NAME_MAX_LEN];
uint64_t uid;
uint8_t type;
uint8_t playable;
- if (len < 12)
+ if (!parse_media_folder_name(operands, len, name))
return NULL;
uid = get_be64(&operands[0]);
type = operands[8];
playable = operands[9];
- memset(name, 0, sizeof(name));
- namelen = MIN(get_be16(&operands[12]), sizeof(name) - 1);
- if (namelen > 0)
- memcpy(name, &operands[14], namelen);
-
item = media_player_create_folder(mp, name, type, uid);
if (!item)
return NULL;
--
2.55.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [BlueZ, v2 2/3] unit: Adapt poc_*_oob.c test into a new test
2026-08-04 14:23 [BlueZ, v2 0/3] avrcp: Fix Out-of-Bounds Read in AVRCP GetFolderItems parsing Bastien Nocera
2026-08-04 14:23 ` [BlueZ, v2 1/3] avrcp: Split off name parsing from parse_*_element() Bastien Nocera
@ 2026-08-04 14:23 ` Bastien Nocera
2026-08-04 16:46 ` Luiz Augusto von Dentz
2026-08-04 14:23 ` [BlueZ, v2 3/3] avrcp: Fix Out-of-Bounds Read in AVRCP GetFolderItems parsing Bastien Nocera
2 siblings, 1 reply; 12+ messages in thread
From: Bastien Nocera @ 2026-08-04 14:23 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Elman Shahbazov
Adapt poc_avrcp_oob.c and poc_folder_oob.c into unit tests.
Co-authored-by: Elman Shahbazov <shahbazovelman97@gmail.com>
---
Makefile.am | 9 +++++
unit/test-avrcp-sec.c | 76 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 85 insertions(+)
create mode 100644 unit/test-avrcp-sec.c
diff --git a/Makefile.am b/Makefile.am
index 19c468d3a504..e3baa4155c1f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -660,6 +660,15 @@ unit_test_avrcp_SOURCES = unit/test-avrcp.c \
unit_test_avrcp_LDADD = lib/libbluetooth-internal.la \
src/libshared-glib.la $(GLIB_LIBS)
+unit_tests += unit/test-avrcp-sec
+
+unit_test_avrcp_sec_SOURCES = unit/test-avrcp-sec.c \
+ profiles/audio/avrcp-parse.c \
+ profiles/audio/avrcp-parse.h \
+ src/log.h src/log.c
+unit_test_avrcp_sec_LDADD = lib/libbluetooth-internal.la \
+ src/libshared-glib.la $(GLIB_LIBS)
+
unit_tests += unit/test-hfp
unit_test_hfp_SOURCES = unit/test-hfp.c
diff --git a/unit/test-avrcp-sec.c b/unit/test-avrcp-sec.c
new file mode 100644
index 000000000000..a100b2d68e35
--- /dev/null
+++ b/unit/test-avrcp-sec.c
@@ -0,0 +1,76 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2026 Red Hat Inc.
+ *
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+
+#include "src/shared/util.h"
+#include "src/shared/tester.h"
+#include "src/log.h"
+
+#include "profiles/audio/avrcp-parse.h"
+
+static void avrcp_element_name_oob(gconstpointer data)
+{
+ char name[255];
+ uint16_t namesize;
+ gboolean ret;
+
+ /* Crafting a malicious payload.
+ * Actual packet length (len) = 14 bytes */
+ uint8_t malicious_packet[14] = {0};
+
+ /* Specify namesize = 1000 (0x03E8 in Big Endian) at offset 11 */
+ malicious_packet[11] = 0x03;
+ malicious_packet[12] = 0xE8;
+
+ /* Launching the PoC. We transmit a 14-byte packet, but namesize=1000... */
+ ret = parse_media_element_name(malicious_packet, sizeof(malicious_packet),
+ name, &namesize);
+ if (ret)
+ tester_test_passed();
+ else
+ tester_test_failed();
+}
+
+static void avrcp_folder_name_oob(gconstpointer data)
+{
+ char name[255];
+ gboolean ret;
+
+ /* Crafting a malicious payload.
+ * Actual packet length (len) = 14 bytes */
+ uint8_t malicious_packet[14] = {0};
+
+ /* Specify namesize = 1000 (0x03E8 in Big Endian) at offset 12 */
+ malicious_packet[12] = 0x03;
+ malicious_packet[13] = 0xE8;
+
+ /* Launching the PoC. We transmit a 14-byte packet, but namesize=1000... */
+ ret = parse_media_folder_name(malicious_packet, sizeof(malicious_packet),
+ name);
+ if (ret)
+ tester_test_passed();
+ else
+ tester_test_failed();
+}
+
+int main(int argc, char *argv[])
+{
+ tester_init(&argc, &argv);
+
+ tester_add("/avrcp-element-name-oob", NULL, NULL, avrcp_element_name_oob, NULL);
+ tester_add("/avrcp-folder-name-oob", NULL, NULL, avrcp_folder_name_oob, NULL);
+
+ return tester_run();
+}
--
2.55.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [BlueZ, v2 3/3] avrcp: Fix Out-of-Bounds Read in AVRCP GetFolderItems parsing
2026-08-04 14:23 [BlueZ, v2 0/3] avrcp: Fix Out-of-Bounds Read in AVRCP GetFolderItems parsing Bastien Nocera
2026-08-04 14:23 ` [BlueZ, v2 1/3] avrcp: Split off name parsing from parse_*_element() Bastien Nocera
2026-08-04 14:23 ` [BlueZ, v2 2/3] unit: Adapt poc_*_oob.c test into a new test Bastien Nocera
@ 2026-08-04 14:23 ` Bastien Nocera
2 siblings, 0 replies; 12+ messages in thread
From: Bastien Nocera @ 2026-08-04 14:23 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Elman Shahbazov
From: Elman Shahbazov <shahbazovelman97@gmail.com>
Co-Authored-by: Bastien Nocera <hadess@hadess.net>
---
profiles/audio/avrcp-parse.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/profiles/audio/avrcp-parse.c b/profiles/audio/avrcp-parse.c
index d3d0a070a4da..251580fd9c55 100644
--- a/profiles/audio/avrcp-parse.c
+++ b/profiles/audio/avrcp-parse.c
@@ -20,8 +20,12 @@ gboolean parse_media_element_name(uint8_t *operands, uint16_t len,
return FALSE;
memset(name, 0, NAME_MAX_LEN);
- *namesize = get_be16(&operands[11]);
+ *namesize = MIN(get_be16(&operands[11]), len - 13);
namelen = MIN(*namesize, NAME_MAX_LEN - 1);
+
+ if (len < 13 + *namesize)
+ return FALSE;
+
if (namelen > 0) {
memcpy(name, &operands[13], namelen);
strtoutf8(name, namelen);
@@ -39,7 +43,8 @@ gboolean parse_media_folder_name(uint8_t *operands, uint16_t len,
return FALSE;
memset(name, 0, NAME_MAX_LEN);
- namelen = MIN(get_be16(&operands[12]), NAME_MAX_LEN - 1);
+ namelen = MIN(get_be16(&operands[12]), len - 14);
+ namelen = MIN(namelen, NAME_MAX_LEN - 1);
if (namelen > 0)
memcpy(name, &operands[14], namelen);
--
2.55.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* RE: avrcp: Fix Out-of-Bounds Read in AVRCP GetFolderItems parsing
2026-08-04 14:23 ` [BlueZ, v2 1/3] avrcp: Split off name parsing from parse_*_element() Bastien Nocera
@ 2026-08-04 16:27 ` bluez.test.bot
2026-08-05 17:12 ` [BlueZ, v2 1/3] avrcp: Split off name parsing from parse_*_element() Luiz Augusto von Dentz
1 sibling, 0 replies; 12+ messages in thread
From: bluez.test.bot @ 2026-08-04 16:27 UTC (permalink / raw)
To: linux-bluetooth, hadess
[-- Attachment #1: Type: text/plain, Size: 4212 bytes --]
This is automated email and please do not reply to this email!
Dear submitter,
Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1140181
---Test result---
Test Summary:
CheckPatch FAIL 1.01 seconds
GitLint PASS 0.65 seconds
BuildEll PASS 21.33 seconds
BluezMake PASS 551.90 seconds
MakeCheck PASS 19.02 seconds
MakeDistcheck PASS 159.31 seconds
CheckValgrind PASS 227.71 seconds
CheckSmatch PASS 309.84 seconds
bluezmakeextell PASS 98.23 seconds
IncrementalBuild PASS 563.59 seconds
ScanBuild PASS 945.33 seconds
Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script
Output:
[BlueZ,v2,2/3] unit: Adapt poc_*_oob.c test into a new test
WARNING:BAD_SIGN_OFF: Non-standard signature: Co-authored-by:
#56:
Co-authored-by: Elman Shahbazov <shahbazovelman97@gmail.com>
WARNING:BLOCK_COMMENT_STYLE: Block comments use a trailing */ on a separate line
#118: FILE: unit/test-avrcp-sec.c:30:
+ * Actual packet length (len) = 14 bytes */
WARNING:LONG_LINE_COMMENT: line length of 83 exceeds 80 columns
#125: FILE: unit/test-avrcp-sec.c:37:
+ /* Launching the PoC. We transmit a 14-byte packet, but namesize=1000... */
WARNING:LONG_LINE: line length of 82 exceeds 80 columns
#126: FILE: unit/test-avrcp-sec.c:38:
+ ret = parse_media_element_name(malicious_packet, sizeof(malicious_packet),
WARNING:BLOCK_COMMENT_STYLE: Block comments use a trailing */ on a separate line
#140: FILE: unit/test-avrcp-sec.c:52:
+ * Actual packet length (len) = 14 bytes */
WARNING:LONG_LINE_COMMENT: line length of 83 exceeds 80 columns
#147: FILE: unit/test-avrcp-sec.c:59:
+ /* Launching the PoC. We transmit a 14-byte packet, but namesize=1000... */
WARNING:LONG_LINE: line length of 81 exceeds 80 columns
#148: FILE: unit/test-avrcp-sec.c:60:
+ ret = parse_media_folder_name(malicious_packet, sizeof(malicious_packet),
WARNING:LONG_LINE: line length of 88 exceeds 80 columns
#160: FILE: unit/test-avrcp-sec.c:72:
+ tester_add("/avrcp-element-name-oob", NULL, NULL, avrcp_element_name_oob, NULL);
WARNING:LONG_LINE: line length of 86 exceeds 80 columns
#161: FILE: unit/test-avrcp-sec.c:73:
+ tester_add("/avrcp-folder-name-oob", NULL, NULL, avrcp_folder_name_oob, NULL);
/github/workspace/src/patch/14730317.patch total: 0 errors, 9 warnings, 91 lines checked
NOTE: For some of the reported defects, checkpatch may be able to
mechanically convert to the typical style using --fix or --fix-inplace.
/github/workspace/src/patch/14730317.patch has style problems, please review.
NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO
NOTE: If any of the errors are false positives, please report
them to the maintainer, see CHECKPATCH in MAINTAINERS.
[BlueZ,v2,3/3] avrcp: Fix Out-of-Bounds Read in AVRCP GetFolderItems parsing
WARNING:BAD_SIGN_OFF: Non-standard signature: Co-Authored-by:
#57:
Co-Authored-by: Bastien Nocera <hadess@hadess.net>
WARNING:BAD_SIGN_OFF: 'Co-authored-by:' is the preferred signature form
#57:
Co-Authored-by: Bastien Nocera <hadess@hadess.net>
/github/workspace/src/patch/14730318.patch total: 0 errors, 2 warnings, 22 lines checked
NOTE: For some of the reported defects, checkpatch may be able to
mechanically convert to the typical style using --fix or --fix-inplace.
/github/workspace/src/patch/14730318.patch has style problems, please review.
NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO
NOTE: If any of the errors are false positives, please report
them to the maintainer, see CHECKPATCH in MAINTAINERS.
https://github.com/bluez/bluez/pull/2376
---
Regards,
Linux Bluetooth
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [BlueZ, v2 2/3] unit: Adapt poc_*_oob.c test into a new test
2026-08-04 14:23 ` [BlueZ, v2 2/3] unit: Adapt poc_*_oob.c test into a new test Bastien Nocera
@ 2026-08-04 16:46 ` Luiz Augusto von Dentz
2026-08-05 7:59 ` Bastien Nocera
0 siblings, 1 reply; 12+ messages in thread
From: Luiz Augusto von Dentz @ 2026-08-04 16:46 UTC (permalink / raw)
To: Bastien Nocera; +Cc: linux-bluetooth, Elman Shahbazov
Hi Bastien,
On Tue, Aug 4, 2026 at 10:31 AM Bastien Nocera <hadess@hadess.net> wrote:
>
> Adapt poc_avrcp_oob.c and poc_folder_oob.c into unit tests.
>
> Co-authored-by: Elman Shahbazov <shahbazovelman97@gmail.com>
> ---
> Makefile.am | 9 +++++
> unit/test-avrcp-sec.c | 76 +++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 85 insertions(+)
> create mode 100644 unit/test-avrcp-sec.c
>
> diff --git a/Makefile.am b/Makefile.am
> index 19c468d3a504..e3baa4155c1f 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -660,6 +660,15 @@ unit_test_avrcp_SOURCES = unit/test-avrcp.c \
> unit_test_avrcp_LDADD = lib/libbluetooth-internal.la \
> src/libshared-glib.la $(GLIB_LIBS)
>
> +unit_tests += unit/test-avrcp-sec
> +
> +unit_test_avrcp_sec_SOURCES = unit/test-avrcp-sec.c \
> + profiles/audio/avrcp-parse.c \
> + profiles/audio/avrcp-parse.h \
> + src/log.h src/log.c
> +unit_test_avrcp_sec_LDADD = lib/libbluetooth-internal.la \
> + src/libshared-glib.la $(GLIB_LIBS)
Any reason why this couldn't live inside test-avrcp.c?
> unit_tests += unit/test-hfp
>
> unit_test_hfp_SOURCES = unit/test-hfp.c
> diff --git a/unit/test-avrcp-sec.c b/unit/test-avrcp-sec.c
> new file mode 100644
> index 000000000000..a100b2d68e35
> --- /dev/null
> +++ b/unit/test-avrcp-sec.c
> @@ -0,0 +1,76 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + *
> + * BlueZ - Bluetooth protocol stack for Linux
> + *
> + * Copyright (C) 2026 Red Hat Inc.
> + *
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <glib.h>
> +
> +#include "src/shared/util.h"
> +#include "src/shared/tester.h"
> +#include "src/log.h"
> +
> +#include "profiles/audio/avrcp-parse.h"
> +
> +static void avrcp_element_name_oob(gconstpointer data)
> +{
> + char name[255];
> + uint16_t namesize;
> + gboolean ret;
> +
> + /* Crafting a malicious payload.
> + * Actual packet length (len) = 14 bytes */
> + uint8_t malicious_packet[14] = {0};
> +
> + /* Specify namesize = 1000 (0x03E8 in Big Endian) at offset 11 */
> + malicious_packet[11] = 0x03;
> + malicious_packet[12] = 0xE8;
> +
> + /* Launching the PoC. We transmit a 14-byte packet, but namesize=1000... */
> + ret = parse_media_element_name(malicious_packet, sizeof(malicious_packet),
> + name, &namesize);
> + if (ret)
> + tester_test_passed();
> + else
> + tester_test_failed();
> +}
> +
> +static void avrcp_folder_name_oob(gconstpointer data)
> +{
> + char name[255];
> + gboolean ret;
> +
> + /* Crafting a malicious payload.
> + * Actual packet length (len) = 14 bytes */
> + uint8_t malicious_packet[14] = {0};
> +
> + /* Specify namesize = 1000 (0x03E8 in Big Endian) at offset 12 */
> + malicious_packet[12] = 0x03;
> + malicious_packet[13] = 0xE8;
> +
> + /* Launching the PoC. We transmit a 14-byte packet, but namesize=1000... */
> + ret = parse_media_folder_name(malicious_packet, sizeof(malicious_packet),
> + name);
> + if (ret)
> + tester_test_passed();
> + else
> + tester_test_failed();
> +}
> +
> +int main(int argc, char *argv[])
> +{
> + tester_init(&argc, &argv);
> +
> + tester_add("/avrcp-element-name-oob", NULL, NULL, avrcp_element_name_oob, NULL);
> + tester_add("/avrcp-folder-name-oob", NULL, NULL, avrcp_folder_name_oob, NULL);
> +
> + return tester_run();
> +}
> --
> 2.55.0
>
>
--
Luiz Augusto von Dentz
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [BlueZ, v2 2/3] unit: Adapt poc_*_oob.c test into a new test
2026-08-04 16:46 ` Luiz Augusto von Dentz
@ 2026-08-05 7:59 ` Bastien Nocera
2026-08-05 16:44 ` Luiz Augusto von Dentz
0 siblings, 1 reply; 12+ messages in thread
From: Bastien Nocera @ 2026-08-05 7:59 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: linux-bluetooth, Elman Shahbazov
On Tue, 2026-08-04 at 12:46 -0400, Luiz Augusto von Dentz wrote:
> Hi Bastien,
>
> On Tue, Aug 4, 2026 at 10:31 AM Bastien Nocera <hadess@hadess.net>
> wrote:
> >
> > Adapt poc_avrcp_oob.c and poc_folder_oob.c into unit tests.
> >
> > Co-authored-by: Elman Shahbazov <shahbazovelman97@gmail.com>
> > ---
> > Makefile.am | 9 +++++
> > unit/test-avrcp-sec.c | 76
> > +++++++++++++++++++++++++++++++++++++++++++
> > 2 files changed, 85 insertions(+)
> > create mode 100644 unit/test-avrcp-sec.c
> >
> > diff --git a/Makefile.am b/Makefile.am
> > index 19c468d3a504..e3baa4155c1f 100644
> > --- a/Makefile.am
> > +++ b/Makefile.am
> > @@ -660,6 +660,15 @@ unit_test_avrcp_SOURCES = unit/test-avrcp.c \
> > unit_test_avrcp_LDADD = lib/libbluetooth-internal.la \
> > src/libshared-glib.la $(GLIB_LIBS)
> >
> > +unit_tests += unit/test-avrcp-sec
> > +
> > +unit_test_avrcp_sec_SOURCES = unit/test-avrcp-sec.c \
> > + profiles/audio/avrcp-parse.c \
> > + profiles/audio/avrcp-parse.h \
> > + src/log.h src/log.c
> > +unit_test_avrcp_sec_LDADD = lib/libbluetooth-internal.la \
> > + src/libshared-glib.la $(GLIB_LIBS)
>
> Any reason why this couldn't live inside test-avrcp.c?
Because most of the code in test-avrcp.c is mocked in unit/avrcp-
lib.[ch] and conflicts with code from profiles/audio/avrcp.c. I really
did try...
I can change the name of the test if needed.
>
> > unit_tests += unit/test-hfp
> >
> > unit_test_hfp_SOURCES = unit/test-hfp.c
> > diff --git a/unit/test-avrcp-sec.c b/unit/test-avrcp-sec.c
> > new file mode 100644
> > index 000000000000..a100b2d68e35
> > --- /dev/null
> > +++ b/unit/test-avrcp-sec.c
> > @@ -0,0 +1,76 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +/*
> > + *
> > + * BlueZ - Bluetooth protocol stack for Linux
> > + *
> > + * Copyright (C) 2026 Red Hat Inc.
> > + *
> > + *
> > + */
> > +
> > +#ifdef HAVE_CONFIG_H
> > +#include <config.h>
> > +#endif
> > +
> > +#include <glib.h>
> > +
> > +#include "src/shared/util.h"
> > +#include "src/shared/tester.h"
> > +#include "src/log.h"
> > +
> > +#include "profiles/audio/avrcp-parse.h"
> > +
> > +static void avrcp_element_name_oob(gconstpointer data)
> > +{
> > + char name[255];
> > + uint16_t namesize;
> > + gboolean ret;
> > +
> > + /* Crafting a malicious payload.
> > + * Actual packet length (len) = 14 bytes */
> > + uint8_t malicious_packet[14] = {0};
> > +
> > + /* Specify namesize = 1000 (0x03E8 in Big Endian) at offset
> > 11 */
> > + malicious_packet[11] = 0x03;
> > + malicious_packet[12] = 0xE8;
> > +
> > + /* Launching the PoC. We transmit a 14-byte packet, but
> > namesize=1000... */
> > + ret = parse_media_element_name(malicious_packet,
> > sizeof(malicious_packet),
> > + name, &namesize);
> > + if (ret)
> > + tester_test_passed();
> > + else
> > + tester_test_failed();
> > +}
> > +
> > +static void avrcp_folder_name_oob(gconstpointer data)
> > +{
> > + char name[255];
> > + gboolean ret;
> > +
> > + /* Crafting a malicious payload.
> > + * Actual packet length (len) = 14 bytes */
> > + uint8_t malicious_packet[14] = {0};
> > +
> > + /* Specify namesize = 1000 (0x03E8 in Big Endian) at offset
> > 12 */
> > + malicious_packet[12] = 0x03;
> > + malicious_packet[13] = 0xE8;
> > +
> > + /* Launching the PoC. We transmit a 14-byte packet, but
> > namesize=1000... */
> > + ret = parse_media_folder_name(malicious_packet,
> > sizeof(malicious_packet),
> > + name);
> > + if (ret)
> > + tester_test_passed();
> > + else
> > + tester_test_failed();
> > +}
> > +
> > +int main(int argc, char *argv[])
> > +{
> > + tester_init(&argc, &argv);
> > +
> > + tester_add("/avrcp-element-name-oob", NULL, NULL,
> > avrcp_element_name_oob, NULL);
> > + tester_add("/avrcp-folder-name-oob", NULL, NULL,
> > avrcp_folder_name_oob, NULL);
> > +
> > + return tester_run();
> > +}
> > --
> > 2.55.0
> >
> >
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [BlueZ, v2 2/3] unit: Adapt poc_*_oob.c test into a new test
2026-08-05 7:59 ` Bastien Nocera
@ 2026-08-05 16:44 ` Luiz Augusto von Dentz
2026-08-06 10:50 ` Bastien Nocera
0 siblings, 1 reply; 12+ messages in thread
From: Luiz Augusto von Dentz @ 2026-08-05 16:44 UTC (permalink / raw)
To: Bastien Nocera; +Cc: linux-bluetooth, Elman Shahbazov
Hi Bastien,
On Wed, Aug 5, 2026 at 3:59 AM Bastien Nocera <hadess@hadess.net> wrote:
>
> On Tue, 2026-08-04 at 12:46 -0400, Luiz Augusto von Dentz wrote:
> > Hi Bastien,
> >
> > On Tue, Aug 4, 2026 at 10:31 AM Bastien Nocera <hadess@hadess.net>
> > wrote:
> > >
> > > Adapt poc_avrcp_oob.c and poc_folder_oob.c into unit tests.
> > >
> > > Co-authored-by: Elman Shahbazov <shahbazovelman97@gmail.com>
> > > ---
> > > Makefile.am | 9 +++++
> > > unit/test-avrcp-sec.c | 76
> > > +++++++++++++++++++++++++++++++++++++++++++
> > > 2 files changed, 85 insertions(+)
> > > create mode 100644 unit/test-avrcp-sec.c
> > >
> > > diff --git a/Makefile.am b/Makefile.am
> > > index 19c468d3a504..e3baa4155c1f 100644
> > > --- a/Makefile.am
> > > +++ b/Makefile.am
> > > @@ -660,6 +660,15 @@ unit_test_avrcp_SOURCES = unit/test-avrcp.c \
> > > unit_test_avrcp_LDADD = lib/libbluetooth-internal.la \
> > > src/libshared-glib.la $(GLIB_LIBS)
> > >
> > > +unit_tests += unit/test-avrcp-sec
> > > +
> > > +unit_test_avrcp_sec_SOURCES = unit/test-avrcp-sec.c \
> > > + profiles/audio/avrcp-parse.c \
> > > + profiles/audio/avrcp-parse.h \
> > > + src/log.h src/log.c
> > > +unit_test_avrcp_sec_LDADD = lib/libbluetooth-internal.la \
> > > + src/libshared-glib.la $(GLIB_LIBS)
> >
> > Any reason why this couldn't live inside test-avrcp.c?
>
> Because most of the code in test-avrcp.c is mocked in unit/avrcp-
> lib.[ch] and conflicts with code from profiles/audio/avrcp.c. I really
> did try...
Ok, well then perhaps we should start testing what we really use in
the avrcp plugin rather than the removed Android code, or we could
have a bigger task: converting this type of code to src/shared/avrcp.c
(e.g. bt_avrcp) so it can be unit tested.
> I can change the name of the test if needed.
I'm not concerned about the name, I'm concerned about the number of
unit test files which could otherwise be in a single file instead of
duplicating a lot of context.
> >
> > > unit_tests += unit/test-hfp
> > >
> > > unit_test_hfp_SOURCES = unit/test-hfp.c
> > > diff --git a/unit/test-avrcp-sec.c b/unit/test-avrcp-sec.c
> > > new file mode 100644
> > > index 000000000000..a100b2d68e35
> > > --- /dev/null
> > > +++ b/unit/test-avrcp-sec.c
> > > @@ -0,0 +1,76 @@
> > > +// SPDX-License-Identifier: GPL-2.0-or-later
> > > +/*
> > > + *
> > > + * BlueZ - Bluetooth protocol stack for Linux
> > > + *
> > > + * Copyright (C) 2026 Red Hat Inc.
> > > + *
> > > + *
> > > + */
> > > +
> > > +#ifdef HAVE_CONFIG_H
> > > +#include <config.h>
> > > +#endif
> > > +
> > > +#include <glib.h>
> > > +
> > > +#include "src/shared/util.h"
> > > +#include "src/shared/tester.h"
> > > +#include "src/log.h"
> > > +
> > > +#include "profiles/audio/avrcp-parse.h"
> > > +
> > > +static void avrcp_element_name_oob(gconstpointer data)
> > > +{
> > > + char name[255];
> > > + uint16_t namesize;
> > > + gboolean ret;
> > > +
> > > + /* Crafting a malicious payload.
> > > + * Actual packet length (len) = 14 bytes */
> > > + uint8_t malicious_packet[14] = {0};
> > > +
> > > + /* Specify namesize = 1000 (0x03E8 in Big Endian) at offset
> > > 11 */
> > > + malicious_packet[11] = 0x03;
> > > + malicious_packet[12] = 0xE8;
> > > +
> > > + /* Launching the PoC. We transmit a 14-byte packet, but
> > > namesize=1000... */
> > > + ret = parse_media_element_name(malicious_packet,
> > > sizeof(malicious_packet),
> > > + name, &namesize);
> > > + if (ret)
> > > + tester_test_passed();
> > > + else
> > > + tester_test_failed();
> > > +}
> > > +
> > > +static void avrcp_folder_name_oob(gconstpointer data)
> > > +{
> > > + char name[255];
> > > + gboolean ret;
> > > +
> > > + /* Crafting a malicious payload.
> > > + * Actual packet length (len) = 14 bytes */
> > > + uint8_t malicious_packet[14] = {0};
> > > +
> > > + /* Specify namesize = 1000 (0x03E8 in Big Endian) at offset
> > > 12 */
> > > + malicious_packet[12] = 0x03;
> > > + malicious_packet[13] = 0xE8;
> > > +
> > > + /* Launching the PoC. We transmit a 14-byte packet, but
> > > namesize=1000... */
> > > + ret = parse_media_folder_name(malicious_packet,
> > > sizeof(malicious_packet),
> > > + name);
> > > + if (ret)
> > > + tester_test_passed();
> > > + else
> > > + tester_test_failed();
> > > +}
> > > +
> > > +int main(int argc, char *argv[])
> > > +{
> > > + tester_init(&argc, &argv);
> > > +
> > > + tester_add("/avrcp-element-name-oob", NULL, NULL,
> > > avrcp_element_name_oob, NULL);
> > > + tester_add("/avrcp-folder-name-oob", NULL, NULL,
> > > avrcp_folder_name_oob, NULL);
> > > +
> > > + return tester_run();
> > > +}
> > > --
> > > 2.55.0
> > >
> > >
> >
--
Luiz Augusto von Dentz
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [BlueZ, v2 1/3] avrcp: Split off name parsing from parse_*_element()
2026-08-04 14:23 ` [BlueZ, v2 1/3] avrcp: Split off name parsing from parse_*_element() Bastien Nocera
2026-08-04 16:27 ` avrcp: Fix Out-of-Bounds Read in AVRCP GetFolderItems parsing bluez.test.bot
@ 2026-08-05 17:12 ` Luiz Augusto von Dentz
2026-08-06 9:59 ` Bastien Nocera
1 sibling, 1 reply; 12+ messages in thread
From: Luiz Augusto von Dentz @ 2026-08-05 17:12 UTC (permalink / raw)
To: Bastien Nocera; +Cc: linux-bluetooth
Hi Bastien,
On Tue, Aug 4, 2026 at 10:31 AM Bastien Nocera <hadess@hadess.net> wrote:
>
> This will allow us to use the name extraction code in
> parse_media_element() and parse_folder_element() separately, such
> as in tests.
> ---
> Makefile.plugins | 1 +
> profiles/audio/avrcp-parse.c | 47 ++++++++++++++++++++++++++++++++++++
> profiles/audio/avrcp-parse.h | 19 +++++++++++++++
> profiles/audio/avrcp.c | 26 +++++---------------
> 4 files changed, 73 insertions(+), 20 deletions(-)
> create mode 100644 profiles/audio/avrcp-parse.c
> create mode 100644 profiles/audio/avrcp-parse.h
>
> diff --git a/Makefile.plugins b/Makefile.plugins
> index ac667beda847..a505fcd6691f 100644
> --- a/Makefile.plugins
> +++ b/Makefile.plugins
> @@ -37,6 +37,7 @@ builtin_modules += avrcp
> builtin_sources += profiles/audio/control.h profiles/audio/control.c \
> profiles/audio/avctp.h profiles/audio/avctp.c \
> profiles/audio/avrcp.h profiles/audio/avrcp.c \
> + profiles/audio/avrcp-parse.h profiles/audio/avrcp-parse.c \
> profiles/audio/avrcp-player.c
> endif
>
> diff --git a/profiles/audio/avrcp-parse.c b/profiles/audio/avrcp-parse.c
> new file mode 100644
> index 000000000000..d3d0a070a4da
> --- /dev/null
> +++ b/profiles/audio/avrcp-parse.c
> @@ -0,0 +1,47 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + *
> + * BlueZ - Bluetooth protocol stack for Linux
> + *
> + * Copyright (C) 2026 Red Hat Inc.
> + *
> + *
> + */
> +
> +#include "avrcp-parse.h"
> +#include "src/shared/util.h"
> +
> +gboolean parse_media_element_name(uint8_t *operands, uint16_t len,
> + char *name, uint16_t *namesize)
> +{
> + uint16_t namelen;
> +
> + if (len < 13)
> + return FALSE;
> +
> + memset(name, 0, NAME_MAX_LEN);
> + *namesize = get_be16(&operands[11]);
> + namelen = MIN(*namesize, NAME_MAX_LEN - 1);
> + if (namelen > 0) {
> + memcpy(name, &operands[13], namelen);
> + strtoutf8(name, namelen);
> + }
> +
> + return TRUE;
> +}
> +
> +gboolean parse_media_folder_name(uint8_t *operands, uint16_t len,
> + char *name)
> +{
> + uint16_t namelen;
> +
> + if (len < 12)
> + return FALSE;
> +
> + memset(name, 0, NAME_MAX_LEN);
> + namelen = MIN(get_be16(&operands[12]), NAME_MAX_LEN - 1);
> + if (namelen > 0)
> + memcpy(name, &operands[14], namelen);
> +
> + return TRUE;
> +}
Rather than creating yet another file how about hosting this under
shared/util.h directly? It already depends on it anyway, we could got
with something like strntoutf8 or a similar function that checks the
length, etc, actually be maybe better to do it under
util_iov_pull_utf8(iov, len, str, str_max_len) so we can load the pdu
into the iov then use iov_pull_mem, etc, to verify that we have enough
bytes in a generic manner.
> diff --git a/profiles/audio/avrcp-parse.h b/profiles/audio/avrcp-parse.h
> new file mode 100644
> index 000000000000..f7a33c854442
> --- /dev/null
> +++ b/profiles/audio/avrcp-parse.h
> @@ -0,0 +1,19 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + *
> + * BlueZ - Bluetooth protocol stack for Linux
> + *
> + * Copyright (C) 2026 Red Hat Inc.
> + *
> + *
> + */
> +
> +#include <glib.h>
> +#include <inttypes.h>
> +
> +#define NAME_MAX_LEN 255
> +
> +gboolean parse_media_element_name(uint8_t *operands, uint16_t len,
> + char *name, uint16_t *namesize);
> +gboolean parse_media_folder_name(uint8_t *operands, uint16_t len,
> + char *name);
> diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
> index 2194a913580f..af3c72174764 100644
> --- a/profiles/audio/avrcp.c
> +++ b/profiles/audio/avrcp.c
> @@ -52,6 +52,7 @@
>
> #include "avctp.h"
> #include "avrcp.h"
> +#include "avrcp-parse.h"
> #include "control.h"
> #include "media.h"
> #include "player.h"
> @@ -2614,24 +2615,15 @@ static struct media_item *parse_media_element(struct avrcp *session,
> struct avrcp_player *player;
> struct media_player *mp;
> struct media_item *item;
> - uint16_t namelen, namesize;
> - char name[255];
> + uint16_t namesize;
> + char name[NAME_MAX_LEN];
> uint64_t uid;
> uint8_t count;
>
> - if (len < 13)
> + if (!parse_media_element_name(operands, len, name, &namesize))
> return NULL;
>
> uid = get_be64(&operands[0]);
> -
> - memset(name, 0, sizeof(name));
> - namesize = get_be16(&operands[11]);
> - namelen = MIN(namesize, sizeof(name) - 1);
> - if (namelen > 0) {
> - memcpy(name, &operands[13], namelen);
> - strtoutf8(name, namelen);
> - }
> -
> count = operands[13 + namesize];
>
> player = session->controller->player;
> @@ -2655,24 +2647,18 @@ static struct media_item *parse_media_folder(struct avrcp *session,
> struct avrcp_player *player = session->controller->player;
> struct media_player *mp = player->user_data;
> struct media_item *item;
> - uint16_t namelen;
> - char name[255];
> + char name[NAME_MAX_LEN];
> uint64_t uid;
> uint8_t type;
> uint8_t playable;
>
> - if (len < 12)
> + if (!parse_media_folder_name(operands, len, name))
> return NULL;
>
> uid = get_be64(&operands[0]);
> type = operands[8];
> playable = operands[9];
>
> - memset(name, 0, sizeof(name));
> - namelen = MIN(get_be16(&operands[12]), sizeof(name) - 1);
> - if (namelen > 0)
> - memcpy(name, &operands[14], namelen);
> -
> item = media_player_create_folder(mp, name, type, uid);
> if (!item)
> return NULL;
> --
> 2.55.0
>
>
--
Luiz Augusto von Dentz
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [BlueZ, v2 1/3] avrcp: Split off name parsing from parse_*_element()
2026-08-05 17:12 ` [BlueZ, v2 1/3] avrcp: Split off name parsing from parse_*_element() Luiz Augusto von Dentz
@ 2026-08-06 9:59 ` Bastien Nocera
2026-08-06 14:19 ` Luiz Augusto von Dentz
0 siblings, 1 reply; 12+ messages in thread
From: Bastien Nocera @ 2026-08-06 9:59 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
On Wed, 2026-08-05 at 13:12 -0400, Luiz Augusto von Dentz wrote:
> Hi Bastien,
>
> On Tue, Aug 4, 2026 at 10:31 AM Bastien Nocera <hadess@hadess.net>
> wrote:
> >
> > This will allow us to use the name extraction code in
> > parse_media_element() and parse_folder_element() separately, such
> > as in tests.
> > ---
> > Makefile.plugins | 1 +
> > profiles/audio/avrcp-parse.c | 47
> > ++++++++++++++++++++++++++++++++++++
> > profiles/audio/avrcp-parse.h | 19 +++++++++++++++
> > profiles/audio/avrcp.c | 26 +++++---------------
> > 4 files changed, 73 insertions(+), 20 deletions(-)
> > create mode 100644 profiles/audio/avrcp-parse.c
> > create mode 100644 profiles/audio/avrcp-parse.h
> >
> > diff --git a/Makefile.plugins b/Makefile.plugins
> > index ac667beda847..a505fcd6691f 100644
> > --- a/Makefile.plugins
> > +++ b/Makefile.plugins
> > @@ -37,6 +37,7 @@ builtin_modules += avrcp
> > builtin_sources += profiles/audio/control.h
> > profiles/audio/control.c \
> > profiles/audio/avctp.h
> > profiles/audio/avctp.c \
> > profiles/audio/avrcp.h
> > profiles/audio/avrcp.c \
> > + profiles/audio/avrcp-parse.h
> > profiles/audio/avrcp-parse.c \
> > profiles/audio/avrcp-player.c
> > endif
> >
> > diff --git a/profiles/audio/avrcp-parse.c b/profiles/audio/avrcp-
> > parse.c
> > new file mode 100644
> > index 000000000000..d3d0a070a4da
> > --- /dev/null
> > +++ b/profiles/audio/avrcp-parse.c
> > @@ -0,0 +1,47 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +/*
> > + *
> > + * BlueZ - Bluetooth protocol stack for Linux
> > + *
> > + * Copyright (C) 2026 Red Hat Inc.
> > + *
> > + *
> > + */
> > +
> > +#include "avrcp-parse.h"
> > +#include "src/shared/util.h"
> > +
> > +gboolean parse_media_element_name(uint8_t *operands, uint16_t len,
> > + char *name, uint16_t
> > *namesize)
> > +{
> > + uint16_t namelen;
> > +
> > + if (len < 13)
> > + return FALSE;
> > +
> > + memset(name, 0, NAME_MAX_LEN);
> > + *namesize = get_be16(&operands[11]);
> > + namelen = MIN(*namesize, NAME_MAX_LEN - 1);
> > + if (namelen > 0) {
> > + memcpy(name, &operands[13], namelen);
> > + strtoutf8(name, namelen);
> > + }
> > +
> > + return TRUE;
> > +}
> > +
> > +gboolean parse_media_folder_name(uint8_t *operands, uint16_t len,
> > + char *name)
> > +{
> > + uint16_t namelen;
> > +
> > + if (len < 12)
> > + return FALSE;
> > +
> > + memset(name, 0, NAME_MAX_LEN);
> > + namelen = MIN(get_be16(&operands[12]), NAME_MAX_LEN - 1);
> > + if (namelen > 0)
> > + memcpy(name, &operands[14], namelen);
> > +
> > + return TRUE;
> > +}
>
> Rather than creating yet another file how about hosting this under
> shared/util.h directly? It already depends on it anyway, we could got
> with something like strntoutf8 or a similar function that checks the
> length, etc, actually be maybe better to do it under
> util_iov_pull_utf8(iov, len, str, str_max_len) so we can load the pdu
> into the iov then use iov_pull_mem, etc, to verify that we have
> enough
> bytes in a generic manner.
That would be nice follow-up work to be done, but this patch is
specifically about being able to test the out-of-bounds access caused
by those 2 portions of code in patch #2.
Then the fix is applied in patch #3.
Finally, we could optimise/clean this up and remove that parsing code,
but that would be in a 4th patch.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [BlueZ, v2 2/3] unit: Adapt poc_*_oob.c test into a new test
2026-08-05 16:44 ` Luiz Augusto von Dentz
@ 2026-08-06 10:50 ` Bastien Nocera
0 siblings, 0 replies; 12+ messages in thread
From: Bastien Nocera @ 2026-08-06 10:50 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: linux-bluetooth, Elman Shahbazov
On Wed, 2026-08-05 at 12:44 -0400, Luiz Augusto von Dentz wrote:
> Hi Bastien,
>
> On Wed, Aug 5, 2026 at 3:59 AM Bastien Nocera <hadess@hadess.net>
> wrote:
> >
> > On Tue, 2026-08-04 at 12:46 -0400, Luiz Augusto von Dentz wrote:
> > > Hi Bastien,
> > >
> > > On Tue, Aug 4, 2026 at 10:31 AM Bastien Nocera
> > > <hadess@hadess.net>
> > > wrote:
> > > >
> > > > Adapt poc_avrcp_oob.c and poc_folder_oob.c into unit tests.
> > > >
> > > > Co-authored-by: Elman Shahbazov <shahbazovelman97@gmail.com>
> > > > ---
> > > > Makefile.am | 9 +++++
> > > > unit/test-avrcp-sec.c | 76
> > > > +++++++++++++++++++++++++++++++++++++++++++
> > > > 2 files changed, 85 insertions(+)
> > > > create mode 100644 unit/test-avrcp-sec.c
> > > >
> > > > diff --git a/Makefile.am b/Makefile.am
> > > > index 19c468d3a504..e3baa4155c1f 100644
> > > > --- a/Makefile.am
> > > > +++ b/Makefile.am
> > > > @@ -660,6 +660,15 @@ unit_test_avrcp_SOURCES = unit/test-
> > > > avrcp.c \
> > > > unit_test_avrcp_LDADD = lib/libbluetooth-internal.la \
> > > > src/libshared-glib.la
> > > > $(GLIB_LIBS)
> > > >
> > > > +unit_tests += unit/test-avrcp-sec
> > > > +
> > > > +unit_test_avrcp_sec_SOURCES = unit/test-avrcp-sec.c \
> > > > + profiles/audio/avrcp-parse.c \
> > > > + profiles/audio/avrcp-parse.h \
> > > > + src/log.h src/log.c
> > > > +unit_test_avrcp_sec_LDADD = lib/libbluetooth-internal.la \
> > > > + src/libshared-glib.la
> > > > $(GLIB_LIBS)
> > >
> > > Any reason why this couldn't live inside test-avrcp.c?
> >
> > Because most of the code in test-avrcp.c is mocked in unit/avrcp-
> > lib.[ch] and conflicts with code from profiles/audio/avrcp.c. I
> > really
> > did try...
>
> Ok, well then perhaps we should start testing what we really use in
> the avrcp plugin rather than the removed Android code, or we could
> have a bigger task: converting this type of code to
> src/shared/avrcp.c
> (e.g. bt_avrcp) so it can be unit tested.
I figured that this code would actually test *something*, but it looks
like I was wrong.
I'll re-send the patch to remove the dead code for unit/avrcp.c, and
send a follow-up patch to remove this code here, and reinstate it with
this test.
Right now, "make coverage" says that profiles/audio has no coverage at
all...
> > I can change the name of the test if needed.
>
> I'm not concerned about the name, I'm concerned about the number of
> unit test files which could otherwise be in a single file instead of
> duplicating a lot of context.
>
> > >
> > > > unit_tests += unit/test-hfp
> > > >
> > > > unit_test_hfp_SOURCES = unit/test-hfp.c
> > > > diff --git a/unit/test-avrcp-sec.c b/unit/test-avrcp-sec.c
> > > > new file mode 100644
> > > > index 000000000000..a100b2d68e35
> > > > --- /dev/null
> > > > +++ b/unit/test-avrcp-sec.c
> > > > @@ -0,0 +1,76 @@
> > > > +// SPDX-License-Identifier: GPL-2.0-or-later
> > > > +/*
> > > > + *
> > > > + * BlueZ - Bluetooth protocol stack for Linux
> > > > + *
> > > > + * Copyright (C) 2026 Red Hat Inc.
> > > > + *
> > > > + *
> > > > + */
> > > > +
> > > > +#ifdef HAVE_CONFIG_H
> > > > +#include <config.h>
> > > > +#endif
> > > > +
> > > > +#include <glib.h>
> > > > +
> > > > +#include "src/shared/util.h"
> > > > +#include "src/shared/tester.h"
> > > > +#include "src/log.h"
> > > > +
> > > > +#include "profiles/audio/avrcp-parse.h"
> > > > +
> > > > +static void avrcp_element_name_oob(gconstpointer data)
> > > > +{
> > > > + char name[255];
> > > > + uint16_t namesize;
> > > > + gboolean ret;
> > > > +
> > > > + /* Crafting a malicious payload.
> > > > + * Actual packet length (len) = 14 bytes */
> > > > + uint8_t malicious_packet[14] = {0};
> > > > +
> > > > + /* Specify namesize = 1000 (0x03E8 in Big Endian) at
> > > > offset
> > > > 11 */
> > > > + malicious_packet[11] = 0x03;
> > > > + malicious_packet[12] = 0xE8;
> > > > +
> > > > + /* Launching the PoC. We transmit a 14-byte packet, but
> > > > namesize=1000... */
> > > > + ret = parse_media_element_name(malicious_packet,
> > > > sizeof(malicious_packet),
> > > > + name, &namesize);
> > > > + if (ret)
> > > > + tester_test_passed();
> > > > + else
> > > > + tester_test_failed();
> > > > +}
> > > > +
> > > > +static void avrcp_folder_name_oob(gconstpointer data)
> > > > +{
> > > > + char name[255];
> > > > + gboolean ret;
> > > > +
> > > > + /* Crafting a malicious payload.
> > > > + * Actual packet length (len) = 14 bytes */
> > > > + uint8_t malicious_packet[14] = {0};
> > > > +
> > > > + /* Specify namesize = 1000 (0x03E8 in Big Endian) at
> > > > offset
> > > > 12 */
> > > > + malicious_packet[12] = 0x03;
> > > > + malicious_packet[13] = 0xE8;
> > > > +
> > > > + /* Launching the PoC. We transmit a 14-byte packet, but
> > > > namesize=1000... */
> > > > + ret = parse_media_folder_name(malicious_packet,
> > > > sizeof(malicious_packet),
> > > > + name);
> > > > + if (ret)
> > > > + tester_test_passed();
> > > > + else
> > > > + tester_test_failed();
> > > > +}
> > > > +
> > > > +int main(int argc, char *argv[])
> > > > +{
> > > > + tester_init(&argc, &argv);
> > > > +
> > > > + tester_add("/avrcp-element-name-oob", NULL, NULL,
> > > > avrcp_element_name_oob, NULL);
> > > > + tester_add("/avrcp-folder-name-oob", NULL, NULL,
> > > > avrcp_folder_name_oob, NULL);
> > > > +
> > > > + return tester_run();
> > > > +}
> > > > --
> > > > 2.55.0
> > > >
> > > >
> > >
>
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [BlueZ, v2 1/3] avrcp: Split off name parsing from parse_*_element()
2026-08-06 9:59 ` Bastien Nocera
@ 2026-08-06 14:19 ` Luiz Augusto von Dentz
0 siblings, 0 replies; 12+ messages in thread
From: Luiz Augusto von Dentz @ 2026-08-06 14:19 UTC (permalink / raw)
To: Bastien Nocera; +Cc: linux-bluetooth
Hi Bastien,
On Thu, Aug 6, 2026 at 5:59 AM Bastien Nocera <hadess@hadess.net> wrote:
>
> On Wed, 2026-08-05 at 13:12 -0400, Luiz Augusto von Dentz wrote:
> > Hi Bastien,
> >
> > On Tue, Aug 4, 2026 at 10:31 AM Bastien Nocera <hadess@hadess.net>
> > wrote:
> > >
> > > This will allow us to use the name extraction code in
> > > parse_media_element() and parse_folder_element() separately, such
> > > as in tests.
> > > ---
> > > Makefile.plugins | 1 +
> > > profiles/audio/avrcp-parse.c | 47
> > > ++++++++++++++++++++++++++++++++++++
> > > profiles/audio/avrcp-parse.h | 19 +++++++++++++++
> > > profiles/audio/avrcp.c | 26 +++++---------------
> > > 4 files changed, 73 insertions(+), 20 deletions(-)
> > > create mode 100644 profiles/audio/avrcp-parse.c
> > > create mode 100644 profiles/audio/avrcp-parse.h
> > >
> > > diff --git a/Makefile.plugins b/Makefile.plugins
> > > index ac667beda847..a505fcd6691f 100644
> > > --- a/Makefile.plugins
> > > +++ b/Makefile.plugins
> > > @@ -37,6 +37,7 @@ builtin_modules += avrcp
> > > builtin_sources += profiles/audio/control.h
> > > profiles/audio/control.c \
> > > profiles/audio/avctp.h
> > > profiles/audio/avctp.c \
> > > profiles/audio/avrcp.h
> > > profiles/audio/avrcp.c \
> > > + profiles/audio/avrcp-parse.h
> > > profiles/audio/avrcp-parse.c \
> > > profiles/audio/avrcp-player.c
> > > endif
> > >
> > > diff --git a/profiles/audio/avrcp-parse.c b/profiles/audio/avrcp-
> > > parse.c
> > > new file mode 100644
> > > index 000000000000..d3d0a070a4da
> > > --- /dev/null
> > > +++ b/profiles/audio/avrcp-parse.c
> > > @@ -0,0 +1,47 @@
> > > +// SPDX-License-Identifier: GPL-2.0-or-later
> > > +/*
> > > + *
> > > + * BlueZ - Bluetooth protocol stack for Linux
> > > + *
> > > + * Copyright (C) 2026 Red Hat Inc.
> > > + *
> > > + *
> > > + */
> > > +
> > > +#include "avrcp-parse.h"
> > > +#include "src/shared/util.h"
> > > +
> > > +gboolean parse_media_element_name(uint8_t *operands, uint16_t len,
> > > + char *name, uint16_t
> > > *namesize)
> > > +{
> > > + uint16_t namelen;
> > > +
> > > + if (len < 13)
> > > + return FALSE;
> > > +
> > > + memset(name, 0, NAME_MAX_LEN);
> > > + *namesize = get_be16(&operands[11]);
> > > + namelen = MIN(*namesize, NAME_MAX_LEN - 1);
> > > + if (namelen > 0) {
> > > + memcpy(name, &operands[13], namelen);
> > > + strtoutf8(name, namelen);
> > > + }
> > > +
> > > + return TRUE;
> > > +}
> > > +
> > > +gboolean parse_media_folder_name(uint8_t *operands, uint16_t len,
> > > + char *name)
> > > +{
> > > + uint16_t namelen;
> > > +
> > > + if (len < 12)
> > > + return FALSE;
> > > +
> > > + memset(name, 0, NAME_MAX_LEN);
> > > + namelen = MIN(get_be16(&operands[12]), NAME_MAX_LEN - 1);
> > > + if (namelen > 0)
> > > + memcpy(name, &operands[14], namelen);
> > > +
> > > + return TRUE;
> > > +}
> >
> > Rather than creating yet another file how about hosting this under
> > shared/util.h directly? It already depends on it anyway, we could got
> > with something like strntoutf8 or a similar function that checks the
> > length, etc, actually be maybe better to do it under
> > util_iov_pull_utf8(iov, len, str, str_max_len) so we can load the pdu
> > into the iov then use iov_pull_mem, etc, to verify that we have
> > enough
> > bytes in a generic manner.
>
> That would be nice follow-up work to be done, but this patch is
> specifically about being able to test the out-of-bounds access caused
> by those 2 portions of code in patch #2.
>
> Then the fix is applied in patch #3.
>
> Finally, we could optimise/clean this up and remove that parsing code,
> but that would be in a 4th patch.
I don't think this is the best approach because test-avrcp is testing
the wrong implementation, so that needs rework. I'd go straight to
shared/util helper function which would allow us to create test cases
immediately without changing a bunch of things and removing
test-avrcp.c in the process.
--
Luiz Augusto von Dentz
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2026-08-06 14:19 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-04 14:23 [BlueZ, v2 0/3] avrcp: Fix Out-of-Bounds Read in AVRCP GetFolderItems parsing Bastien Nocera
2026-08-04 14:23 ` [BlueZ, v2 1/3] avrcp: Split off name parsing from parse_*_element() Bastien Nocera
2026-08-04 16:27 ` avrcp: Fix Out-of-Bounds Read in AVRCP GetFolderItems parsing bluez.test.bot
2026-08-05 17:12 ` [BlueZ, v2 1/3] avrcp: Split off name parsing from parse_*_element() Luiz Augusto von Dentz
2026-08-06 9:59 ` Bastien Nocera
2026-08-06 14:19 ` Luiz Augusto von Dentz
2026-08-04 14:23 ` [BlueZ, v2 2/3] unit: Adapt poc_*_oob.c test into a new test Bastien Nocera
2026-08-04 16:46 ` Luiz Augusto von Dentz
2026-08-05 7:59 ` Bastien Nocera
2026-08-05 16:44 ` Luiz Augusto von Dentz
2026-08-06 10:50 ` Bastien Nocera
2026-08-04 14:23 ` [BlueZ, v2 3/3] avrcp: Fix Out-of-Bounds Read in AVRCP GetFolderItems parsing Bastien Nocera
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).