summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Wellving <andreas.wellving@enea.com>2019-02-04 14:05:29 +0100
committerAndreas Wellving <andreas.wellving@enea.com>2019-02-04 14:05:29 +0100
commit4122d7341425209be538c71dffed6043659d683b (patch)
tree94b45930f1aee97ffde5967f119737bc616fd06b
parentb6643e162871f2c81cc342f510ac9bd35e7744bd (diff)
downloadenea-kernel-cache-4122d7341425209be538c71dffed6043659d683b.tar.gz
vhost/vsock: CVE-2018-14625
vhost/vsock: fix use-after-free in network stack callers References: https://nvd.nist.gov/vuln/detail/CVE-2018-14625 https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=linux-4.14.y&id=f15c072d6576c5e2b693c22e39ccc9103c952078 Change-Id: Ica09a6a909b9276f3d8ba1d0980e2e6473d461d7 Signed-off-by: Andreas Wellving <andreas.wellving@enea.com>
-rw-r--r--patches/cve/4.14.x.scc3
-rw-r--r--patches/cve/CVE-2018-14625-vhost-vsock-fix-use-after-free-in-network-stack-call.patch199
2 files changed, 202 insertions, 0 deletions
diff --git a/patches/cve/4.14.x.scc b/patches/cve/4.14.x.scc
index 59a57b6..e1a218f 100644
--- a/patches/cve/4.14.x.scc
+++ b/patches/cve/4.14.x.scc
@@ -13,3 +13,6 @@ patch CVE-2018-18690-xfs-don-t-fail-when-converting-shortform-attr-to-lon.patch
13patch CVE-2018-19407-KVM-X86-Fix-scan-ioapic-use-before-initialization.patch 13patch CVE-2018-19407-KVM-X86-Fix-scan-ioapic-use-before-initialization.patch
14#CVEs fixed in 4.14.87: 14#CVEs fixed in 4.14.87:
15patch CVE-2018-18397-userfaultfd-use-ENOENT-instead-of-EFAULT-if-the-atom.patch 15patch CVE-2018-18397-userfaultfd-use-ENOENT-instead-of-EFAULT-if-the-atom.patch
16#CVEs fixed in 4.14.88:
17patch CVE-2018-14625-vhost-vsock-fix-use-after-free-in-network-stack-call.patch
18
diff --git a/patches/cve/CVE-2018-14625-vhost-vsock-fix-use-after-free-in-network-stack-call.patch b/patches/cve/CVE-2018-14625-vhost-vsock-fix-use-after-free-in-network-stack-call.patch
new file mode 100644
index 0000000..d51b3c8
--- /dev/null
+++ b/patches/cve/CVE-2018-14625-vhost-vsock-fix-use-after-free-in-network-stack-call.patch
@@ -0,0 +1,199 @@
1From f15c072d6576c5e2b693c22e39ccc9103c952078 Mon Sep 17 00:00:00 2001
2From: Stefan Hajnoczi <stefanha@redhat.com>
3Date: Mon, 5 Nov 2018 10:35:47 +0000
4Subject: [PATCH] vhost/vsock: fix use-after-free in network stack callers
5
6commit 834e772c8db0c6a275d75315d90aba4ebbb1e249 upstream.
7
8If the network stack calls .send_pkt()/.cancel_pkt() during .release(),
9a struct vhost_vsock use-after-free is possible. This occurs because
10.release() does not wait for other CPUs to stop using struct
11vhost_vsock.
12
13Switch to an RCU-enabled hashtable (indexed by guest CID) so that
14.release() can wait for other CPUs by calling synchronize_rcu(). This
15also eliminates vhost_vsock_lock acquisition in the data path so it
16could have a positive effect on performance.
17
18This is CVE-2018-14625 "kernel: use-after-free Read in vhost_transport_send_pkt".
19
20CVE: CVE-2018-14625
21Upstream-Status: Backport
22
23Cc: stable@vger.kernel.org
24Reported-and-tested-by: syzbot+bd391451452fb0b93039@syzkaller.appspotmail.com
25Reported-by: syzbot+e3e074963495f92a89ed@syzkaller.appspotmail.com
26Reported-by: syzbot+d5a0a170c5069658b141@syzkaller.appspotmail.com
27Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
28Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
29Acked-by: Jason Wang <jasowang@redhat.com>
30Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
31Signed-off-by: Andreas Wellving <andreas.wellving@enea.com>
32---
33 drivers/vhost/vsock.c | 57 +++++++++++++++++++++++++------------------
34 1 file changed, 33 insertions(+), 24 deletions(-)
35
36diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c
37index c9de9c41aa97..b044a0800805 100644
38--- a/drivers/vhost/vsock.c
39+++ b/drivers/vhost/vsock.c
40@@ -15,6 +15,7 @@
41 #include <net/sock.h>
42 #include <linux/virtio_vsock.h>
43 #include <linux/vhost.h>
44+#include <linux/hashtable.h>
45
46 #include <net/af_vsock.h>
47 #include "vhost.h"
48@@ -27,14 +28,14 @@ enum {
49
50 /* Used to track all the vhost_vsock instances on the system. */
51 static DEFINE_SPINLOCK(vhost_vsock_lock);
52-static LIST_HEAD(vhost_vsock_list);
53+static DEFINE_READ_MOSTLY_HASHTABLE(vhost_vsock_hash, 8);
54
55 struct vhost_vsock {
56 struct vhost_dev dev;
57 struct vhost_virtqueue vqs[2];
58
59- /* Link to global vhost_vsock_list, protected by vhost_vsock_lock */
60- struct list_head list;
61+ /* Link to global vhost_vsock_hash, writes use vhost_vsock_lock */
62+ struct hlist_node hash;
63
64 struct vhost_work send_pkt_work;
65 spinlock_t send_pkt_list_lock;
66@@ -50,11 +51,14 @@ static u32 vhost_transport_get_local_cid(void)
67 return VHOST_VSOCK_DEFAULT_HOST_CID;
68 }
69
70-static struct vhost_vsock *__vhost_vsock_get(u32 guest_cid)
71+/* Callers that dereference the return value must hold vhost_vsock_lock or the
72+ * RCU read lock.
73+ */
74+static struct vhost_vsock *vhost_vsock_get(u32 guest_cid)
75 {
76 struct vhost_vsock *vsock;
77
78- list_for_each_entry(vsock, &vhost_vsock_list, list) {
79+ hash_for_each_possible_rcu(vhost_vsock_hash, vsock, hash, guest_cid) {
80 u32 other_cid = vsock->guest_cid;
81
82 /* Skip instances that have no CID yet */
83@@ -69,17 +73,6 @@ static struct vhost_vsock *__vhost_vsock_get(u32 guest_cid)
84 return NULL;
85 }
86
87-static struct vhost_vsock *vhost_vsock_get(u32 guest_cid)
88-{
89- struct vhost_vsock *vsock;
90-
91- spin_lock_bh(&vhost_vsock_lock);
92- vsock = __vhost_vsock_get(guest_cid);
93- spin_unlock_bh(&vhost_vsock_lock);
94-
95- return vsock;
96-}
97-
98 static void
99 vhost_transport_do_send_pkt(struct vhost_vsock *vsock,
100 struct vhost_virtqueue *vq)
101@@ -210,9 +203,12 @@ vhost_transport_send_pkt(struct virtio_vsock_pkt *pkt)
102 struct vhost_vsock *vsock;
103 int len = pkt->len;
104
105+ rcu_read_lock();
106+
107 /* Find the vhost_vsock according to guest context id */
108 vsock = vhost_vsock_get(le64_to_cpu(pkt->hdr.dst_cid));
109 if (!vsock) {
110+ rcu_read_unlock();
111 virtio_transport_free_pkt(pkt);
112 return -ENODEV;
113 }
114@@ -225,6 +221,8 @@ vhost_transport_send_pkt(struct virtio_vsock_pkt *pkt)
115 spin_unlock_bh(&vsock->send_pkt_list_lock);
116
117 vhost_work_queue(&vsock->dev, &vsock->send_pkt_work);
118+
119+ rcu_read_unlock();
120 return len;
121 }
122
123@@ -234,12 +232,15 @@ vhost_transport_cancel_pkt(struct vsock_sock *vsk)
124 struct vhost_vsock *vsock;
125 struct virtio_vsock_pkt *pkt, *n;
126 int cnt = 0;
127+ int ret = -ENODEV;
128 LIST_HEAD(freeme);
129
130+ rcu_read_lock();
131+
132 /* Find the vhost_vsock according to guest context id */
133 vsock = vhost_vsock_get(vsk->remote_addr.svm_cid);
134 if (!vsock)
135- return -ENODEV;
136+ goto out;
137
138 spin_lock_bh(&vsock->send_pkt_list_lock);
139 list_for_each_entry_safe(pkt, n, &vsock->send_pkt_list, list) {
140@@ -265,7 +266,10 @@ vhost_transport_cancel_pkt(struct vsock_sock *vsk)
141 vhost_poll_queue(&tx_vq->poll);
142 }
143
144- return 0;
145+ ret = 0;
146+out:
147+ rcu_read_unlock();
148+ return ret;
149 }
150
151 static struct virtio_vsock_pkt *
152@@ -531,10 +535,6 @@ static int vhost_vsock_dev_open(struct inode *inode, struct file *file)
153 spin_lock_init(&vsock->send_pkt_list_lock);
154 INIT_LIST_HEAD(&vsock->send_pkt_list);
155 vhost_work_init(&vsock->send_pkt_work, vhost_transport_send_pkt_work);
156-
157- spin_lock_bh(&vhost_vsock_lock);
158- list_add_tail(&vsock->list, &vhost_vsock_list);
159- spin_unlock_bh(&vhost_vsock_lock);
160 return 0;
161
162 out:
163@@ -575,9 +575,13 @@ static int vhost_vsock_dev_release(struct inode *inode, struct file *file)
164 struct vhost_vsock *vsock = file->private_data;
165
166 spin_lock_bh(&vhost_vsock_lock);
167- list_del(&vsock->list);
168+ if (vsock->guest_cid)
169+ hash_del_rcu(&vsock->hash);
170 spin_unlock_bh(&vhost_vsock_lock);
171
172+ /* Wait for other CPUs to finish using vsock */
173+ synchronize_rcu();
174+
175 /* Iterating over all connections for all CIDs to find orphans is
176 * inefficient. Room for improvement here. */
177 vsock_for_each_connected_socket(vhost_vsock_reset_orphans);
178@@ -618,12 +622,17 @@ static int vhost_vsock_set_cid(struct vhost_vsock *vsock, u64 guest_cid)
179
180 /* Refuse if CID is already in use */
181 spin_lock_bh(&vhost_vsock_lock);
182- other = __vhost_vsock_get(guest_cid);
183+ other = vhost_vsock_get(guest_cid);
184 if (other && other != vsock) {
185 spin_unlock_bh(&vhost_vsock_lock);
186 return -EADDRINUSE;
187 }
188+
189+ if (vsock->guest_cid)
190+ hash_del_rcu(&vsock->hash);
191+
192 vsock->guest_cid = guest_cid;
193+ hash_add_rcu(vhost_vsock_hash, &vsock->hash, guest_cid);
194 spin_unlock_bh(&vhost_vsock_lock);
195
196 return 0;
197--
1982.19.2
199