Commit 8d37de41 authored by Greg Kurz's avatar Greg Kurz
Browse files

virtio-9p: break device if buffers are misconfigured



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.

Signed-off-by: default avatarGreg Kurz <groug@kaod.org>
parent a4d99854
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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);
    }
+1 −1
Original line number Diff line number Diff line
@@ -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);
};

+36 −4
Original line number Diff line number Diff line
@@ -146,8 +146,16 @@ 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];
    ssize_t ret;

    return v9fs_iov_vmarshal(elem->in_sg, elem->in_num, offset, 1, fmt, ap);
    ret = v9fs_iov_vmarshal(elem->in_sg, elem->in_num, offset, 1, fmt, ap);
    if (ret < 0) {
        VirtIODevice *vdev = VIRTIO_DEVICE(v);

        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 +164,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];
    ssize_t ret;

    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;
+2 −1
Original line number Diff line number Diff line
@@ -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];