log_info("All fd truncation tests passed");
}
+static void test_bus_nested_variant_depth_limit(void) {
+ /* Craft a raw D-Bus message with an unknown header field whose value is a variant
+ * containing a variant containing a variant... nested beyond BUS_CONTAINER_DEPTH.
+ * Without the depth limit in message_skip_fields(), this causes unbounded recursion
+ * and stack overflow. With the fix, it should be rejected with -EBADMSG. */
+
+ _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+ const unsigned depth = BUS_CONTAINER_DEPTH + 1; /* one past the limit */
+
+ /* Each nesting level in the fields area is: 1 byte sig_len + 1 byte 'v' + 1 byte NUL = 3 bytes.
+ * The innermost level has sig_len=1, 'u', NUL, then 4 bytes for the uint32 value.
+ * The field header is: 1 byte field_code + 1 byte sig_len + 1 byte 'v' + 1 byte NUL = 4 bytes. */
+ size_t fields_size = 4 + (depth * 3) + 4; /* field header + nested variant sigs + uint32 */
+ size_t padded_fields = ALIGN8(fields_size);
+ size_t total = sizeof(BusMessageHeader) + padded_fields;
+
+ _cleanup_free_ void *buf = ASSERT_PTR(malloc0(total));
+
+ BusMessageHeader *h = buf;
+ *h = (BusMessageHeader) {
+ .endian = BUS_NATIVE_ENDIAN,
+ .type = SD_BUS_MESSAGE_METHOD_CALL,
+ .version = 1,
+ .serial = 1,
+ .fields_size = (uint32_t) fields_size,
+ };
+
+ uint8_t *p = (uint8_t *) buf + sizeof(BusMessageHeader);
+
+ /* Unknown field code (triggers default: in message_parse_fields) */
+ *p++ = 0xFF;
+ /* Field signature: variant */
+ *p++ = 1; /* sig length */
+ *p++ = 'v';
+ *p++ = '\0';
+
+ /* Nested variant signatures: each level declares its content is another variant */
+ for (unsigned i = 0; i < depth; i++) {
+ *p++ = 1; /* sig length */
+ *p++ = 'v';
+ *p++ = '\0';
+ }
+
+ /* Innermost value: a uint32 */
+ memset(p, 0, 4);
+
+ ASSERT_OK(sd_bus_new(&bus));
+
+ ASSERT_ERROR(bus_message_from_malloc(bus, buf, total, NULL, 0, false, NULL, &m), EBADMSG);
+}
+
static void test_bus_label_escape(void) {
test_bus_label_escape_one("foo123bar", "foo123bar");
test_bus_label_escape_one("foo.bar", "foo_2ebar");
test_bus_path_encode_unique();
test_bus_path_encode_many();
test_bus_fds_truncated();
+ test_bus_nested_variant_depth_limit();
return 0;
}