From 8fbeb23bbf82d2e6934d69d2f810e7d762f00b90 Mon Sep 17 00:00:00 2001 From: hackerman-kl Date: Mon, 13 Apr 2026 18:52:30 +0200 Subject: [PATCH 01/12] milan-avb: implement deregister unsolicited notifications to actually clear registration --- ...cmd-deregister-unsolicited-notifications.c | 32 ++++++------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/src/modules/module-avb/aecp-aem-cmds-resps/cmd-deregister-unsolicited-notifications.c b/src/modules/module-avb/aecp-aem-cmds-resps/cmd-deregister-unsolicited-notifications.c index 37a4f5f96..d151e605a 100644 --- a/src/modules/module-avb/aecp-aem-cmds-resps/cmd-deregister-unsolicited-notifications.c +++ b/src/modules/module-avb/aecp-aem-cmds-resps/cmd-deregister-unsolicited-notifications.c @@ -33,36 +33,24 @@ int handle_cmd_deregister_unsol_notif_milan_v12(struct aecp *aecp, int64_t now, entity_state = (struct aecp_aem_entity_milan_state *) desc->ptr; unsol = entity_state->unsol_notif_state; - /** First check if the controller was already registered */ + /** Clear the slot matching this controller, if any */ for (index = 0; index < ctrler_max; index++) { uint64_t ctrl_eid = unsol[index].ctrler_entity_id; bool ctrler_reged = unsol[index].is_registered; if ((ctrl_eid == controller_id) && ctrler_reged) { - pw_log_debug("controller 0x%"PRIx64", already registered", - controller_id); + unsol[index].is_registered = false; + unsol[index].ctrler_entity_id = 0; + unsol[index].next_seq_id = 0; + unsol[index].port_id = 0; + memset(unsol[index].ctrler_mac_addr, 0, + sizeof(unsol[index].ctrler_mac_addr)); + pw_log_info("Unsol deregistration for 0x%"PRIx64, + controller_id); return reply_success(aecp, m, len); } } - /** When one slot is in the array is available use it */ - for (index = 0; index < ctrler_max; index++) { - if (!unsol[index].is_registered) { - break; - } - } - - /** Reach the maximum controller allocated */ - if (index == ctrler_max) { - return reply_no_resources(aecp, m, len); - } - - unsol[index].ctrler_entity_id = controller_id; - memcpy(unsol[index].ctrler_mac_addr, h->src, sizeof(h->src)); - unsol[index].is_registered = true; - unsol[index].port_id = 0; - unsol[index].next_seq_id = 0; - - pw_log_info("Unsol registration for 0x%"PRIx64, controller_id); + pw_log_debug("controller 0x%"PRIx64" was not registered", controller_id); return reply_success(aecp, m, len); } From d1deabe5ac129fdf7bac4b1f9f976d3898088fd2 Mon Sep 17 00:00:00 2001 From: hackerman-kl Date: Tue, 14 Apr 2026 19:00:02 +0200 Subject: [PATCH 02/12] milan-avb: fix descriptor field and endianness in GET_CLOCK_SOURCE lookup --- .../aecp-aem-cmds-resps/cmd-get-set-clock-source.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-clock-source.c b/src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-clock-source.c index 9dc9307f4..0991e6214 100644 --- a/src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-clock-source.c +++ b/src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-clock-source.c @@ -71,8 +71,8 @@ int handle_cmd_get_clock_source_milan_v12(struct aecp *aecp, int64_t now, sclk_source = (struct avb_packet_aecp_aem_setget_clock_source *) p->payload; - desc_index = htons(sclk_source->descriptor_id); - desc_type = htons(sclk_source->descriptor_id); + desc_type = ntohs(sclk_source->descriptor_type); + desc_index = ntohs(sclk_source->descriptor_id); desc = server_find_descriptor(aecp->server, desc_type, desc_index); if (desc == NULL) @@ -84,8 +84,7 @@ int handle_cmd_get_clock_source_milan_v12(struct aecp *aecp, int64_t now, /** Descriptors always keep the network endianness */ sclk_source->clock_source_index = dclk_domain->clock_source_index; - len = sizeof(*p) + sizeof(*sclk_source) + sizeof(*h); - return reply_success(aecp, m, len); + return reply_success(aecp, buf, len); } /** From f06234fda887d5b99e43b20abf6f46e1caf23042 Mon Sep 17 00:00:00 2001 From: hackerman-kl Date: Thu, 16 Apr 2026 19:07:59 +0200 Subject: [PATCH 03/12] milan-avb: bound packet copy length in clock-source handlers --- .../aecp-aem-cmds-resps/cmd-get-set-clock-source.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-clock-source.c b/src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-clock-source.c index 0991e6214..2c8fabd02 100644 --- a/src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-clock-source.c +++ b/src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-clock-source.c @@ -3,6 +3,7 @@ /* SPDX-FileCopyrightText: Copyright © 2025 Alexandre Malki */ /* SPDX-License-Identifier: MIT */ +#include #include #include @@ -23,6 +24,9 @@ static int reply_invalid_clock_source(struct aecp *aecp, struct avb_packet_aecp_aem *p = SPA_PTROFF(h, sizeof(*h), void); struct avb_packet_aecp_aem_setget_clock_source *sclk_source; + if (len < 0 || (size_t)len > sizeof(buf)) + return reply_status(aecp, AVB_AECP_AEM_STATUS_BAD_ARGUMENTS, m, len); + memcpy(buf, m, len); sclk_source = (struct avb_packet_aecp_aem_setget_clock_source *) p->payload; @@ -41,6 +45,9 @@ static int handle_unsol_set_clock_source(struct aecp *aecp, struct descriptor *d struct aecp_aem_base_info bi = { 0 }; int rc; + if (len < 0 || (size_t)len > sizeof(buf)) + return -EINVAL; + memcpy(buf, m, len); bi.controller_entity_id = htobe64(ctrler_id); bi.expire_timeout = INT64_MAX; @@ -67,6 +74,9 @@ int handle_cmd_get_clock_source_milan_v12(struct aecp *aecp, int64_t now, uint16_t desc_index; uint16_t desc_type; + if (len < 0 || (size_t)len > sizeof(buf)) + return reply_status(aecp, AVB_AECP_AEM_STATUS_BAD_ARGUMENTS, m, len); + memcpy(buf, m, len); sclk_source = (struct avb_packet_aecp_aem_setget_clock_source *) p->payload; From b831fd857fdb08370d7ec24ad015d9410a51f087 Mon Sep 17 00:00:00 2001 From: hackerman-kl Date: Thu, 16 Apr 2026 19:50:33 +0200 Subject: [PATCH 04/12] milan-avb: bound packet copy length in get-set-control handlers --- .../aecp-aem-cmds-resps/cmd-get-set-control.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-control.c b/src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-control.c index f7f1c3fce..1b1ce2b8c 100644 --- a/src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-control.c +++ b/src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-control.c @@ -3,6 +3,7 @@ /* SPDX-FileCopyrightText: Copyright © 2026 Alexandre Malki */ /* SPDX-License-Identifier: MIT */ +#include #include #include #include @@ -44,6 +45,9 @@ static int send_unsol_control_milan_v12(struct aecp *aecp, struct aecp_aem_base_info info = { 0 }; int rc = 0; + if (len > sizeof(unsol_buf)) + return -EINVAL; + memcpy(unsol_buf, m, len); /* Prepare a template packet */ info.controller_entity_id = htobe64(ctrler_id); @@ -78,6 +82,10 @@ static int reply_control_badargs(struct aecp *aecp, const void *m, int len, m, len); } + if (len < 0 || (size_t)len > sizeof(buf)) + return reply_status(aecp, AVB_AECP_AEM_STATUS_BAD_ARGUMENTS, + m, len); + memcpy(buf, m, len); ae_reply = (struct avb_packet_aecp_aem_setget_control *)p_reply->payload; @@ -102,6 +110,10 @@ static int handle_cmd_get_control_identify(struct aecp *aecp, struct descriptor ctrl_desc = desc->ptr; desc_formats = ctrl_desc->value_format; + if (len < 0 || (size_t)len > sizeof(buf)) + return reply_status(aecp, AVB_AECP_AEM_STATUS_BAD_ARGUMENTS, + m, len); + memcpy(buf, m, len); ae_reply = (struct avb_packet_aecp_aem_setget_control *)p_reply->payload; From 0291895498dbbe0f17651b88348505ea0dcf041e Mon Sep 17 00:00:00 2001 From: hackerman-kl Date: Sat, 18 Apr 2026 17:13:05 +0200 Subject: [PATCH 05/12] milan-avb: zero-pad oversized SET_CONTROL reply buffer to avoid stack info leak --- .../module-avb/aecp-aem-cmds-resps/cmd-get-set-control.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-control.c b/src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-control.c index 1b1ce2b8c..7891782ff 100644 --- a/src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-control.c +++ b/src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-control.c @@ -87,6 +87,8 @@ static int reply_control_badargs(struct aecp *aecp, const void *m, int len, m, len); memcpy(buf, m, len); + if (pkt_size > len) + memset(buf + len, 0, pkt_size - len); ae_reply = (struct avb_packet_aecp_aem_setget_control *)p_reply->payload; control_copy_payload(format, ae_reply->payload, type_sz, count); @@ -120,6 +122,9 @@ static int handle_cmd_get_control_identify(struct aecp *aecp, struct descriptor // Idenfity only has one value element pkt_size = sizeof(*h) + sizeof(*p_reply)+ CONTROL_LINEAR_UINT8_SIZE; + if (pkt_size > len) + memset(buf + len, 0, pkt_size - len); + control_copy_payload(desc_formats, ae_reply->payload, CONTROL_LINEAR_UINT8_SIZE, 1); From 09f9100ce7dcd7ddbe16adfbc91c355017783630 Mon Sep 17 00:00:00 2001 From: hackerman-kl Date: Sun, 19 Apr 2026 07:39:03 +0200 Subject: [PATCH 06/12] milan-avb: validate packet length before dereferencing SET_CONTROL value byte --- .../module-avb/aecp-aem-cmds-resps/cmd-get-set-control.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-control.c b/src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-control.c index 7891782ff..d24a15629 100644 --- a/src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-control.c +++ b/src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-control.c @@ -150,6 +150,11 @@ static int handle_cmd_set_control_identify(struct aecp *aecp, struct descriptor old_value_format = desc_formats; value_req = (uint8_t *)control->payload; + if (len < 0 || (size_t)len < sizeof(*h) + sizeof(*p) + + sizeof(*control) + CONTROL_LINEAR_UINT8_SIZE) + return reply_status(aecp, AVB_AECP_AEM_STATUS_BAD_ARGUMENTS, + m, len); + if (*value_req == desc_formats->current_value) { return reply_success(aecp, m, len); } From e6b4de6442062572d036a6280158b4a135392f5e Mon Sep 17 00:00:00 2001 From: hackerman-kl Date: Sun, 19 Apr 2026 18:58:01 +0200 Subject: [PATCH 07/12] milan-avb: guard against size_t underflow on short packets in unsol reply prepare --- .../module-avb/aecp-aem-cmds-resps/reply-unsol-helpers.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/modules/module-avb/aecp-aem-cmds-resps/reply-unsol-helpers.c b/src/modules/module-avb/aecp-aem-cmds-resps/reply-unsol-helpers.c index dfc6617d4..ab776ba03 100644 --- a/src/modules/module-avb/aecp-aem-cmds-resps/reply-unsol-helpers.c +++ b/src/modules/module-avb/aecp-aem-cmds-resps/reply-unsol-helpers.c @@ -111,8 +111,11 @@ static void reply_unsol_notifications_prepare(struct aecp *aecp, /* Here the value of 12 is the delta between the target_entity_id and start of the AECP message specific data. */ - ctrl_data_length = len - (sizeof(*h) + sizeof(*p)) - + AVB_PACKET_CONTROL_DATA_OFFSET; + if (len < sizeof(*h) + sizeof(*p)) + ctrl_data_length = AVB_PACKET_CONTROL_DATA_OFFSET; + else + ctrl_data_length = len - (sizeof(*h) + sizeof(*p)) + + AVB_PACKET_CONTROL_DATA_OFFSET; h = (struct avb_ethernet_header*) packet; p = SPA_PTROFF(h, sizeof(*h), void); From a8832c74d0fefd6e1bdf9be8ef6359d289ae8ee6 Mon Sep 17 00:00:00 2001 From: hackerman-kl Date: Mon, 20 Apr 2026 18:29:56 +0200 Subject: [PATCH 08/12] module-avb: bound packet copy length in get-set-name handlers --- .../aecp-aem-cmds-resps/cmd-get-set-name.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-name.c b/src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-name.c index 8381a0cbb..0d39c4d4e 100644 --- a/src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-name.c +++ b/src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-name.c @@ -2,6 +2,7 @@ /* SPDX-FileCopyrightText: Copyright © 2025 Alexandre Malki */ /* SPDX-License-Identifier: MIT */ +#include #include #include #include @@ -73,6 +74,9 @@ static int send_unsol_name(struct aecp *aecp, uint8_t unsol_buf[512]; struct aecp_aem_base_info info = { 0 }; + if (len < 0 || (size_t)len > sizeof(unsol_buf)) + return -EINVAL; + memcpy(unsol_buf, msg, len); info.controller_entity_id = htobe64(p->aecp.controller_guid); info.expire_timeout = INT64_MAX; @@ -114,6 +118,11 @@ int handle_cmd_get_name_common(struct aecp *aecp, int64_t now, return reply_status(aecp, AVB_AECP_AEM_STATUS_BAD_ARGUMENTS, m, len); + if (len < 0 || (size_t)len > sizeof(buf) || + (size_t)len < sizeof(*h) + sizeof(*p) + sizeof(*cmd)) + return reply_status(aecp, + AVB_AECP_AEM_STATUS_BAD_ARGUMENTS, m, len); + memcpy(buf, m, len); h_reply = (struct avb_ethernet_header *)buf; p_reply = SPA_PTROFF(h_reply, sizeof(*h_reply), void); @@ -162,6 +171,10 @@ int handle_cmd_set_name_common(struct aecp *aecp, int64_t now, return reply_status(aecp, AVB_AECP_AEM_STATUS_BAD_ARGUMENTS, m, len); + if (len < 0 || (size_t)len < sizeof(*h) + sizeof(*p) + sizeof(*cmd)) + return reply_status(aecp, + AVB_AECP_AEM_STATUS_BAD_ARGUMENTS, m, len); + /** * IEEE 1722.1-2021: 7.4.17.1: The name does not contain a trailing NULL * but if the name is less than 64 bytes in length then it is zero From 6ca2f509e30077afaf8541257e60d61a01e4e675 Mon Sep 17 00:00:00 2001 From: hackerman-kl Date: Wed, 22 Apr 2026 19:19:10 +0200 Subject: [PATCH 09/12] module-avb: bound descriptor size in READ_DESCRIPTOR reply to prevent stack overflow --- src/modules/module-avb/aecp-aem.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/modules/module-avb/aecp-aem.c b/src/modules/module-avb/aecp-aem.c index 78b3eb818..33b4a2dbf 100644 --- a/src/modules/module-avb/aecp-aem.c +++ b/src/modules/module-avb/aecp-aem.c @@ -100,11 +100,17 @@ static int handle_read_descriptor_common(struct aecp *aecp, int64_t now, const v if (desc == NULL) return reply_status(aecp, AVB_AECP_AEM_STATUS_NO_SUCH_DESCRIPTOR, m, len); - memcpy(buf, m, len); + if (len < 0 || (size_t)len > sizeof(buf)) + return reply_status(aecp, AVB_AECP_AEM_STATUS_BAD_ARGUMENTS, m, len); psize = sizeof(*rd); size = sizeof(*h) + sizeof(*reply) + psize; + if (desc->size > sizeof(buf) || size > sizeof(buf) - desc->size) + return reply_status(aecp, AVB_AECP_AEM_STATUS_NO_RESOURCES, m, len); + + memcpy(buf, m, len); + memcpy(buf + size, desc->ptr, desc->size); size += desc->size; psize += desc->size; From f091b85b034a8cb9272fddd624c98989b1e3adcb Mon Sep 17 00:00:00 2001 From: hackerman-kl Date: Thu, 23 Apr 2026 17:25:26 +0200 Subject: [PATCH 10/12] module-avb: enforce minimum AECP packet length and replace VLA on dispatch --- src/modules/module-avb/aecp.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/modules/module-avb/aecp.c b/src/modules/module-avb/aecp.c index 6a15f87a9..442798c04 100644 --- a/src/modules/module-avb/aecp.c +++ b/src/modules/module-avb/aecp.c @@ -2,6 +2,8 @@ /* SPDX-FileCopyrightText: Copyright © 2022 Wim Taymans */ /* SPDX-License-Identifier: MIT */ +#include + #include #include @@ -22,10 +24,13 @@ struct msg_info { static int reply_not_implemented(struct aecp *aecp, const void *p, int len) { struct server *server = aecp->server; - uint8_t buf[len]; + uint8_t buf[AVB_PACKET_MILAN_DEFAULT_MTU]; struct avb_ethernet_header *h = (void*)buf; struct avb_packet_aecp_header *reply = SPA_PTROFF(h, sizeof(*h), void); + if (len < 0 || (size_t)len > sizeof(buf)) + return -EINVAL; + memcpy(h, p, len); AVB_PACKET_AECP_SET_STATUS(reply, AVB_AECP_STATUS_NOT_IMPLEMENTED); @@ -64,6 +69,10 @@ static int aecp_message(void *data, uint64_t now, const void *message, int len) const struct msg_info *info; int message_type; + if (len < 0 || + (size_t)len < sizeof(*h) + sizeof(*p) || + (size_t)len > AVB_PACKET_MILAN_DEFAULT_MTU) + return 0; if (ntohs(h->type) != AVB_TSN_ETH) return 0; if (memcmp(h->dest, mac, 6) != 0 && From 01dd7e607c244098348ffade1923f238988c9978 Mon Sep 17 00:00:00 2001 From: hackerman-kl Date: Fri, 24 Apr 2026 07:02:54 +0200 Subject: [PATCH 11/12] module-avb: bound packet copy length in reply_status helper --- .../module-avb/aecp-aem-cmds-resps/cmd-resp-helpers.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/modules/module-avb/aecp-aem-cmds-resps/cmd-resp-helpers.h b/src/modules/module-avb/aecp-aem-cmds-resps/cmd-resp-helpers.h index de9152a84..bbae66e9c 100644 --- a/src/modules/module-avb/aecp-aem-cmds-resps/cmd-resp-helpers.h +++ b/src/modules/module-avb/aecp-aem-cmds-resps/cmd-resp-helpers.h @@ -6,6 +6,7 @@ #ifndef __AVB_AECP_AEM_HELPERS_H__ #define __AVB_AECP_AEM_HELPERS_H__ +#include #include #include @@ -21,6 +22,11 @@ static inline int reply_status(struct aecp *aecp, int status, const void *m, int struct avb_ethernet_header *h = (void*)buf; struct avb_packet_aecp_header *reply = SPA_PTROFF(h, sizeof(*h), void); + if (len < 0 || (size_t)len > sizeof(buf)) { + pw_log_warn("reply_status: invalid len %d", len); + return -EINVAL; + } + memcpy(buf, m, len); pw_log_debug("status 0x%x\n", status); From 0ac8b1c5fa31bd7f609f61eed252b1980c9b5121 Mon Sep 17 00:00:00 2001 From: hackerman-kl Date: Fri, 24 Apr 2026 07:52:17 +0200 Subject: [PATCH 12/12] module-avb: fix GET_NAME to validate length before field reads and reply with fixed size --- .../aecp-aem-cmds-resps/cmd-get-set-name.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-name.c b/src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-name.c index 0d39c4d4e..8180e56b6 100644 --- a/src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-name.c +++ b/src/modules/module-avb/aecp-aem-cmds-resps/cmd-get-set-name.c @@ -102,6 +102,12 @@ int handle_cmd_get_name_common(struct aecp *aecp, int64_t now, struct descriptor *desc; uint16_t desc_type, desc_id, name_index; char *name_ptr; + size_t reply_len; + + if (len < 0 || (size_t)len > sizeof(buf) || + (size_t)len < sizeof(*h) + sizeof(*p) + sizeof(*cmd)) + return reply_status(aecp, + AVB_AECP_AEM_STATUS_BAD_ARGUMENTS, m, len); cmd = (const struct avb_packet_aecp_aem_setget_name *)p->payload; desc_type = ntohs(cmd->descriptor_type); @@ -118,12 +124,9 @@ int handle_cmd_get_name_common(struct aecp *aecp, int64_t now, return reply_status(aecp, AVB_AECP_AEM_STATUS_BAD_ARGUMENTS, m, len); - if (len < 0 || (size_t)len > sizeof(buf) || - (size_t)len < sizeof(*h) + sizeof(*p) + sizeof(*cmd)) - return reply_status(aecp, - AVB_AECP_AEM_STATUS_BAD_ARGUMENTS, m, len); + reply_len = sizeof(*h) + sizeof(*p) + sizeof(*cmd); - memcpy(buf, m, len); + memcpy(buf, m, reply_len); h_reply = (struct avb_ethernet_header *)buf; p_reply = SPA_PTROFF(h_reply, sizeof(*h_reply), void); reply = (struct avb_packet_aecp_aem_setget_name *)p_reply->payload; @@ -135,7 +138,7 @@ int handle_cmd_get_name_common(struct aecp *aecp, int64_t now, */ memcpy(reply->name, name_ptr, 64); - return reply_success(aecp, buf, len); + return reply_success(aecp, buf, reply_len); }