security: reject negative DBus array lengths in Bluetooth transport

Memory Safety: High

dbus_message_iter_get_fixed_array() returns the array length as a
signed int. A malformed DBus message could produce a negative length
value. In the Configuration property handler, the check 'if (!len)'
does not catch negative values, allowing negative lengths to be passed
to malloc() and memcpy() where sign extension to size_t creates
enormous values. The debug logging call spa_debug_log_mem() also
receives the negative length cast to size_t, causing an out-of-bounds
read.

In the Capabilities/Metadata handler, 'if (n)' is similarly true for
negative values, and the negative int assigned to the size_t *size
output parameter corrupts the stored length.

Fix by using 'len <= 0' and 'n > 0' checks respectively, and move
debug logging after validation. Explicitly zero the length on the
negative/zero path to prevent storing corrupted sizes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Wim Taymans 2026-04-24 16:54:26 +02:00
parent f3538dd7fe
commit c525cfcced

View file

@ -1035,13 +1035,14 @@ static int parse_endpoint_props(struct spa_bt_monitor *monitor, DBusMessageIter
dbus_message_iter_recurse(&it[1], &it[2]);
dbus_message_iter_get_fixed_array(&it[2], &data, &n);
if (n) {
if (n > 0) {
buf = malloc(n);
if (!buf)
return -ENOMEM;
memcpy(buf, data, n);
} else {
buf = NULL;
n = 0;
}
free(*dest);
@ -3834,17 +3835,17 @@ static int transport_update_props(struct spa_bt_transport *transport,
dbus_message_iter_recurse(&it[1], &iter);
dbus_message_iter_get_fixed_array(&iter, &value, &len);
spa_log_debug(monitor->log, "transport %p: %s=%d", transport, key, len);
spa_debug_log_mem(monitor->log, SPA_LOG_LEVEL_DEBUG, 2, value, (size_t)len);
free(transport->configuration);
transport->configuration_len = 0;
if (!len) {
if (len <= 0) {
transport->configuration = NULL;
goto next;
}
spa_log_debug(monitor->log, "transport %p: %s=%d", transport, key, len);
spa_debug_log_mem(monitor->log, SPA_LOG_LEVEL_DEBUG, 2, value, (size_t)len);
transport->configuration = malloc(len);
if (transport->configuration) {
memcpy(transport->configuration, value, len);