summaryrefslogtreecommitdiffstats
path: root/net-vhost_net-fix-possible-infinite-loop.patch
diff options
context:
space:
mode:
authorJeremy Cline <jcline@redhat.com>2019-05-06 16:48:38 +0000
committerJeremy Cline <jcline@redhat.com>2019-05-07 14:02:01 +0000
commit6f9babcb28ce9b8ecfc1afb612361d26c9ec34a7 (patch)
treeb65513d62661f81b4ca9edbcc33abf0e15c88ab9 /net-vhost_net-fix-possible-infinite-loop.patch
parent2d62e0d70f99987e98fedec648a10a286000eab0 (diff)
downloadkernel-6f9babcb28ce9b8ecfc1afb612361d26c9ec34a7.tar.gz
kernel-6f9babcb28ce9b8ecfc1afb612361d26c9ec34a7.tar.xz
kernel-6f9babcb28ce9b8ecfc1afb612361d26c9ec34a7.zip
Initial v5.1 rebase
Diffstat (limited to 'net-vhost_net-fix-possible-infinite-loop.patch')
-rw-r--r--net-vhost_net-fix-possible-infinite-loop.patch200
1 files changed, 200 insertions, 0 deletions
diff --git a/net-vhost_net-fix-possible-infinite-loop.patch b/net-vhost_net-fix-possible-infinite-loop.patch
new file mode 100644
index 000000000..f45d84bb2
--- /dev/null
+++ b/net-vhost_net-fix-possible-infinite-loop.patch
@@ -0,0 +1,200 @@
+From patchwork Thu Apr 25 07:33:19 2019
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Submitter: Jason Wang <jasowang@redhat.com>
+X-Patchwork-Id: 10916185
+Return-Path: <kvm-owner@kernel.org>
+Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org
+ [172.30.200.125])
+ by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E4F501575
+ for <patchwork-kvm@patchwork.kernel.org>;
+ Thu, 25 Apr 2019 07:33:33 +0000 (UTC)
+Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1])
+ by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D276828BD7
+ for <patchwork-kvm@patchwork.kernel.org>;
+ Thu, 25 Apr 2019 07:33:33 +0000 (UTC)
+Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486)
+ id C64AC28BE1; Thu, 25 Apr 2019 07:33:33 +0000 (UTC)
+X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on
+ pdx-wl-mail.web.codeaurora.org
+X-Spam-Level:
+X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI,
+ RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1
+Received: from vger.kernel.org (vger.kernel.org [209.132.180.67])
+ by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 590B228BD7
+ for <patchwork-kvm@patchwork.kernel.org>;
+ Thu, 25 Apr 2019 07:33:33 +0000 (UTC)
+Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
+ id S1726957AbfDYHd1 (ORCPT
+ <rfc822;patchwork-kvm@patchwork.kernel.org>);
+ Thu, 25 Apr 2019 03:33:27 -0400
+Received: from mx1.redhat.com ([209.132.183.28]:60130 "EHLO mx1.redhat.com"
+ rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP
+ id S1726317AbfDYHd1 (ORCPT <rfc822;kvm@vger.kernel.org>);
+ Thu, 25 Apr 2019 03:33:27 -0400
+Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com
+ [10.5.11.22])
+ (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))
+ (No client certificate requested)
+ by mx1.redhat.com (Postfix) with ESMTPS id C2BCE3002619;
+ Thu, 25 Apr 2019 07:33:26 +0000 (UTC)
+Received: from hp-dl380pg8-02.lab.eng.pek2.redhat.com
+ (hp-dl380pg8-02.lab.eng.pek2.redhat.com [10.73.8.12])
+ by smtp.corp.redhat.com (Postfix) with ESMTP id 5DA021001DDB;
+ Thu, 25 Apr 2019 07:33:21 +0000 (UTC)
+From: Jason Wang <jasowang@redhat.com>
+To: mst@redhat.com, jasowang@redhat.com, kvm@vger.kernel.org,
+ virtualization@lists.linux-foundation.org, netdev@vger.kernel.org,
+ linux-kernel@vger.kernel.org
+Cc: ppandit@redhat.com
+Subject: [PATCH net] vhost_net: fix possible infinite loop
+Date: Thu, 25 Apr 2019 03:33:19 -0400
+Message-Id: <1556177599-56248-1-git-send-email-jasowang@redhat.com>
+X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22
+X-Greylist: Sender IP whitelisted,
+ not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.40]);
+ Thu, 25 Apr 2019 07:33:26 +0000 (UTC)
+Sender: kvm-owner@vger.kernel.org
+Precedence: bulk
+List-ID: <kvm.vger.kernel.org>
+X-Mailing-List: kvm@vger.kernel.org
+X-Virus-Scanned: ClamAV using ClamSMTP
+
+When the rx buffer is too small for a packet, we will discard the vq
+descriptor and retry it for the next packet:
+
+while ((sock_len = vhost_net_rx_peek_head_len(net, sock->sk,
+ &busyloop_intr))) {
+...
+ /* On overrun, truncate and discard */
+ if (unlikely(headcount > UIO_MAXIOV)) {
+ iov_iter_init(&msg.msg_iter, READ, vq->iov, 1, 1);
+ err = sock->ops->recvmsg(sock, &msg,
+ 1, MSG_DONTWAIT | MSG_TRUNC);
+ pr_debug("Discarded rx packet: len %zd\n", sock_len);
+ continue;
+ }
+...
+}
+
+This makes it possible to trigger a infinite while..continue loop
+through the co-opreation of two VMs like:
+
+1) Malicious VM1 allocate 1 byte rx buffer and try to slow down the
+ vhost process as much as possible e.g using indirect descriptors or
+ other.
+2) Malicious VM2 generate packets to VM1 as fast as possible
+
+Fixing this by checking against weight at the end of RX and TX
+loop. This also eliminate other similar cases when:
+
+- userspace is consuming the packets in the meanwhile
+- theoretical TOCTOU attack if guest moving avail index back and forth
+ to hit the continue after vhost find guest just add new buffers
+
+This addresses CVE-2019-3900.
+
+Fixes: d8316f3991d20 ("vhost: fix total length when packets are too short")
+Fixes: 3a4d5c94e9593 ("vhost_net: a kernel-level virtio server")
+Signed-off-by: Jason Wang <jasowang@redhat.com>
+---
+ drivers/vhost/net.c | 41 +++++++++++++++++++++--------------------
+ 1 file changed, 21 insertions(+), 20 deletions(-)
+
+diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
+index df51a35..fb46e6b 100644
+--- a/drivers/vhost/net.c
++++ b/drivers/vhost/net.c
+@@ -778,8 +778,9 @@ static void handle_tx_copy(struct vhost_net *net, struct socket *sock)
+ int err;
+ int sent_pkts = 0;
+ bool sock_can_batch = (sock->sk->sk_sndbuf == INT_MAX);
++ bool next_round = false;
+
+- for (;;) {
++ do {
+ bool busyloop_intr = false;
+
+ if (nvq->done_idx == VHOST_NET_BATCH)
+@@ -845,11 +846,10 @@ static void handle_tx_copy(struct vhost_net *net, struct socket *sock)
+ vq->heads[nvq->done_idx].id = cpu_to_vhost32(vq, head);
+ vq->heads[nvq->done_idx].len = 0;
+ ++nvq->done_idx;
+- if (vhost_exceeds_weight(++sent_pkts, total_len)) {
+- vhost_poll_queue(&vq->poll);
+- break;
+- }
+- }
++ } while (!(next_round = vhost_exceeds_weight(++sent_pkts, total_len)));
++
++ if (next_round)
++ vhost_poll_queue(&vq->poll);
+
+ vhost_tx_batch(net, nvq, sock, &msg);
+ }
+@@ -873,8 +873,9 @@ static void handle_tx_zerocopy(struct vhost_net *net, struct socket *sock)
+ struct vhost_net_ubuf_ref *uninitialized_var(ubufs);
+ bool zcopy_used;
+ int sent_pkts = 0;
++ bool next_round = false;
+
+- for (;;) {
++ do {
+ bool busyloop_intr;
+
+ /* Release DMAs done buffers first */
+@@ -951,11 +952,10 @@ static void handle_tx_zerocopy(struct vhost_net *net, struct socket *sock)
+ else
+ vhost_zerocopy_signal_used(net, vq);
+ vhost_net_tx_packet(net);
+- if (unlikely(vhost_exceeds_weight(++sent_pkts, total_len))) {
+- vhost_poll_queue(&vq->poll);
+- break;
+- }
+- }
++ } while (!(next_round = vhost_exceeds_weight(++sent_pkts, total_len)));
++
++ if (next_round)
++ vhost_poll_queue(&vq->poll);
+ }
+
+ /* Expects to be always run from workqueue - which acts as
+@@ -1134,6 +1134,7 @@ static void handle_rx(struct vhost_net *net)
+ struct iov_iter fixup;
+ __virtio16 num_buffers;
+ int recv_pkts = 0;
++ bool next_round = false;
+
+ mutex_lock_nested(&vq->mutex, VHOST_NET_VQ_RX);
+ sock = vq->private_data;
+@@ -1153,8 +1154,11 @@ static void handle_rx(struct vhost_net *net)
+ vq->log : NULL;
+ mergeable = vhost_has_feature(vq, VIRTIO_NET_F_MRG_RXBUF);
+
+- while ((sock_len = vhost_net_rx_peek_head_len(net, sock->sk,
+- &busyloop_intr))) {
++ do {
++ sock_len = vhost_net_rx_peek_head_len(net, sock->sk,
++ &busyloop_intr);
++ if (!sock_len)
++ break;
+ sock_len += sock_hlen;
+ vhost_len = sock_len + vhost_hlen;
+ headcount = get_rx_bufs(vq, vq->heads + nvq->done_idx,
+@@ -1239,12 +1243,9 @@ static void handle_rx(struct vhost_net *net)
+ vhost_log_write(vq, vq_log, log, vhost_len,
+ vq->iov, in);
+ total_len += vhost_len;
+- if (unlikely(vhost_exceeds_weight(++recv_pkts, total_len))) {
+- vhost_poll_queue(&vq->poll);
+- goto out;
+- }
+- }
+- if (unlikely(busyloop_intr))
++ } while (!(next_round = vhost_exceeds_weight(++recv_pkts, total_len)));
++
++ if (unlikely(busyloop_intr || next_round))
+ vhost_poll_queue(&vq->poll);
+ else
+ vhost_net_enable_vq(net, vq);