[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH v4 3/4] virtio-9p: break device if buffers are m
From: |
Stefano Stabellini |
Subject: |
Re: [Qemu-devel] [PATCH v4 3/4] virtio-9p: break device if buffers are misconfigured |
Date: |
Tue, 27 Jun 2017 16:34:51 -0700 (PDT) |
User-agent: |
Alpine 2.10 (DEB 1266 2009-07-14) |
On Tue, 27 Jun 2017, Greg Kurz wrote:
> On Mon, 26 Jun 2017 16:22:23 -0700 (PDT)
> Stefano Stabellini <address@hidden> wrote:
>
> > On Fri, 23 Jun 2017, Greg Kurz wrote:
> > > The 9P protocol is transport agnostic: if the guest misconfigured the
> > > buffers, the best we can do is to set the broken flag on the device.
> > >
> > > Since virtio_pdu_vmarshal() may be called by several active PDUs, we
> > > check if the transport isn't broken already to avoid printing extra
> > > error messages.
> > >
> > > Signed-off-by: Greg Kurz <address@hidden>
> > > ---
> > > v4: - update changelog and add comment to explain why we check
> > > vdev->broken
> > > in virtio_pdu_vmarshal()
> > > - dropped uneeded vdev->broken check in virtio_pdu_vunmarshal()
> > > ---
> > > hw/9pfs/9p.c | 2 +-
> > > hw/9pfs/9p.h | 2 +-
> > > hw/9pfs/virtio-9p-device.c | 48
> > > +++++++++++++++++++++++++++++++++++++++-----
> > > hw/9pfs/xen-9p-backend.c | 3 ++-
> > > 4 files changed, 47 insertions(+), 8 deletions(-)
> > >
> > > diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
> > > index a0ae98f7ca6f..8e5cac71eb60 100644
> > > --- a/hw/9pfs/9p.c
> > > +++ b/hw/9pfs/9p.c
> > > @@ -1664,7 +1664,7 @@ static void v9fs_init_qiov_from_pdu(QEMUIOVector
> > > *qiov, V9fsPDU *pdu,
> > > unsigned int niov;
> > >
> > > if (is_write) {
> > > - pdu->s->transport->init_out_iov_from_pdu(pdu, &iov, &niov);
> > > + pdu->s->transport->init_out_iov_from_pdu(pdu, &iov, &niov, size
> > > + skip);
> > > } else {
> > > pdu->s->transport->init_in_iov_from_pdu(pdu, &iov, &niov, size +
> > > skip);
> > > }
> > > diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h
> > > index aac1b0b2ce3d..d1cfeaf10e4f 100644
> > > --- a/hw/9pfs/9p.h
> > > +++ b/hw/9pfs/9p.h
> > > @@ -363,7 +363,7 @@ struct V9fsTransport {
> > > void (*init_in_iov_from_pdu)(V9fsPDU *pdu, struct iovec
> > > **piov,
> > > unsigned int *pniov, size_t
> > > size);
> > > void (*init_out_iov_from_pdu)(V9fsPDU *pdu, struct iovec
> > > **piov,
> > > - unsigned int *pniov);
> > > + unsigned int *pniov, size_t
> > > size);
> > > void (*push_and_notify)(V9fsPDU *pdu);
> > > };
> > >
> > > diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
> > > index 1a68c1622d3a..ed9e4817a26c 100644
> > > --- a/hw/9pfs/virtio-9p-device.c
> > > +++ b/hw/9pfs/virtio-9p-device.c
> > > @@ -146,8 +146,22 @@ static ssize_t virtio_pdu_vmarshal(V9fsPDU *pdu,
> > > size_t offset,
> > > V9fsState *s = pdu->s;
> > > V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
> > > VirtQueueElement *elem = v->elems[pdu->idx];
> > > -
> > > - return v9fs_iov_vmarshal(elem->in_sg, elem->in_num, offset, 1, fmt,
> > > ap);
> > > + int ret;
> >
> > I think ret should be ssize_t
> >
>
> Yes, you're right. I'll change that.
>
> >
> > > + ret = v9fs_iov_vmarshal(elem->in_sg, elem->in_num, offset, 1, fmt,
> > > ap);
> > > + if (ret < 0) {
> > > + VirtIODevice *vdev = VIRTIO_DEVICE(v);
> > > +
> > > + /* Any active PDU may try to send something back to the client
> > > without
> > > + * knowing if the transport is broken or not. This could result
> > > in
> > > + * MAX_REQ - 1 (ie, 127) extra error messages being printed.
> > > + */
> > > + if (!vdev->broken) {
> > > + virtio_error(vdev, "Failed to encode VirtFS reply type %d",
> > > + pdu->id + 1);
> > > + }
> > > + }
> > > + return ret;
> > > }
> > >
> > > static ssize_t virtio_pdu_vunmarshal(V9fsPDU *pdu, size_t offset,
> > > @@ -156,28 +170,52 @@ static ssize_t virtio_pdu_vunmarshal(V9fsPDU *pdu,
> > > size_t offset,
> > > V9fsState *s = pdu->s;
> > > V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
> > > VirtQueueElement *elem = v->elems[pdu->idx];
> > > + int ret;
> >
> > same here
> >
>
> Ditto.
>
> >
> > > - return v9fs_iov_vunmarshal(elem->out_sg, elem->out_num, offset, 1,
> > > fmt, ap);
> > > + ret = v9fs_iov_vunmarshal(elem->out_sg, elem->out_num, offset, 1,
> > > fmt, ap);
> > > + if (ret < 0) {
> > > + VirtIODevice *vdev = VIRTIO_DEVICE(v);
> > > +
> > > + virtio_error(vdev, "Failed to decode VirtFS request type %d",
> > > pdu->id);
> > > + }
> > > + return ret;
> > > }
> > >
> > > -/* The size parameter is used by other transports. Do not drop it. */
> > > static void virtio_init_in_iov_from_pdu(V9fsPDU *pdu, struct iovec
> > > **piov,
> > > unsigned int *pniov, size_t size)
> > > {
> > > V9fsState *s = pdu->s;
> > > V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
> > > VirtQueueElement *elem = v->elems[pdu->idx];
> > > + size_t buf_size = iov_size(elem->in_sg, elem->in_num);
> > > +
> > > + if (buf_size < size) {
> > > + VirtIODevice *vdev = VIRTIO_DEVICE(v);
> > > +
> > > + virtio_error(vdev,
> > > + "VirtFS reply type %d needs %zu bytes, buffer has
> > > %zu",
> > > + pdu->id + 1, size, buf_size);
> > > + }
> > >
> > > *piov = elem->in_sg;
> > > *pniov = elem->in_num;
> > > }
> > >
> > > static void virtio_init_out_iov_from_pdu(V9fsPDU *pdu, struct iovec
> > > **piov,
> > > - unsigned int *pniov)
> > > + unsigned int *pniov, size_t
> > > size)
> > > {
> > > V9fsState *s = pdu->s;
> > > V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
> > > VirtQueueElement *elem = v->elems[pdu->idx];
> > > + size_t buf_size = iov_size(elem->out_sg, elem->out_num);
> > > +
> > > + if (buf_size < size) {
> > > + VirtIODevice *vdev = VIRTIO_DEVICE(v);
> > > +
> > > + virtio_error(vdev,
> > > + "VirtFS request type %d needs %zu bytes, buffer has
> > > %zu",
> > > + pdu->id, size, buf_size);
> > > + }
> > >
> > > *piov = elem->out_sg;
> > > *pniov = elem->out_num;
> > > diff --git a/hw/9pfs/xen-9p-backend.c b/hw/9pfs/xen-9p-backend.c
> > > index 922cc967be63..a82cf817fe45 100644
> > > --- a/hw/9pfs/xen-9p-backend.c
> > > +++ b/hw/9pfs/xen-9p-backend.c
> > > @@ -147,7 +147,8 @@ static ssize_t xen_9pfs_pdu_vunmarshal(V9fsPDU *pdu,
> > >
> > > static void xen_9pfs_init_out_iov_from_pdu(V9fsPDU *pdu,
> > > struct iovec **piov,
> > > - unsigned int *pniov)
> > > + unsigned int *pniov,
> > > + size_t size)
> > > {
> > > Xen9pfsDev *xen_9pfs = container_of(pdu->s, Xen9pfsDev, state);
> > > Xen9pfsRing *ring = &xen_9pfs->rings[pdu->tag %
> > > xen_9pfs->num_rings];
> >
> > Maybe you could include the same changes you made for xen, see below
> >
>
> Sure, I'd be glad to do so. I just have one concern. In the virtio case, we
> call
> virtio_error() which does two things: print an error message AND set the
> device
> broken flag (no more I/O until device is reset). Is there something similar
> with
> the xen transport ?
No, there isn't anything like that yet. The backend is also missing the
implementation of "disconnect", I think it is the right time to
introduce it. I made enough changes that I think they deserve their own
patch, but I would be happy if you carried it in your series.
---
xen-9pfs: disconnect if buffers are misconfigured
Implement xen_9pfs_disconnect by unbinding the event channels. On
xen_9pfs_free, call disconnect if any event channels haven't been
disconnected.
If the frontend misconfigured the buffers set the backend to "Closing"
and disconnect it. Misconfigurations include requesting a read of more
bytes than available on the ring buffer, or claiming to be writing more
data than available on the ring buffer.
Signed-off-by: Stefano Stabellini <address@hidden>
diff --git a/hw/9pfs/xen-9p-backend.c b/hw/9pfs/xen-9p-backend.c
index a82cf81..8db4703 100644
--- a/hw/9pfs/xen-9p-backend.c
+++ b/hw/9pfs/xen-9p-backend.c
@@ -54,6 +54,8 @@ typedef struct Xen9pfsDev {
Xen9pfsRing *rings;
} Xen9pfsDev;
+static void xen_9pfs_disconnect(struct XenDevice *xendev);
+
static void xen_9pfs_in_sg(Xen9pfsRing *ring,
struct iovec *in_sg,
int *num,
@@ -125,10 +127,19 @@ static ssize_t xen_9pfs_pdu_vmarshal(V9fsPDU *pdu,
Xen9pfsDev *xen_9pfs = container_of(pdu->s, Xen9pfsDev, state);
struct iovec in_sg[2];
int num;
+ ssize_t ret;
xen_9pfs_in_sg(&xen_9pfs->rings[pdu->tag % xen_9pfs->num_rings],
in_sg, &num, pdu->idx, ROUND_UP(offset + 128, 512));
- return v9fs_iov_vmarshal(in_sg, num, offset, 0, fmt, ap);
+
+ ret = v9fs_iov_vmarshal(in_sg, num, offset, 0, fmt, ap);
+ if (ret < 0) {
+ xen_pv_printf(&xen_9pfs->xendev, 0,
+ "Failed to encode VirtFS request type %d\n", pdu->id +
1);
+ xen_be_set_state(&xen_9pfs->xendev, XenbusStateClosing);
+ xen_9pfs_disconnect(&xen_9pfs->xendev);
+ }
+ return ret;
}
static ssize_t xen_9pfs_pdu_vunmarshal(V9fsPDU *pdu,
@@ -139,10 +150,19 @@ static ssize_t xen_9pfs_pdu_vunmarshal(V9fsPDU *pdu,
Xen9pfsDev *xen_9pfs = container_of(pdu->s, Xen9pfsDev, state);
struct iovec out_sg[2];
int num;
+ ssize_t ret;
xen_9pfs_out_sg(&xen_9pfs->rings[pdu->tag % xen_9pfs->num_rings],
out_sg, &num, pdu->idx);
- return v9fs_iov_vunmarshal(out_sg, num, offset, 0, fmt, ap);
+
+ ret = v9fs_iov_vunmarshal(out_sg, num, offset, 0, fmt, ap);
+ if (ret < 0) {
+ xen_pv_printf(&xen_9pfs->xendev, 0,
+ "Failed to decode VirtFS request type %d\n", pdu->id);
+ xen_be_set_state(&xen_9pfs->xendev, XenbusStateClosing);
+ xen_9pfs_disconnect(&xen_9pfs->xendev);
+ }
+ return ret;
}
static void xen_9pfs_init_out_iov_from_pdu(V9fsPDU *pdu,
@@ -170,11 +190,22 @@ static void xen_9pfs_init_in_iov_from_pdu(V9fsPDU *pdu,
Xen9pfsDev *xen_9pfs = container_of(pdu->s, Xen9pfsDev, state);
Xen9pfsRing *ring = &xen_9pfs->rings[pdu->tag % xen_9pfs->num_rings];
int num;
+ size_t buf_size;
g_free(ring->sg);
ring->sg = g_malloc0(sizeof(*ring->sg) * 2);
xen_9pfs_in_sg(ring, ring->sg, &num, pdu->idx, size);
+
+ buf_size = iov_size(ring->sg, num);
+ if (buf_size < size) {
+ xen_pv_printf(&xen_9pfs->xendev, 0, "Xen 9pfs request type %d"
+ "needs %zu bytes, buffer has %zu\n", pdu->id, size,
+ buf_size);
+ xen_be_set_state(&xen_9pfs->xendev, XenbusStateClosing);
+ xen_9pfs_disconnect(&xen_9pfs->xendev);
+ }
+
*piov = ring->sg;
*pniov = num;
}
@@ -218,7 +249,7 @@ static int xen_9pfs_init(struct XenDevice *xendev)
static int xen_9pfs_receive(Xen9pfsRing *ring)
{
P9MsgHeader h;
- RING_IDX cons, prod, masked_prod, masked_cons;
+ RING_IDX cons, prod, masked_prod, masked_cons, queued;
V9fsPDU *pdu;
if (ring->inprogress) {
@@ -229,8 +260,8 @@ static int xen_9pfs_receive(Xen9pfsRing *ring)
prod = ring->intf->out_prod;
xen_rmb();
- if (xen_9pfs_queued(prod, cons, XEN_FLEX_RING_SIZE(ring->ring_order)) <
- sizeof(h)) {
+ queued = xen_9pfs_queued(prod, cons, XEN_FLEX_RING_SIZE(ring->ring_order));
+ if (queued < sizeof(h)) {
return 0;
}
ring->inprogress = true;
@@ -247,6 +278,15 @@ static int xen_9pfs_receive(Xen9pfsRing *ring)
ring->out_size = le32_to_cpu(h.size_le);
ring->out_cons = cons + le32_to_cpu(h.size_le);
+ if (queued < ring->out_size) {
+ xen_pv_printf(&ring->priv->xendev, 0, "Xen 9pfs request type %d"
+ "needs %u bytes, buffer has %u\n", pdu->id, ring->out_size,
+ queued);
+ xen_be_set_state(&ring->priv->xendev, XenbusStateClosing);
+ xen_9pfs_disconnect(&ring->priv->xendev);
+ return -EINVAL;
+ }
+
pdu_submit(pdu, &h);
return 0;
@@ -269,15 +309,30 @@ static void xen_9pfs_evtchn_event(void *opaque)
qemu_bh_schedule(ring->bh);
}
-static int xen_9pfs_free(struct XenDevice *xendev)
+static void xen_9pfs_disconnect(struct XenDevice *xendev)
{
+ Xen9pfsDev *xen_9pdev = container_of(xendev, Xen9pfsDev, xendev);
int i;
+
+ for (i = 0; i < xen_9pdev->num_rings; i++) {
+ if (xen_9pdev->rings[i].evtchndev != NULL) {
+ qemu_set_fd_handler(xenevtchn_fd(xen_9pdev->rings[i].evtchndev),
+ NULL, NULL, NULL);
+ xenevtchn_unbind(xen_9pdev->rings[i].evtchndev,
+ xen_9pdev->rings[i].local_port);
+ xen_9pdev->rings[i].evtchndev = NULL;
+ }
+ }
+}
+
+static int xen_9pfs_free(struct XenDevice *xendev)
+{
Xen9pfsDev *xen_9pdev = container_of(xendev, Xen9pfsDev, xendev);
+ int i;
- g_free(xen_9pdev->id);
- g_free(xen_9pdev->tag);
- g_free(xen_9pdev->path);
- g_free(xen_9pdev->security_model);
+ if (xen_9pdev->rings[0].evtchndev != NULL) {
+ xen_9pfs_disconnect(xendev);
+ }
for (i = 0; i < xen_9pdev->num_rings; i++) {
if (xen_9pdev->rings[i].data != NULL) {
@@ -290,16 +345,15 @@ static int xen_9pfs_free(struct XenDevice *xendev)
xen_9pdev->rings[i].intf,
1);
}
- if (xen_9pdev->rings[i].evtchndev > 0) {
- qemu_set_fd_handler(xenevtchn_fd(xen_9pdev->rings[i].evtchndev),
- NULL, NULL, NULL);
- xenevtchn_unbind(xen_9pdev->rings[i].evtchndev,
- xen_9pdev->rings[i].local_port);
- }
if (xen_9pdev->rings[i].bh != NULL) {
qemu_bh_delete(xen_9pdev->rings[i].bh);
}
}
+
+ g_free(xen_9pdev->id);
+ g_free(xen_9pdev->tag);
+ g_free(xen_9pdev->path);
+ g_free(xen_9pdev->security_model);
g_free(xen_9pdev->rings);
return 0;
}
@@ -423,11 +477,6 @@ static void xen_9pfs_alloc(struct XenDevice *xendev)
xenstore_write_be_int(xendev, "max-ring-page-order", MAX_RING_ORDER);
}
-static void xen_9pfs_disconnect(struct XenDevice *xendev)
-{
- /* Dynamic hotplug of PV filesystems at runtime is not supported. */
-}
-
struct XenDevOps xen_9pfs_ops = {
.size = sizeof(Xen9pfsDev),
.flags = DEVOPS_FLAG_NEED_GNTDEV,
- [Qemu-devel] [PATCH v4 0/4] 9pfs: handle transport errors, Greg Kurz, 2017/06/23
- [Qemu-devel] [PATCH v4 1/4] virtio-9p: record element after sanity checks, Greg Kurz, 2017/06/23
- [Qemu-devel] [PATCH v4 2/4] virtio-9p: message header is 7-byte long, Greg Kurz, 2017/06/23
- [Qemu-devel] [PATCH v4 3/4] virtio-9p: break device if buffers are misconfigured, Greg Kurz, 2017/06/23
- Re: [Qemu-devel] [PATCH v4 3/4] virtio-9p: break device if buffers are misconfigured, Stefano Stabellini, 2017/06/26
- Re: [Qemu-devel] [PATCH v4 3/4] virtio-9p: break device if buffers are misconfigured, Greg Kurz, 2017/06/27
- Re: [Qemu-devel] [PATCH v4 3/4] virtio-9p: break device if buffers are misconfigured,
Stefano Stabellini <=
- Re: [Qemu-devel] [PATCH v4 3/4] virtio-9p: break device if buffers are misconfigured, Greg Kurz, 2017/06/28
- Re: [Qemu-devel] [PATCH v4 3/4] virtio-9p: break device if buffers are misconfigured, Stefano Stabellini, 2017/06/28
- Re: [Qemu-devel] [PATCH v4 3/4] virtio-9p: break device if buffers are misconfigured, Greg Kurz, 2017/06/28
- Re: [Qemu-devel] [PATCH v4 3/4] virtio-9p: break device if buffers are misconfigured, Stefano Stabellini, 2017/06/28
[Qemu-devel] [PATCH v4 4/4] 9pfs: handle transport errors in pdu_complete(), Greg Kurz, 2017/06/23