Skip to content

Commit c346dae

Browse files
jasowangmstsirkin
authored andcommitted
virtio: disable notification hardening by default
We try to harden virtio device notifications in 8b4ec69 ("virtio: harden vring IRQ"). It works with the assumption that the driver or core can properly call virtio_device_ready() at the right place. Unfortunately, this seems to be not true and uncover various bugs of the existing drivers, mainly the issue of using virtio_device_ready() incorrectly. So let's add a Kconfig option and disable it by default. It gives us time to fix the drivers and then we can consider re-enabling it. Signed-off-by: Jason Wang <[email protected]> Message-Id: <[email protected]> Signed-off-by: Michael S. Tsirkin <[email protected]> Reviewed-by: Cornelia Huck <[email protected]>
1 parent 03d9571 commit c346dae

File tree

5 files changed

+37
-1
lines changed

5 files changed

+37
-1
lines changed

drivers/s390/virtio/virtio_ccw.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1136,8 +1136,13 @@ static void virtio_ccw_int_handler(struct ccw_device *cdev,
11361136
vcdev->err = -EIO;
11371137
}
11381138
virtio_ccw_check_activity(vcdev, activity);
1139-
/* Interrupts are disabled here */
1139+
#ifdef CONFIG_VIRTIO_HARDEN_NOTIFICATION
1140+
/*
1141+
* Paired with virtio_ccw_synchronize_cbs() and interrupts are
1142+
* disabled here.
1143+
*/
11401144
read_lock(&vcdev->irq_lock);
1145+
#endif
11411146
for_each_set_bit(i, indicators(vcdev),
11421147
sizeof(*indicators(vcdev)) * BITS_PER_BYTE) {
11431148
/* The bit clear must happen before the vring kick. */
@@ -1146,7 +1151,9 @@ static void virtio_ccw_int_handler(struct ccw_device *cdev,
11461151
vq = virtio_ccw_vq_by_ind(vcdev, i);
11471152
vring_interrupt(0, vq);
11481153
}
1154+
#ifdef CONFIG_VIRTIO_HARDEN_NOTIFICATION
11491155
read_unlock(&vcdev->irq_lock);
1156+
#endif
11501157
if (test_bit(0, indicators2(vcdev))) {
11511158
virtio_config_changed(&vcdev->vdev);
11521159
clear_bit(0, indicators2(vcdev));

drivers/virtio/Kconfig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,19 @@ menuconfig VIRTIO_MENU
2929

3030
if VIRTIO_MENU
3131

32+
config VIRTIO_HARDEN_NOTIFICATION
33+
bool "Harden virtio notification"
34+
help
35+
Enable this to harden the device notifications and suppress
36+
those that happen at a time where notifications are illegal.
37+
38+
Experimental: Note that several drivers still have bugs that
39+
may cause crashes or hangs when correct handling of
40+
notifications is enforced; depending on the subset of
41+
drivers and devices you use, this may or may not work.
42+
43+
If unsure, say N.
44+
3245
config VIRTIO_PCI
3346
tristate "PCI driver for virtio devices"
3447
depends on PCI

drivers/virtio/virtio.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ static int virtio_features_ok(struct virtio_device *dev)
219219
* */
220220
void virtio_reset_device(struct virtio_device *dev)
221221
{
222+
#ifdef CONFIG_VIRTIO_HARDEN_NOTIFICATION
222223
/*
223224
* The below virtio_synchronize_cbs() guarantees that any
224225
* interrupt for this line arriving after
@@ -227,6 +228,7 @@ void virtio_reset_device(struct virtio_device *dev)
227228
*/
228229
virtio_break_device(dev);
229230
virtio_synchronize_cbs(dev);
231+
#endif
230232

231233
dev->config->reset(dev);
232234
}

drivers/virtio/virtio_ring.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1708,7 +1708,11 @@ static struct virtqueue *vring_create_virtqueue_packed(
17081708
vq->we_own_ring = true;
17091709
vq->notify = notify;
17101710
vq->weak_barriers = weak_barriers;
1711+
#ifdef CONFIG_VIRTIO_HARDEN_NOTIFICATION
17111712
vq->broken = true;
1713+
#else
1714+
vq->broken = false;
1715+
#endif
17121716
vq->last_used_idx = 0 | (1 << VRING_PACKED_EVENT_F_WRAP_CTR);
17131717
vq->event_triggered = false;
17141718
vq->num_added = 0;
@@ -2154,9 +2158,13 @@ irqreturn_t vring_interrupt(int irq, void *_vq)
21542158
}
21552159

21562160
if (unlikely(vq->broken)) {
2161+
#ifdef CONFIG_VIRTIO_HARDEN_NOTIFICATION
21572162
dev_warn_once(&vq->vq.vdev->dev,
21582163
"virtio vring IRQ raised before DRIVER_OK");
21592164
return IRQ_NONE;
2165+
#else
2166+
return IRQ_HANDLED;
2167+
#endif
21602168
}
21612169

21622170
/* Just a hint for performance: so it's ok that this can be racy! */
@@ -2199,7 +2207,11 @@ struct virtqueue *__vring_new_virtqueue(unsigned int index,
21992207
vq->we_own_ring = false;
22002208
vq->notify = notify;
22012209
vq->weak_barriers = weak_barriers;
2210+
#ifdef CONFIG_VIRTIO_HARDEN_NOTIFICATION
22022211
vq->broken = true;
2212+
#else
2213+
vq->broken = false;
2214+
#endif
22032215
vq->last_used_idx = 0;
22042216
vq->event_triggered = false;
22052217
vq->num_added = 0;

include/linux/virtio_config.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,13 +257,15 @@ void virtio_device_ready(struct virtio_device *dev)
257257

258258
WARN_ON(status & VIRTIO_CONFIG_S_DRIVER_OK);
259259

260+
#ifdef CONFIG_VIRTIO_HARDEN_NOTIFICATION
260261
/*
261262
* The virtio_synchronize_cbs() makes sure vring_interrupt()
262263
* will see the driver specific setup if it sees vq->broken
263264
* as false (even if the notifications come before DRIVER_OK).
264265
*/
265266
virtio_synchronize_cbs(dev);
266267
__virtio_unbreak_device(dev);
268+
#endif
267269
/*
268270
* The transport should ensure the visibility of vq->broken
269271
* before setting DRIVER_OK. See the comments for the transport

0 commit comments

Comments
 (0)