@samitouri / QOSamiQemu / commits / d5b33fc180

hw/intc: fix heap OOB in ACLINT MTIMER multi-socket

The MMIO read/write handlers index timecmp[] with the absolute hartid (hartid_base + offset) but the array is allocated with num_harts elements. In multi-socket configurations with hartid_base > 0 this causes heap OOB access in the QEMU process. Fix by using the relative offset for array indexing. Cc: qemu-security@nongnu.org Signed-off-by: Sebastián Alba Vives <sebasjosue84@gmail.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260401053853.10473-2-sebasjosue84@gmail.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>

Sebastián Alba Vives committed Mar 31, 2026 at 23:38 UTC d5b33fc180f557ee3574cef9c64650174d0ef5dd
1 file changed +6 -4
hw/intc/riscv_aclint.c
+6 -4
@@ -131,6 +131,7 @@ static uint64_t riscv_aclint_mtimer_read(void *opaque, hwaddr addr,
131 addr < (mtimer->timecmp_base + (mtimer->num_harts << 3))) {
132 size_t hartid = mtimer->hartid_base +
133 ((addr - mtimer->timecmp_base) >> 3);
134 + size_t hartid_offset = hartid - mtimer->hartid_base;
135 CPUState *cpu = cpu_by_arch_id(hartid);
136 CPURISCVState *env = cpu ? cpu_env(cpu) : NULL;
137 if (!env) {
@@ -138,11 +139,11 @@ static uint64_t riscv_aclint_mtimer_read(void *opaque, hwaddr addr,
139 "aclint-mtimer: invalid hartid: %zu", hartid);
140 } else if ((addr & 0x7) == 0) {
141 /* timecmp_lo for RV32/RV64 or timecmp for RV64 */
141 - uint64_t timecmp = mtimer->timecmp[hartid];
142 + uint64_t timecmp = mtimer->timecmp[hartid_offset];
143 return (size == 4) ? (timecmp & 0xFFFFFFFF) : timecmp;
144 } else if ((addr & 0x7) == 4) {
145 /* timecmp_hi */
145 - uint64_t timecmp = mtimer->timecmp[hartid];
146 + uint64_t timecmp = mtimer->timecmp[hartid_offset];
147 return (timecmp >> 32) & 0xFFFFFFFF;
148 } else {
149 qemu_log_mask(LOG_UNIMP,
@@ -174,6 +175,7 @@ static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr,
175 addr < (mtimer->timecmp_base + (mtimer->num_harts << 3))) {
176 size_t hartid = mtimer->hartid_base +
177 ((addr - mtimer->timecmp_base) >> 3);
178 + size_t hartid_offset = hartid - mtimer->hartid_base;
179 CPUState *cpu = cpu_by_arch_id(hartid);
180 CPURISCVState *env = cpu ? cpu_env(cpu) : NULL;
181 if (!env) {
@@ -182,7 +184,7 @@ static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr,
184 } else if ((addr & 0x7) == 0) {
185 if (size == 4) {
186 /* timecmp_lo for RV32/RV64 */
185 - uint64_t timecmp_hi = mtimer->timecmp[hartid] >> 32;
187 + uint64_t timecmp_hi = mtimer->timecmp[hartid_offset] >> 32;
188 riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu), hartid,
189 timecmp_hi << 32 | (value & 0xFFFFFFFF));
190 } else {
@@ -193,7 +195,7 @@ static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr,
195 } else if ((addr & 0x7) == 4) {
196 if (size == 4) {
197 /* timecmp_hi for RV32/RV64 */
196 - uint64_t timecmp_lo = mtimer->timecmp[hartid];
198 + uint64_t timecmp_lo = mtimer->timecmp[hartid_offset];
199 riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu), hartid,
200 value << 32 | (timecmp_lo & 0xFFFFFFFF));
201 } else {