Revert "9p: init_in_iov_from_pdu can truncate the size"

This reverts commit 16724a1730.
It causes https://bugs.launchpad.net/bugs/1877688.

Signed-off-by: Stefano Stabellini <stefano.stabellini@xilinx.com>
Reviewed-by: Christian Schoenebeck <qemu_oss@crudebyte.com>
Message-Id: <20200521192627.15259-1-sstabellini@kernel.org>
Signed-off-by: Greg Kurz <groug@kaod.org>
This commit is contained in:
Stefano Stabellini 2020-05-21 12:26:25 -07:00 committed by Greg Kurz
parent ed463454ef
commit cf45183b71
4 changed files with 22 additions and 39 deletions

View File

@ -2103,29 +2103,22 @@ out_nofid:
* with qemu_iovec_destroy(). * with qemu_iovec_destroy().
*/ */
static void v9fs_init_qiov_from_pdu(QEMUIOVector *qiov, V9fsPDU *pdu, static void v9fs_init_qiov_from_pdu(QEMUIOVector *qiov, V9fsPDU *pdu,
size_t skip, size_t *size, size_t skip, size_t size,
bool is_write) bool is_write)
{ {
QEMUIOVector elem; QEMUIOVector elem;
struct iovec *iov; struct iovec *iov;
unsigned int niov; unsigned int niov;
size_t alloc_size = *size + skip;
if (is_write) { if (is_write) {
pdu->s->transport->init_out_iov_from_pdu(pdu, &iov, &niov, alloc_size); 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, &alloc_size); pdu->s->transport->init_in_iov_from_pdu(pdu, &iov, &niov, size + skip);
}
if (alloc_size < skip) {
*size = 0;
} else {
*size = alloc_size - skip;
} }
qemu_iovec_init_external(&elem, iov, niov); qemu_iovec_init_external(&elem, iov, niov);
qemu_iovec_init(qiov, niov); qemu_iovec_init(qiov, niov);
qemu_iovec_concat(qiov, &elem, skip, *size); qemu_iovec_concat(qiov, &elem, skip, size);
} }
static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp, static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
@ -2133,14 +2126,15 @@ static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
{ {
ssize_t err; ssize_t err;
size_t offset = 7; size_t offset = 7;
size_t read_count; uint64_t read_count;
QEMUIOVector qiov_full; QEMUIOVector qiov_full;
if (fidp->fs.xattr.len < off) { if (fidp->fs.xattr.len < off) {
read_count = 0; read_count = 0;
} else if (fidp->fs.xattr.len - off < max_count) {
read_count = fidp->fs.xattr.len - off;
} else { } else {
read_count = fidp->fs.xattr.len - off;
}
if (read_count > max_count) {
read_count = max_count; read_count = max_count;
} }
err = pdu_marshal(pdu, offset, "d", read_count); err = pdu_marshal(pdu, offset, "d", read_count);
@ -2149,7 +2143,7 @@ static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
} }
offset += err; offset += err;
v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset, &read_count, false); v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset, read_count, false);
err = v9fs_pack(qiov_full.iov, qiov_full.niov, 0, err = v9fs_pack(qiov_full.iov, qiov_full.niov, 0,
((char *)fidp->fs.xattr.value) + off, ((char *)fidp->fs.xattr.value) + off,
read_count); read_count);
@ -2278,11 +2272,9 @@ static void coroutine_fn v9fs_read(void *opaque)
QEMUIOVector qiov_full; QEMUIOVector qiov_full;
QEMUIOVector qiov; QEMUIOVector qiov;
int32_t len; int32_t len;
size_t size = max_count;
v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset + 4, &size, false); v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset + 4, max_count, false);
qemu_iovec_init(&qiov, qiov_full.niov); qemu_iovec_init(&qiov, qiov_full.niov);
max_count = size;
do { do {
qemu_iovec_reset(&qiov); qemu_iovec_reset(&qiov);
qemu_iovec_concat(&qiov, &qiov_full, count, qiov_full.size - count); qemu_iovec_concat(&qiov, &qiov_full, count, qiov_full.size - count);
@ -2533,7 +2525,6 @@ static void coroutine_fn v9fs_write(void *opaque)
int32_t len = 0; int32_t len = 0;
int32_t total = 0; int32_t total = 0;
size_t offset = 7; size_t offset = 7;
size_t size;
V9fsFidState *fidp; V9fsFidState *fidp;
V9fsPDU *pdu = opaque; V9fsPDU *pdu = opaque;
V9fsState *s = pdu->s; V9fsState *s = pdu->s;
@ -2546,9 +2537,7 @@ static void coroutine_fn v9fs_write(void *opaque)
return; return;
} }
offset += err; offset += err;
size = count; v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset, count, true);
v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset, &size, true);
count = size;
trace_v9fs_write(pdu->tag, pdu->id, fid, off, count, qiov_full.niov); trace_v9fs_write(pdu->tag, pdu->id, fid, off, count, qiov_full.niov);
fidp = get_fid(pdu, fid); fidp = get_fid(pdu, fid);

View File

@ -436,7 +436,7 @@ struct V9fsTransport {
ssize_t (*pdu_vunmarshal)(V9fsPDU *pdu, size_t offset, const char *fmt, ssize_t (*pdu_vunmarshal)(V9fsPDU *pdu, size_t offset, const char *fmt,
va_list ap); va_list ap);
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, size_t size); unsigned int *pniov, size_t size);
void (*push_and_notify)(V9fsPDU *pdu); void (*push_and_notify)(V9fsPDU *pdu);

View File

@ -147,22 +147,19 @@ static ssize_t virtio_pdu_vunmarshal(V9fsPDU *pdu, size_t offset,
} }
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); size_t buf_size = iov_size(elem->in_sg, elem->in_num);
if (buf_size < P9_IOHDRSZ) { if (buf_size < size) {
VirtIODevice *vdev = VIRTIO_DEVICE(v); VirtIODevice *vdev = VIRTIO_DEVICE(v);
virtio_error(vdev, virtio_error(vdev,
"VirtFS reply type %d needs %zu bytes, buffer has %zu, less than minimum", "VirtFS reply type %d needs %zu bytes, buffer has %zu",
pdu->id + 1, *size, buf_size); pdu->id + 1, size, buf_size);
}
if (buf_size < *size) {
*size = buf_size;
} }
*piov = elem->in_sg; *piov = elem->in_sg;

View File

@ -188,7 +188,7 @@ static void xen_9pfs_init_out_iov_from_pdu(V9fsPDU *pdu,
static void xen_9pfs_init_in_iov_from_pdu(V9fsPDU *pdu, static void xen_9pfs_init_in_iov_from_pdu(V9fsPDU *pdu,
struct iovec **piov, struct iovec **piov,
unsigned int *pniov, unsigned int *pniov,
size_t *size) 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];
@ -198,19 +198,16 @@ static void xen_9pfs_init_in_iov_from_pdu(V9fsPDU *pdu,
g_free(ring->sg); g_free(ring->sg);
ring->sg = g_new0(struct iovec, 2); ring->sg = g_new0(struct iovec, 2);
xen_9pfs_in_sg(ring, ring->sg, &num, pdu->idx, *size); xen_9pfs_in_sg(ring, ring->sg, &num, pdu->idx, size);
buf_size = iov_size(ring->sg, num); buf_size = iov_size(ring->sg, num);
if (buf_size < P9_IOHDRSZ) { if (buf_size < size) {
xen_pv_printf(&xen_9pfs->xendev, 0, "Xen 9pfs reply type %d needs " xen_pv_printf(&xen_9pfs->xendev, 0, "Xen 9pfs request type %d"
"%zu bytes, buffer has %zu, less than minimum\n", "needs %zu bytes, buffer has %zu\n", pdu->id, size,
pdu->id + 1, *size, buf_size); buf_size);
xen_be_set_state(&xen_9pfs->xendev, XenbusStateClosing); xen_be_set_state(&xen_9pfs->xendev, XenbusStateClosing);
xen_9pfs_disconnect(&xen_9pfs->xendev); xen_9pfs_disconnect(&xen_9pfs->xendev);
} }
if (buf_size < *size) {
*size = buf_size;
}
*piov = ring->sg; *piov = ring->sg;
*pniov = num; *pniov = num;