From patchwork Wed Jun 28 20:44:39 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Greg Kurz X-Patchwork-Id: 781932 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3wyZbC6SK2z9s4q for ; Thu, 29 Jun 2017 06:46:47 +1000 (AEST) Received: from localhost ([::1]:35591 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dQJrJ-0008PD-GJ for incoming@patchwork.ozlabs.org; Wed, 28 Jun 2017 16:46:45 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:40275) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dQJpP-0007Ho-Et for qemu-devel@nongnu.org; Wed, 28 Jun 2017 16:44:48 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dQJpM-0004B5-Aj for qemu-devel@nongnu.org; Wed, 28 Jun 2017 16:44:47 -0400 Received: from 5.mo5.mail-out.ovh.net ([87.98.173.103]:56961) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dQJpM-0004AK-0L for qemu-devel@nongnu.org; Wed, 28 Jun 2017 16:44:44 -0400 Received: from player799.ha.ovh.net (b9.ovh.net [213.186.33.59]) by mo5.mail-out.ovh.net (Postfix) with ESMTP id 89E7910DD66 for ; Wed, 28 Jun 2017 22:44:42 +0200 (CEST) Received: from bahia.lan (gar31-1-82-66-74-139.fbx.proxad.net [82.66.74.139]) (Authenticated sender: groug@kaod.org) by player799.ha.ovh.net (Postfix) with ESMTPA id 3C9C252007A; Wed, 28 Jun 2017 22:44:39 +0200 (CEST) From: Greg Kurz To: qemu-devel@nongnu.org Date: Wed, 28 Jun 2017 22:44:39 +0200 Message-ID: <149868267896.23385.6937506856085271797.stgit@bahia.lan> In-Reply-To: <149868263738.23385.16723444264552987199.stgit@bahia.lan> References: <149868263738.23385.16723444264552987199.stgit@bahia.lan> User-Agent: StGit/0.17.1-20-gc0b1b-dirty MIME-Version: 1.0 X-Ovh-Tracer-Id: 1529535026195241393 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrfeelkedrtddvgdduheeiucetufdoteggodetrfdotffvucfrrhhofhhilhgvmecuqfggjfdpvefjgfevmfevgfenuceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddm X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 87.98.173.103 Subject: [Qemu-devel] [PATCH v5 4/5] xen-9pfs: disconnect if buffers are misconfigured X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Stefano Stabellini , Greg Kurz , "Michael S. Tsirkin" Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" From: Stefano Stabellini 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 Signed-off-by: Greg Kurz --- Changes: - fixed some whitespace damages - xen_9pfs_receive() now returns 0 in case of short read --- hw/9pfs/xen-9p-backend.c | 85 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 64 insertions(+), 21 deletions(-) diff --git a/hw/9pfs/xen-9p-backend.c b/hw/9pfs/xen-9p-backend.c index a82cf817fe45..ee87f08926a2 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; @@ -241,6 +272,9 @@ static int xen_9pfs_receive(Xen9pfsRing *ring) xen_9pfs_read_packet((uint8_t *) &h, ring->ring.out, sizeof(h), masked_prod, &masked_cons, XEN_FLEX_RING_SIZE(ring->ring_order)); + if (queued < le32_to_cpu(h.size_le)) { + return 0; + } /* cannot fail, because we only handle one request per ring at a time */ pdu = pdu_alloc(&ring->priv->state); @@ -269,15 +303,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 +339,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 +471,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,