Skip to content

Commit 1596b3b

Browse files
committed
Add upper limit for PCI capabilities
Prevent loops on malformed PCI trees F/232
1 parent e4b12e4 commit 1596b3b

3 files changed

Lines changed: 123 additions & 2 deletions

File tree

src/boot_x86_fsp.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ const uint8_t __attribute__((section(".sig_wolfboot_raw")))
8282
#define FSP_STATUS_RESET_REQUIRED_WARM 0x40000002
8383
#define MEMORY_4GB (4ULL * 1024 * 1024 * 1024)
8484
#define ENDLINE "\r\n"
85+
/* Standard PCI capabilities live in conventional config space at 0x40-0xFC,
86+
* on 4-byte alignment, so there are at most 48 distinct capability headers. */
87+
#define PCI_MAX_STANDARD_CAPABILITIES 48
8588

8689

8790
/* compile time alignment checks */
@@ -342,19 +345,21 @@ static int pci_get_capability(uint8_t bus, uint8_t dev, uint8_t fun,
342345
uint8_t cap_id, uint8_t *cap_off)
343346
{
344347
uint8_t r8, id;
348+
uint8_t cap_count = 0;
345349
uint32_t r32;
346350

347351
r32 = pci_config_read16(bus, dev, fun, PCI_STATUS_OFFSET);
348352
if (!(r32 & PCI_STATUS_CAP_LIST))
349353
return -1;
350354
r8 = pci_config_read8(bus, dev, fun, PCI_CAP_OFFSET);
351-
while (r8 != 0) {
355+
while ((r8 != 0) && (cap_count < PCI_MAX_STANDARD_CAPABILITIES)) {
352356
id = pci_config_read8(bus, dev, fun, r8);
353357
if (id == cap_id) {
354358
*cap_off = r8;
355359
return 0;
356360
}
357361
r8 = pci_config_read8(bus, dev, fun, r8 + 1);
362+
cap_count++;
358363
}
359364
return -1;
360365
}

tools/unit-tests/Makefile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ TESTS:=unit-parser unit-extflash unit-string unit-spi-flash unit-aes128 \
3838
unit-image unit-image-rsa unit-nvm unit-nvm-flagshome unit-enc-nvm \
3939
unit-enc-nvm-flagshome unit-delta unit-update-flash \
4040
unit-update-flash-enc unit-update-ram unit-pkcs11_store unit-psa_store unit-disk \
41-
unit-multiboot
41+
unit-multiboot unit-boot-x86-fsp
4242

4343
all: $(TESTS)
4444

@@ -121,6 +121,11 @@ unit-chacha20: ../../include/target.h unit-extflash.c
121121
unit-pci: unit-pci.c ../../src/pci.c
122122
gcc -o $@ $< $(CFLAGS) -DWOLFBOOT_USE_PCI $(LDFLAGS)
123123

124+
unit-boot-x86-fsp: ../../include/target.h unit-boot-x86_fsp.c
125+
gcc -o $@ $^ $(CFLAGS) -DWOLFBOOT_LOAD_BASE=0x100000 -DWOLFBOOT_FSP \
126+
-DUCODE0_ADDRESS=0 -ffunction-sections -fdata-sections $(LDFLAGS) \
127+
-Wl,--gc-sections
128+
124129
unit-mock-state: ../../include/target.h unit-mock-state.c
125130
gcc -o $@ $^ $(CFLAGS) $(LDFLAGS)
126131

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/* unit-boot-x86_fsp.c
2+
*
3+
* Unit tests for selected boot_x86_fsp helpers.
4+
*/
5+
6+
#include <check.h>
7+
#include <stdint.h>
8+
#include <string.h>
9+
10+
#define TEST_CFG_SIZE 256
11+
#define TEST_READ_LIMIT 200
12+
13+
static uint8_t test_cfg[TEST_CFG_SIZE];
14+
static unsigned int test_read_count;
15+
16+
uint8_t pci_config_read8(uint8_t bus, uint8_t dev, uint8_t fun, uint8_t off)
17+
{
18+
(void)bus;
19+
(void)dev;
20+
(void)fun;
21+
22+
test_read_count++;
23+
ck_assert_msg(test_read_count < TEST_READ_LIMIT,
24+
"pci_get_capability exceeded read limit on cyclic list");
25+
return test_cfg[off];
26+
}
27+
28+
uint16_t pci_config_read16(uint8_t bus, uint8_t dev, uint8_t fun, uint8_t off)
29+
{
30+
uint16_t value;
31+
32+
(void)bus;
33+
(void)dev;
34+
(void)fun;
35+
36+
test_read_count++;
37+
ck_assert_msg(test_read_count < TEST_READ_LIMIT,
38+
"pci_get_capability exceeded read limit on cyclic list");
39+
memcpy(&value, &test_cfg[off], sizeof(value));
40+
return value;
41+
}
42+
43+
#include "../../src/boot_x86_fsp.c"
44+
45+
static void setup(void)
46+
{
47+
memset(test_cfg, 0, sizeof(test_cfg));
48+
test_read_count = 0;
49+
}
50+
51+
START_TEST(test_pci_get_capability_finds_requested_capability)
52+
{
53+
uint8_t cap_off = 0;
54+
uint16_t status = PCI_STATUS_CAP_LIST;
55+
56+
memcpy(&test_cfg[PCI_STATUS_OFFSET], &status, sizeof(status));
57+
test_cfg[PCI_CAP_OFFSET] = 0x40;
58+
test_cfg[0x40] = 0x01;
59+
test_cfg[0x41] = 0x48;
60+
test_cfg[0x48] = PCI_PCIE_CAP_ID;
61+
test_cfg[0x49] = 0x00;
62+
63+
ck_assert_int_eq(pci_get_capability(0, 0, 0, PCI_PCIE_CAP_ID, &cap_off), 0);
64+
ck_assert_uint_eq(cap_off, 0x48);
65+
}
66+
END_TEST
67+
68+
START_TEST(test_pci_get_capability_rejects_cyclic_capability_lists)
69+
{
70+
uint8_t cap_off = 0xAA;
71+
uint16_t status = PCI_STATUS_CAP_LIST;
72+
73+
memcpy(&test_cfg[PCI_STATUS_OFFSET], &status, sizeof(status));
74+
test_cfg[PCI_CAP_OFFSET] = 0x40;
75+
test_cfg[0x40] = 0x01;
76+
test_cfg[0x41] = 0x48;
77+
test_cfg[0x48] = 0x05;
78+
test_cfg[0x49] = 0x40;
79+
80+
ck_assert_int_eq(pci_get_capability(0, 0, 0, PCI_PCIE_CAP_ID, &cap_off), -1);
81+
ck_assert_uint_eq(cap_off, 0xAA);
82+
}
83+
END_TEST
84+
85+
static Suite *boot_x86_fsp_suite(void)
86+
{
87+
Suite *s;
88+
TCase *tc;
89+
90+
s = suite_create("boot_x86_fsp");
91+
tc = tcase_create("pci_get_capability");
92+
tcase_add_checked_fixture(tc, setup, NULL);
93+
tcase_add_test(tc, test_pci_get_capability_finds_requested_capability);
94+
tcase_add_test(tc, test_pci_get_capability_rejects_cyclic_capability_lists);
95+
suite_add_tcase(s, tc);
96+
return s;
97+
}
98+
99+
int main(void)
100+
{
101+
Suite *s;
102+
SRunner *sr;
103+
int failed;
104+
105+
s = boot_x86_fsp_suite();
106+
sr = srunner_create(s);
107+
srunner_run_all(sr, CK_NORMAL);
108+
failed = srunner_ntests_failed(sr);
109+
srunner_free(sr);
110+
return failed == 0 ? 0 : 1;
111+
}

0 commit comments

Comments
 (0)