Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 44a455e0 authored by Juergen Gross's avatar Juergen Gross Committed by Greg Kroah-Hartman
Browse files

xen/events: fix race in evtchn_fifo_unmask()



commit f01337197419b7e8a492e83089552b77d3b5fb90 upstream.

Unmasking a fifo event channel can result in unmasking it twice, once
directly in the kernel and once via a hypercall in case the event was
pending.

Fix that by doing the local unmask only if the event is not pending.

This is part of XSA-332.

Cc: stable@vger.kernel.org
Signed-off-by: default avatarJuergen Gross <jgross@suse.com>
Reviewed-by: default avatarJan Beulich <jbeulich@suse.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 4bea575a
Loading
Loading
Loading
Loading
+9 −4
Original line number Diff line number Diff line
@@ -227,19 +227,25 @@ static bool evtchn_fifo_is_masked(unsigned port)
	return sync_test_bit(EVTCHN_FIFO_BIT(MASKED, word), BM(word));
}
/*
 * Clear MASKED, spinning if BUSY is set.
 * Clear MASKED if not PENDING, spinning if BUSY is set.
 * Return true if mask was cleared.
 */
static void clear_masked(volatile event_word_t *word)
static bool clear_masked_cond(volatile event_word_t *word)
{
	event_word_t new, old, w;

	w = *word;

	do {
		if (w & (1 << EVTCHN_FIFO_PENDING))
			return false;

		old = w & ~(1 << EVTCHN_FIFO_BUSY);
		new = old & ~(1 << EVTCHN_FIFO_MASKED);
		w = sync_cmpxchg(word, old, new);
	} while (w != old);

	return true;
}

static void evtchn_fifo_unmask(unsigned port)
@@ -248,8 +254,7 @@ static void evtchn_fifo_unmask(unsigned port)

	BUG_ON(!irqs_disabled());

	clear_masked(word);
	if (evtchn_fifo_is_pending(port)) {
	if (!clear_masked_cond(word)) {
		struct evtchn_unmask unmask = { .port = port };
		(void)HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &unmask);
	}