This is an attempt to do a 'post-mortem' on XSA-283, to find out how
the error came about, and consider what changes we could make to code
/ processes to prevent such errors from happening in the future.  The
Security Team hopes to make it a habit to perform such analyses in the
future.

As it happened, there XSA-283 was not a security issue; but this was due
to an accident of the implementation; a change to the implementation may
have become a security issue at any point.

This approach is very much a work in progress; and this is my own work
done without consultation from the rest of the XenProject Security
Team.  Feedback / improvements welcome.

# XSA-283: The issue

Interrupt remapping maps a multi-page datastructure shared between
hardware and the OS.

The datastructrue must be page-aligned, meaning that the lower 12 bits
of the address of the structure would always be 0.  The hardware
register pointing to this (DMAR_IRTRA_REG) uses these "extra" bits to
store other flags.

This address is also stored in a per-iommu-domain data structrue
(struct ir_ctrl->iremap_maddr); but the extra hardware bits were
*also* stored in this data structure, in a way that meant "garbage"
bits were stored in the offset.  It was only an accident of the way
the calculation was handled that avoided this resulting in accesses
past the end of the buffer.

# Archaeology

GET_IREMAP_ENTRY() was introduced by d210b9fc623 in 2009.  This mainly
refactored a number of open-coded versions of the same algorithm which
already existed.

At that point, ir_ctrl->iremap_maddr was already being filled with the
contents of DMAR_IRTA_REG, rather than actually being a machine
address.

Various other changesets affecting lines or-ing in the values:
 cda2f6c7613 2009-09-07 // Just slightly changes condition for calculation
 1e9712f180a 2008-10-17 // Replaces magic constants with macros
 12697426971 2008-04-10 // This is the culprit

Changeset 12697426971, in 2008, changes the structure from holding a
long-term pointer allocated from the xenheap, and adding "extra"
values into a local variable, to holding an maddr allocated from
domheap, and adding "extra" values into the maddr stored in the
structure.

It was posted to xen-devel in a thread starting with message-id
<08df4d958216244799fc84f3514d70f0013cd...@pdsmsx415.ccr.corp.intel.com> .

# Analysis

There was no public review of this patch; the commit contains no R-b
or A-b.  Keir's only comment on the patch before committing it was to
note that it conflicted with a different patch and ask for a rebase.

Fundamentally, both the name of the new structure element
("iremap_maddr") and the name of the local variable it was replacing
("paddr") were wrong.  "addr" should imply *only* an address; to
contain other information it should have been named "ctrl" instead.

Furthermore, map_vtd_domain_page() silently discards non-aligned bits
of addressed passed to it.

# Potential changes that could have prevented this

This could have been caught with a more careful review.

We could consider adding an entry to the style guide speciying that
names based on the word 'address' must *only* be an address, and must
not contain other extraneous information; and if such information
needs to be stored to reflect the contents of a hardware register,
then the name should be based on the word 'register' instead.

If map_vtd_domain_page() ASSERT()ed that addresses passed to it were
page-aligned, then this issue would have been caught probably before
the patch was sent.

A more rigorous change could be to create a special type to store
addresses, with access macros to set or get the address, which would
make it difficult to do this sort of casual or'ing.

# Recommendations

Look into ASSERTing that map_vtd_domain_page() is passed a
page-aligned address.

Consider adding a style recommendation in line with the address /
register discussion above.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

Reply via email to