xen/intr: add check for intr_register_source() errors

While unusual, intr_register_source() can return failure.  A likely
cause might be another device grabbing from Xen's interrupt range.
This should NOT happen, but could happen due to a bug.  As such check
for this and fail if it occurs.

This theoretical situation also effects xen_intr_find_unused_isrc().
There, .is_pic must be tested to ensure such an intrusion doesn't cause
misbehavior.

Reviewed by: royger
MFC after: 1 week
Differential Revision: https://reviews.freebsd.org/D31995
This commit is contained in:
Elliott Mitchell 2021-09-12 23:12:08 -07:00 committed by Oscar Zhao
parent 4f83064b94
commit 6ef0026d97

View File

@ -285,8 +285,16 @@ xen_intr_find_unused_isrc(enum evtchn_type type)
vector = first_evtchn_irq + isrc_idx;
isrc = (struct xenisrc *)intr_lookup_source(vector);
if (isrc != NULL
&& isrc->xi_type == EVTCHN_TYPE_UNBOUND) {
/*
* Since intr_register_source() must be called while unlocked,
* isrc == NULL *will* occur, though very infrequently.
*
* This also allows a very small gap where a foreign intrusion
* into Xen's interrupt range could be examined by this test.
*/
if (__predict_true(isrc != NULL) &&
__predict_true(isrc->xi_intsrc.is_pic == &xen_intr_pic) &&
isrc->xi_type == EVTCHN_TYPE_UNBOUND) {
KASSERT(isrc->xi_intsrc.is_handlers == 0,
("Free evtchn still has handlers"));
isrc->xi_type = type;
@ -310,6 +318,7 @@ xen_intr_alloc_isrc(enum evtchn_type type)
static int warned;
struct xenisrc *isrc;
unsigned int vector;
int error;
KASSERT(mtx_owned(&xen_intr_isrc_lock), ("Evtchn alloc lock not held"));
@ -332,7 +341,10 @@ xen_intr_alloc_isrc(enum evtchn_type type)
isrc->xi_intsrc.is_pic = &xen_intr_pic;
isrc->xi_vector = vector;
isrc->xi_type = type;
intr_register_source(&isrc->xi_intsrc);
error = intr_register_source(&isrc->xi_intsrc);
if (error != 0)
panic("%s(): failed registering interrupt %u, error=%d\n",
__func__, vector, error);
mtx_lock(&xen_intr_isrc_lock);
return (isrc);