sd-bus: add depth limit to message_skip_fields() to prevent stack overflow

message_skip_fields() recurses for each nested variant ('v') type in
D-Bus message header fields. A crafted message with deeply nested
variants (e.g., a variant containing a variant containing a variant...)
causes unbounded stack growth, leading to stack overflow and crash.

Add a depth parameter that increments on each recursive call and
rejects messages exceeding BUS_CONTAINER_DEPTH with -EBADMSG. This
matches the existing depth limits enforced elsewhere in the sd-bus
message processing (e.g., bus_message_enter_container).
This commit is contained in:
TristanInSec
2026-05-19 17:33:06 -04:00
parent 6080d1cc42
commit 9b21738498

View File

@@ -3904,7 +3904,8 @@ static int message_skip_fields(
sd_bus_message *m,
size_t *ri,
uint32_t array_size,
const char **signature) {
const char **signature,
unsigned depth) {
size_t original_index;
int r;
@@ -3913,6 +3914,9 @@ static int message_skip_fields(
assert(ri);
assert(signature);
if (depth >= BUS_CONTAINER_DEPTH)
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "Maximum container nesting depth reached, refusing.");
original_index = *ri;
for (;;) {
@@ -3993,7 +3997,7 @@ static int message_skip_fields(
if (r < 0)
return r;
r = message_skip_fields(m, ri, nas, (const char**) &s);
r = message_skip_fields(m, ri, nas, (const char**) &s, depth + 1);
if (r < 0)
return r;
}
@@ -4007,7 +4011,7 @@ static int message_skip_fields(
if (r < 0)
return r;
r = message_skip_fields(m, ri, UINT32_MAX, &s);
r = message_skip_fields(m, ri, UINT32_MAX, &s, depth + 1);
if (r < 0)
return r;
@@ -4025,7 +4029,7 @@ static int message_skip_fields(
strncpy(sig, *signature + 1, l);
sig[l] = '\0';
r = message_skip_fields(m, ri, UINT32_MAX, (const char**) &s);
r = message_skip_fields(m, ri, UINT32_MAX, (const char**) &s, depth + 1);
if (r < 0)
return r;
}
@@ -4198,7 +4202,7 @@ static int message_parse_fields(sd_bus_message *m, bool got_ctrunc) {
break;
default:
r = message_skip_fields(m, &ri, UINT32_MAX, &signature);
r = message_skip_fields(m, &ri, UINT32_MAX, &signature, 0);
}
if (r < 0)
return r;