[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v2 1/2] libacpi: Prevent CPU hotplug AML from corrupting memory
On 12.09.2025 11:32, Alejandro Vallejo wrote: > On Fri Sep 12, 2025 at 8:40 AM CEST, Jan Beulich wrote: >> On 11.09.2025 18:23, Alejandro Vallejo wrote: >>> CPU hotplug relies on the online CPU bitmap being provided on PIO 0xaf00 >>> by the device model. The GPE handler checks this and compares it against >>> the "online" flag on each MADT LAPIC entry, setting the flag to its >>> related bit in the bitmap and adjusting the table's checksum. >>> >>> The bytecode doesn't, however, stop at NCPUS. It keeps comparing until it >>> reaches 128, even if that overflows the MADT into some other (hopefully >>> mapped) memory. The reading isn't as problematic as the writing though. >>> >>> If an "entry" outside the MADT is deemed to disagree with the CPU bitmap >>> then the bit where the "online" flag would be is flipped, thus >>> corrupting that memory. And the MADT checksum gets adjusted for a flip >>> that happened outside its range. It's all terrible. >>> >>> Note that this corruption happens regardless of the device-model being >>> present or not, because even if the bitmap holds 0s, the overflowed >>> memory might not at the bits corresponding to the "online" flag. >>> >>> This patch adjusts the DSDT so entries >=NCPUS are skipped. >>> >>> Fixes: 087543338924("hvmloader: limit CPUs exposed to guests") >>> Reported-by: Grygorii Strashko <grygorii_strashko@xxxxxxxx> >>> Signed-off-by: Alejandro Vallejo <alejandro.garciavallejo@xxxxxxx> >> >> In principle: >> Reviewed-by: Jan Beulich <jbeulich@xxxxxxxx> > > Cheers, > >> >> However, ... >> >>> --- a/tools/libacpi/mk_dsdt.c >>> +++ b/tools/libacpi/mk_dsdt.c >>> @@ -231,6 +231,20 @@ int main(int argc, char **argv) >>> stmt("Store", "ToBuffer(PRS), Local0"); >>> for ( cpu = 0; cpu < max_cpus; cpu++ ) >>> { >>> + if ( cpu ) >>> + { >>> + /* >>> + * Check if we're still within the MADT bounds >>> + * >>> + * LLess() takes one byte, but LLessEqual() takes two. Increase >>> + * `cpu` by 1, so we can avoid it. It does add up once you do >>> it >>> + * 127 times! >>> + */ >>> + push_block("If", "LLess(\\_SB.NCPU, %d)", 1 + cpu); >>> + stmt("Return", "One"); >> >> ... if you already care about size bloat in the conditional, why are the two >> bytes per instance that this extra return requires not relevant? They too >> add up, and they can be avoided by wrapping the If around the rest of the >> code. I didn't count it, but I expect the If encoding to grow by at most one >> byte, perhaps none at all. > > I don't mind either way. Removing the "return" statement and the pop_block() > would save 254 bytes in tota at most. I don't think the conditional would grow > because the there wouldn't be that much contained within, but regardless the > early return is in the spirit of not going through 127 conditionals on every > GPE handle when you typically only have a handful of CPUs. The sooner we drop > out of AML, the better. > > In due time I want to shrink this to be an AML loop in dsdt.asl so it can > be taken out of mk_dsdt.c. That will both shrink the DSDT (a ton) and > accelerate > GPE handling, but I don't have time to do it at the moment. > > Do you have a preference in table size vs execution-time? Personally I'd favor table size. The AML interpreter is slow anyway. Jan
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |