Skip to content

Commit fe41518

Browse files
committed
xen/console: harden hvc_xen against event channel storms
The Xen console driver is still vulnerable for an attack via excessive number of events sent by the backend. Fix that by using a lateeoi event channel. For the normal domU initial console this requires the introduction of bind_evtchn_to_irq_lateeoi() as there is no xenbus device available at the time the event channel is bound to the irq. As the decision whether an interrupt was spurious or not requires to test for bytes having been read from the backend, move sending the event into the if statement, as sending an event without having found any bytes to be read is making no sense at all. This is part of XSA-391 Signed-off-by: Juergen Gross <jgross@suse.com> Reviewed-by: Jan Beulich <jbeulich@suse.com> --- V2: - slightly adapt spurious irq detection (Jan Beulich) V3: - fix spurious irq detection (Jan Beulich)
1 parent b27d479 commit fe41518

3 files changed

Lines changed: 34 additions & 3 deletions

File tree

drivers/tty/hvc/hvc_xen.c

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ struct xencons_info {
3737
struct xenbus_device *xbdev;
3838
struct xencons_interface *intf;
3939
unsigned int evtchn;
40+
XENCONS_RING_IDX out_cons;
41+
unsigned int out_cons_same;
4042
struct hvc_struct *hvc;
4143
int irq;
4244
int vtermno;
@@ -138,6 +140,8 @@ static int domU_read_console(uint32_t vtermno, char *buf, int len)
138140
XENCONS_RING_IDX cons, prod;
139141
int recv = 0;
140142
struct xencons_info *xencons = vtermno_to_xencons(vtermno);
143+
unsigned int eoiflag = 0;
144+
141145
if (xencons == NULL)
142146
return -EINVAL;
143147
intf = xencons->intf;
@@ -157,7 +161,27 @@ static int domU_read_console(uint32_t vtermno, char *buf, int len)
157161
mb(); /* read ring before consuming */
158162
intf->in_cons = cons;
159163

160-
notify_daemon(xencons);
164+
/*
165+
* When to mark interrupt having been spurious:
166+
* - there was no new data to be read, and
167+
* - the backend did not consume some output bytes, and
168+
* - the previous round with no read data didn't see consumed bytes
169+
* (we might have a race with an interrupt being in flight while
170+
* updating xencons->out_cons, so account for that by allowing one
171+
* round without any visible reason)
172+
*/
173+
if (intf->out_cons != xencons->out_cons) {
174+
xencons->out_cons = intf->out_cons;
175+
xencons->out_cons_same = 0;
176+
}
177+
if (recv) {
178+
notify_daemon(xencons);
179+
} else if (xencons->out_cons_same++ > 1) {
180+
eoiflag = XEN_EOI_FLAG_SPURIOUS;
181+
}
182+
183+
xen_irq_lateeoi(xencons->irq, eoiflag);
184+
161185
return recv;
162186
}
163187

@@ -386,7 +410,7 @@ static int xencons_connect_backend(struct xenbus_device *dev,
386410
if (ret)
387411
return ret;
388412
info->evtchn = evtchn;
389-
irq = bind_evtchn_to_irq(evtchn);
413+
irq = bind_interdomain_evtchn_to_irq_lateeoi(dev, evtchn);
390414
if (irq < 0)
391415
return irq;
392416
info->irq = irq;
@@ -551,7 +575,7 @@ static int __init xen_hvc_init(void)
551575
return r;
552576

553577
info = vtermno_to_xencons(HVC_COOKIE);
554-
info->irq = bind_evtchn_to_irq(info->evtchn);
578+
info->irq = bind_evtchn_to_irq_lateeoi(info->evtchn);
555579
}
556580
if (info->irq < 0)
557581
info->irq = 0; /* NO_IRQ */

drivers/xen/events/events_base.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1251,6 +1251,12 @@ int bind_evtchn_to_irq(evtchn_port_t evtchn)
12511251
}
12521252
EXPORT_SYMBOL_GPL(bind_evtchn_to_irq);
12531253

1254+
int bind_evtchn_to_irq_lateeoi(evtchn_port_t evtchn)
1255+
{
1256+
return bind_evtchn_to_irq_chip(evtchn, &xen_lateeoi_chip, NULL);
1257+
}
1258+
EXPORT_SYMBOL_GPL(bind_evtchn_to_irq_lateeoi);
1259+
12541260
static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
12551261
{
12561262
struct evtchn_bind_ipi bind_ipi;

include/xen/events.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ struct xenbus_device;
1717
unsigned xen_evtchn_nr_channels(void);
1818

1919
int bind_evtchn_to_irq(evtchn_port_t evtchn);
20+
int bind_evtchn_to_irq_lateeoi(evtchn_port_t evtchn);
2021
int bind_evtchn_to_irqhandler(evtchn_port_t evtchn,
2122
irq_handler_t handler,
2223
unsigned long irqflags, const char *devname,

0 commit comments

Comments
 (0)