[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v2 1/2] x86/mm: add API for marking only part of a MMIO page read only
On Fri, May 5, 2023 at 5:26 PM Marek Marczykowski-Górecki <marmarek@xxxxxxxxxxxxxxxxxxxxxx> wrote: > > In some cases, only few registers on a page needs to be write-protected. Maybe "In some cases, only part of a page needs to be write-protected"? > Examples include USB3 console (64 bytes worth of registers) or MSI-X's > PBA table (which doesn't need to span the whole table either), although > in the latter case the spec forbids placing other registers on the same > page. Current API allows only marking whole pages pages read-only, > which sometimes may cover other registers that guest may need to > write into. > > Currently, when a guest tries to write to an MMIO page on the > mmio_ro_ranges, it's either immediately crashed on EPT violation - if > that's HVM, or if PV, it gets #PF. In case of Linux PV, if access was > from userspace (like, /dev/mem), it will try to fixup by updating page > tables (that Xen again will force to read-only) and will hit that #PF > again (looping endlessly). Both behaviors are undesirable if guest could > actually be allowed the write. > > Introduce an API that allows marking part of a page read-only. Since > sub-page permissions are not a thing in page tables (they are in EPT, > but not granular enough), do this via emulation (or simply page fault > handler for PV) that handles writes that are supposed to be allowed. > The new subpage_mmio_ro_add() takes a start physical address and the > region size in bytes. Both start address and the size need to be 8-byte > aligned, as a practical simplification (allows using smaller bitmask, > and a smaller granularity isn't really necessary right now). > It will internally add relevant pages to mmio_ro_ranges, but if either > start or end address is not page-aligned, it additionally adds that page > to a list for sub-page R/O handling. The list holds a bitmask which > dwords are supposed to be read-only and an address where page is mapped > for write emulation - this mapping is done only on the first access. A > plain list is used instead of more efficient structure, because there > isn't supposed to be many pages needing this precise r/o control. > > The mechanism this API is plugged in is slightly different for PV and > HVM. For both paths, it's plugged into mmio_ro_emulated_write(). For PV, > it's already called for #PF on read-only MMIO page. For HVM however, EPT > violation on p2m_mmio_direct page results in a direct domain_crash(). > To reach mmio_ro_emulated_write(), change how write violations for > p2m_mmio_direct are handled - specifically, check if they relate to such > partially protected page via subpage_mmio_write_accept() and if so, call > hvm_emulate_one_mmio() for them too. This decodes what guest is trying > write and finally calls mmio_ro_emulated_write(). Note that hitting EPT > write violation for p2m_mmio_direct page can only happen if the page was > on mmio_ro_ranges (see ept_p2m_type_to_flags()), so there is no need for > checking that again. > Both of those paths need an MFN to which guest tried to write (to check > which part of the page is supposed to be read-only, and where > the page is mapped for writes). This information currently isn't > available directly in mmio_ro_emulated_write(), but in both cases it is > already resolved somewhere higher in the call tree. Pass it down to > mmio_ro_emulated_write() via new mmio_ro_emulate_ctxt.mfn field. > > Signed-off-by: Marek Marczykowski-Górecki <marmarek@xxxxxxxxxxxxxxxxxxxxxx> Reviewed-by: Jason Andryuk <jandryuk@xxxxxxxxx> > --- a/xen/arch/x86/include/asm/mm.h > +++ b/xen/arch/x86/include/asm/mm.h > @@ -522,9 +522,24 @@ extern struct rangeset *mmio_ro_ranges; > void memguard_guard_stack(void *p); > void memguard_unguard_stack(void *p); > > +/* > + * Add more precise r/o marking for a MMIO page. Bytes range specified here > + * will still be R/O, but the rest of the page (nor marked as R/O via another s/nor/not/ > + * call) will have writes passed through. > + * The start address and the size must be aligned to SUBPAGE_MMIO_RO_ALIGN. > + * > --- a/xen/arch/x86/mm.c > +++ b/xen/arch/x86/mm.c > + /* > + * We don't know the write seize at this point yet, so it could > be s/seize/size/ > + * an unalligned write, but accept it here anyway and deal with > it s/unalligned/unaligned/ > + * later. > + */ Thanks, Jason
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |