mirror of https://github.com/xemu-project/xemu.git
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: Greg Kurz <groug@kaod.org>
This commit is contained in:
parent
a4d9985450
commit
8d37de41ca
|
@ -1664,7 +1664,7 @@ static void v9fs_init_qiov_from_pdu(QEMUIOVector *qiov, V9fsPDU *pdu,
|
||||||
unsigned int niov;
|
unsigned int niov;
|
||||||
|
|
||||||
if (is_write) {
|
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 {
|
} else {
|
||||||
pdu->s->transport->init_in_iov_from_pdu(pdu, &iov, &niov, size + skip);
|
pdu->s->transport->init_in_iov_from_pdu(pdu, &iov, &niov, size + skip);
|
||||||
}
|
}
|
||||||
|
|
|
@ -363,7 +363,7 @@ struct V9fsTransport {
|
||||||
void (*init_in_iov_from_pdu)(V9fsPDU *pdu, struct iovec **piov,
|
void (*init_in_iov_from_pdu)(V9fsPDU *pdu, struct iovec **piov,
|
||||||
unsigned int *pniov, size_t size);
|
unsigned int *pniov, size_t size);
|
||||||
void (*init_out_iov_from_pdu)(V9fsPDU *pdu, struct iovec **piov,
|
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);
|
void (*push_and_notify)(V9fsPDU *pdu);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -146,8 +146,16 @@ static ssize_t virtio_pdu_vmarshal(V9fsPDU *pdu, size_t offset,
|
||||||
V9fsState *s = pdu->s;
|
V9fsState *s = pdu->s;
|
||||||
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
|
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
|
||||||
VirtQueueElement *elem = v->elems[pdu->idx];
|
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,
|
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;
|
V9fsState *s = pdu->s;
|
||||||
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
|
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
|
||||||
VirtQueueElement *elem = v->elems[pdu->idx];
|
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,
|
static void virtio_init_in_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov,
|
||||||
unsigned int *pniov, size_t size)
|
unsigned int *pniov, size_t size)
|
||||||
{
|
{
|
||||||
V9fsState *s = pdu->s;
|
V9fsState *s = pdu->s;
|
||||||
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
|
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
|
||||||
VirtQueueElement *elem = v->elems[pdu->idx];
|
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;
|
*piov = elem->in_sg;
|
||||||
*pniov = elem->in_num;
|
*pniov = elem->in_num;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void virtio_init_out_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov,
|
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;
|
V9fsState *s = pdu->s;
|
||||||
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
|
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
|
||||||
VirtQueueElement *elem = v->elems[pdu->idx];
|
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;
|
*piov = elem->out_sg;
|
||||||
*pniov = elem->out_num;
|
*pniov = elem->out_num;
|
||||||
|
|
|
@ -147,7 +147,8 @@ static ssize_t xen_9pfs_pdu_vunmarshal(V9fsPDU *pdu,
|
||||||
|
|
||||||
static void xen_9pfs_init_out_iov_from_pdu(V9fsPDU *pdu,
|
static void xen_9pfs_init_out_iov_from_pdu(V9fsPDU *pdu,
|
||||||
struct iovec **piov,
|
struct iovec **piov,
|
||||||
unsigned int *pniov)
|
unsigned int *pniov,
|
||||||
|
size_t size)
|
||||||
{
|
{
|
||||||
Xen9pfsDev *xen_9pfs = container_of(pdu->s, Xen9pfsDev, state);
|
Xen9pfsDev *xen_9pfs = container_of(pdu->s, Xen9pfsDev, state);
|
||||||
Xen9pfsRing *ring = &xen_9pfs->rings[pdu->tag % xen_9pfs->num_rings];
|
Xen9pfsRing *ring = &xen_9pfs->rings[pdu->tag % xen_9pfs->num_rings];
|
||||||
|
|
Loading…
Reference in New Issue