hw/intc/bcm2835_ic.c | 13 +++++-- tests/qtest/bcm2835-ic-test.c | 66 +++++++++++++++++++++++++++++++++++ tests/qtest/meson.build | 2 +- 3 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 tests/qtest/bcm2835-ic-test.c
The FIQ_CONTROL register accepts a 7-bit source selector, but only
sources 0..71 (64 GPU + 8 ARM IRQs) exist. Values 96..127 cause
bcm2835_ic_update() to call extract32(arm_irq_level, start, 1) with
start >= 32, which trips the assertion in bitops.h and aborts QEMU.
Reject writes that select a non-existent source and log a guest error,
so that a malicious or buggy guest cannot kill the emulator.
Add a qtest that verifies both valid and out-of-range FIQ source
selections on raspi3b.
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4368
Signed-off-by: Bin Guo <guobin@linux.alibaba.com>
---
hw/intc/bcm2835_ic.c | 13 +++++--
tests/qtest/bcm2835-ic-test.c | 66 +++++++++++++++++++++++++++++++++++
tests/qtest/meson.build | 2 +-
3 files changed, 78 insertions(+), 3 deletions(-)
create mode 100644 tests/qtest/bcm2835-ic-test.c
diff --git a/hw/intc/bcm2835_ic.c b/hw/intc/bcm2835_ic.c
index 71bf671761..262a620968 100644
--- a/hw/intc/bcm2835_ic.c
+++ b/hw/intc/bcm2835_ic.c
@@ -139,10 +139,19 @@ static void bcm2835_ic_write(void *opaque, hwaddr offset, uint64_t val,
BCM2835ICState *s = opaque;
switch (offset) {
- case FIQ_CONTROL:
- s->fiq_select = extract32(val, 0, 7);
+ case FIQ_CONTROL: {
+ unsigned fiq_select = extract32(val, 0, 7);
+
+ if (fiq_select >= GPU_IRQS + ARM_IRQS) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: FIQ select %u out of range\n",
+ __func__, fiq_select);
+ return;
+ }
+ s->fiq_select = fiq_select;
s->fiq_enable = extract32(val, 7, 1);
break;
+ }
case IRQ_ENABLE_1:
s->gpu_irq_enable |= val;
break;
diff --git a/tests/qtest/bcm2835-ic-test.c b/tests/qtest/bcm2835-ic-test.c
new file mode 100644
index 0000000000..1e171ee092
--- /dev/null
+++ b/tests/qtest/bcm2835-ic-test.c
@@ -0,0 +1,66 @@
+/*
+ * QTest testcase for the BCM2835 Interrupt Controller
+ *
+ * Copyright (c) 2026 Bin Guo <guobin@linux.alibaba.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest-single.h"
+
+#define IC_BASE 0x3f00b200
+#define FIQ_CONTROL (IC_BASE + 0x0c)
+
+static void test_fiq_select_out_of_range(void)
+{
+ uint32_t val;
+
+ /*
+ * Only FIQ sources 0..71 exist. Source 96 used to trigger an assertion
+ * in bcm2835_ic_update() because extract32(arm_irq_level, 32, 1) was
+ * called with start >= 32. Make sure the write is rejected and QEMU
+ * keeps running.
+ */
+ writel(FIQ_CONTROL, 0xe0); /* fiq_select = 96, fiq_enable = 1 */
+ val = readl(FIQ_CONTROL);
+ g_assert_cmpint(val, ==, 0);
+
+ /* The first source past the ARM IRQ range should also be rejected. */
+ writel(FIQ_CONTROL, 0xc8); /* fiq_select = 72, fiq_enable = 1 */
+ val = readl(FIQ_CONTROL);
+ g_assert_cmpint(val, ==, 0);
+}
+
+static void test_fiq_select_valid(void)
+{
+ uint32_t val;
+
+ /* Select the highest valid ARM IRQ source (64 + 7 = 71). */
+ writel(FIQ_CONTROL, 0xc7); /* fiq_select = 71, fiq_enable = 1 */
+ val = readl(FIQ_CONTROL);
+ g_assert_cmpint(val, ==, 0xc7);
+
+ /* Select the highest valid GPU IRQ source. */
+ writel(FIQ_CONTROL, 0x3f); /* fiq_select = 63, fiq_enable = 0 */
+ val = readl(FIQ_CONTROL);
+ g_assert_cmpint(val, ==, 0x3f);
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+
+ g_test_init(&argc, &argv, NULL);
+
+ qtest_add_func("/bcm2835/bcm2835-ic/fiq-select-out-of-range",
+ test_fiq_select_out_of_range);
+ qtest_add_func("/bcm2835/bcm2835-ic/fiq-select-valid",
+ test_fiq_select_valid);
+
+ qtest_start("-machine raspi3b");
+ ret = g_test_run();
+ qtest_end();
+
+ return ret;
+}
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index a13c4af989..149b395e53 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -274,7 +274,7 @@ qtests_aarch64 = \
['tpm-tis-device-test', 'tpm-tis-device-swtpm-test'] : []) + \
(config_all_devices.has_key('CONFIG_XLNX_ZYNQMP_ARM') ? ['xlnx-can-test', 'fuzz-xlnx-dp-test'] : []) + \
(config_all_devices.has_key('CONFIG_XLNX_VERSAL') ? ['xlnx-canfd-test', 'xlnx-versal-trng-test'] : []) + \
- (config_all_devices.has_key('CONFIG_RASPI') ? ['bcm2835-dma-test', 'bcm2835-i2c-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_RASPI') ? ['bcm2835-dma-test', 'bcm2835-i2c-test', 'bcm2835-ic-test'] : []) + \
(config_all_accel.has_key('CONFIG_TCG') and \
config_all_devices.has_key('CONFIG_TPM_TIS_I2C') ? ['tpm-tis-i2c-test', 'tpm-tis-i2c-swtpm-test'] : []) + \
(config_all_devices.has_key('CONFIG_ASPEED_SOC') ? qtests_aspeed64 : []) + \
--
2.50.1 (Apple Git-155)
On 8/31/26 11:17, Bin Guo wrote: > The FIQ_CONTROL register accepts a 7-bit source selector, but only > sources 0..71 (64 GPU + 8 ARM IRQs) exist. Values 96..127 cause > bcm2835_ic_update() to call extract32(arm_irq_level, start, 1) with > start >= 32, which trips the assertion in bitops.h and aborts QEMU. > > Reject writes that select a non-existent source and log a guest error, > so that a malicious or buggy guest cannot kill the emulator. > > Add a qtest that verifies both valid and out-of-range FIQ source > selections on raspi3b. > > Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4368 > Signed-off-by: Bin Guo <guobin@linux.alibaba.com> > --- > hw/intc/bcm2835_ic.c | 13 +++++-- > tests/qtest/bcm2835-ic-test.c | 66 +++++++++++++++++++++++++++++++++++ > tests/qtest/meson.build | 2 +- > 3 files changed, 78 insertions(+), 3 deletions(-) > create mode 100644 tests/qtest/bcm2835-ic-test.c I'm picking this up for currently active stable qemu series. Please let me know if I shouldn't. Thanks, /mjt
On Mon, 31 Aug 2026 at 09:17, Bin Guo <guobin@linux.alibaba.com> wrote: > > The FIQ_CONTROL register accepts a 7-bit source selector, but only > sources 0..71 (64 GPU + 8 ARM IRQs) exist. Values 96..127 cause > bcm2835_ic_update() to call extract32(arm_irq_level, start, 1) with > start >= 32, which trips the assertion in bitops.h and aborts QEMU. > > Reject writes that select a non-existent source and log a guest error, > so that a malicious or buggy guest cannot kill the emulator. > > Add a qtest that verifies both valid and out-of-range FIQ source > selections on raspi3b. > > Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4368 > Signed-off-by: Bin Guo <guobin@linux.alibaba.com> Applied to target-arm.next, thanks. -- PMM
On 31/8/26 10:17, Bin Guo wrote: > The FIQ_CONTROL register accepts a 7-bit source selector, but only > sources 0..71 (64 GPU + 8 ARM IRQs) exist. Values 96..127 cause > bcm2835_ic_update() to call extract32(arm_irq_level, start, 1) with > start >= 32, which trips the assertion in bitops.h and aborts QEMU. > > Reject writes that select a non-existent source and log a guest error, > so that a malicious or buggy guest cannot kill the emulator. > > Add a qtest that verifies both valid and out-of-range FIQ source > selections on raspi3b. > > Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4368 > Signed-off-by: Bin Guo <guobin@linux.alibaba.com> > --- > hw/intc/bcm2835_ic.c | 13 +++++-- > tests/qtest/bcm2835-ic-test.c | 66 +++++++++++++++++++++++++++++++++++ > tests/qtest/meson.build | 2 +- > 3 files changed, 78 insertions(+), 3 deletions(-) > create mode 100644 tests/qtest/bcm2835-ic-test.c Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
© 2016 - 2026 Red Hat, Inc.