firewire: core: add test to avoid excessive configuration ROM length

The configuration ROM parser needs to handle malformed ROM contents
safely. In particular, malformed directory and leaf offsets and block
lengths should not result in accesses beyond the available configuration
ROM data.

Add a KUnit test with malformed configuration ROM content to verify that
the parser sanitizes entries that would cause accesses beyond the
available configuration ROM data.

Reported-by: Aleksandr Shabelnikov <mistermidi@gmail.com>
Link: https://lore.kernel.org/lkml/20250901171547.47065-1-mistermidi@gmail.com/
Link: https://lore.kernel.org/r/20260901134534.2386577-7-o-takashi@sakamocchi.jp
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
This commit is contained in:
Takashi Sakamoto committed 2026-09-01 22:45:27 +09:00
1 parent 7b9011c209
commit 1c4326e7d8
1 file changed
+66 -2
+66 -2
View File
@@ -193,7 +193,7 @@ static const struct parser_test_case {
// Define parser_test_gen_params.
KUNIT_ARRAY_PARAM_DESC(parser_test, parser_test_cases, name);
static int stub_run_regular_transaction(struct fw_card *card, int tcode, int destination_id,
static int stub_run_transaction_regular(struct fw_card *card, int tcode, int destination_id,
int generation, int speed, unsigned long long offset,
void *payload, size_t length)
{
@@ -221,7 +221,7 @@ static void test_parser_with_regular_cases(struct kunit *test)
struct fw_device *device = test->priv;
const struct parser_test_case *param = test->param_value;
kunit_activate_static_stub(test, fw_run_transaction, stub_run_regular_transaction);
kunit_activate_static_stub(test, fw_run_transaction, stub_run_transaction_regular);
device->card->link_speed = SCODE_BETA;
device->node->max_speed = param->phy_speed_in_self_id;
@@ -240,6 +240,69 @@ static void test_parser_with_regular_cases(struct kunit *test)
kunit_deactivate_static_stub(test, fw_run_transaction);
}
static int stub_run_transaction_malformed(struct fw_card *card, int tcode, int destination_id,
int generation, int speed, unsigned long long offset,
void *payload, size_t length)
{
static const u32 config_rom_first_part[] = {
0x04000000,
0x31333934,
0x00008002,
0x00000000,
0x00000000,
0x00030000,
(CSR_VENDOR << 24) | 0x00123456, // Regular entry.
((CSR_LEAF | CSR_DESCRIPTOR) << 24) | 0x000000f9, // Beyond the upper limit.
((CSR_DIRECTORY | CSR_UNIT) << 24) | 0x00000001,
0xffff0000, // Over the upper limit.
};
struct kunit *test = kunit_get_current_test();
KUNIT_ASSERT_GE(test, offset, CSR_REGISTER_BASE | CSR_CONFIG_ROM);
KUNIT_ASSERT_LT(test, offset, CSR_REGISTER_BASE | CSR_CONFIG_ROM_END);
KUNIT_ASSERT_NOT_NULL(test, payload);
KUNIT_ASSERT_EQ(test, length, 4);
unsigned int index = (offset - (CSR_REGISTER_BASE | CSR_CONFIG_ROM)) / sizeof(u32);
u32 *quadlet = payload;
if (index < ARRAY_SIZE(config_rom_first_part))
*quadlet = cpu_to_be32(config_rom_first_part[index]);
else
*quadlet = 0;
return RCODE_COMPLETE;
}
static void test_parser_with_overflowed_case(struct kunit *test)
{
static const u32 corrected_config_rom[] = {
0x04000000,
0x31333934,
0x00008002,
0x00000000,
0x00000000,
0x00030000,
0x03123456,
0x00000000, // Sanitized.
0xd1000001,
0x00000000, // Sanitized.
};
struct fw_device *device = test->priv;
kunit_activate_static_stub(test, fw_run_transaction, stub_run_transaction_malformed);
device->card->link_speed = SCODE_BETA;
KUNIT_EXPECT_EQ(test, read_config_rom(device, 0), RCODE_COMPLETE);
KUNIT_EXPECT_EQ(test, device->config_rom_length, ARRAY_SIZE(corrected_config_rom));
KUNIT_EXPECT_MEMEQ(test, device->config_rom, corrected_config_rom,
sizeof(corrected_config_rom));
kunit_deactivate_static_stub(test, fw_run_transaction);
}
static const struct fw_card_driver dummy_card_driver;
static int config_rom_parser_test_init(struct kunit *test)
@@ -279,6 +342,7 @@ static void config_rom_parser_test_exit(struct kunit *test)
static struct kunit_case config_rom_parser_test_cases[] = {
KUNIT_CASE_PARAM(test_parser_with_regular_cases, parser_test_gen_params),
KUNIT_CASE(test_parser_with_overflowed_case),
{}
};