From patchwork Fri Jun 27 08:34:38 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Dr. David Alan Gilbert" X-Patchwork-Id: 364825 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 0D2041400D2 for ; Fri, 27 Jun 2014 18:35:25 +1000 (EST) Received: from localhost ([::1]:48667 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1X0Rcx-0001zl-7i for incoming@patchwork.ozlabs.org; Fri, 27 Jun 2014 04:35:23 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:60523) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1X0RcP-0001AK-2U for qemu-devel@nongnu.org; Fri, 27 Jun 2014 04:34:55 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1X0RcI-0001Gn-Ui for qemu-devel@nongnu.org; Fri, 27 Jun 2014 04:34:49 -0400 Received: from mx1.redhat.com ([209.132.183.28]:19019) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1X0RcI-0001GW-NR for qemu-devel@nongnu.org; Fri, 27 Jun 2014 04:34:42 -0400 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id s5R8Yfa7011520 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Fri, 27 Jun 2014 04:34:41 -0400 Received: from dgilbert-t530.home.treblig.org (vpn1-7-230.ams2.redhat.com [10.36.7.230]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id s5R8Ydst014590; Fri, 27 Jun 2014 04:34:39 -0400 From: "Dr. David Alan Gilbert (git)" To: qemu-devel@nongnu.org Date: Fri, 27 Jun 2014 09:34:38 +0100 Message-Id: <1403858078-3402-1-git-send-email-dgilbert@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.26 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: pbonzini@redhat.com, quintela@redhat.com, mst@redhat.com Subject: [Qemu-devel] [PATCH] Allow mismatched virtio config-len X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: "Dr. David Alan Gilbert" Commit 'virtio: validate config_len on load' restricted config_len loaded from the wire to match the config_len that the device had. Unfortunately, there are cases where this isn't true, the one we found it on was the wqe addition in virtio-blk. Allow mismatched config-lengths: *) If the version on the wire is shorter then ensure that the remainder is 0xff filled (as virtio_config_read does on out of range reads) *) If the version on the wire is longer, load what we have space for and skip the rest. Signed-off-by: Dr. David Alan Gilbert --- hw/virtio/virtio.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index a3082d5..2b11142 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -927,11 +927,33 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f) } config_len = qemu_get_be32(f); if (config_len != vdev->config_len) { - error_report("Unexpected config length 0x%x. Expected 0x%zx", - config_len, vdev->config_len); - return -1; + /* + * Unfortunately the reality is that there are cases where we + * see mismatched config lengths, so we have to deal with them + * rather than rejecting them. + */ + + if (config_len < vdev->config_len) { + /* This is normal in some devices when they add a new option */ + memset(vdev->config, 0xff, vdev->config_len); + qemu_get_buffer(f, vdev->config, config_len); + } else { + int32_t diff; + /* config_len > vdev->config_len + * This is rarer, but is here to allow us to fix the case above + */ + qemu_get_buffer(f, vdev->config, vdev->config_len); + /* + * Even though we expect the diff to be small, we can't use + * qemu_file_skip because it's not safe for a large skip. + */ + for (diff = config_len - vdev->config_len; diff > 0; diff--) { + qemu_get_byte(f); + } + } + } else { + qemu_get_buffer(f, vdev->config, vdev->config_len); } - qemu_get_buffer(f, vdev->config, vdev->config_len); num = qemu_get_be32(f);