Bug Summary

File:hw/virtio/dataplane/vring.c
Location:line 400, column 5
Description:The left operand of '<' is a garbage value

Annotated Source Code

1/* Copyright 2012 Red Hat, Inc.
2 * Copyright IBM, Corp. 2012
3 *
4 * Based on Linux 2.6.39 vhost code:
5 * Copyright (C) 2009 Red Hat, Inc.
6 * Copyright (C) 2006 Rusty Russell IBM Corporation
7 *
8 * Author: Michael S. Tsirkin <mst@redhat.com>
9 * Stefan Hajnoczi <stefanha@redhat.com>
10 *
11 * Inspiration, some code, and most witty comments come from
12 * Documentation/virtual/lguest/lguest.c, by Rusty Russell
13 *
14 * This work is licensed under the terms of the GNU GPL, version 2.
15 */
16
17#include "trace.h"
18#include "hw/hw.h"
19#include "exec/memory.h"
20#include "exec/address-spaces.h"
21#include "hw/virtio/dataplane/vring.h"
22#include "qemu/error-report.h"
23
24/* vring_map can be coupled with vring_unmap or (if you still have the
25 * value returned in *mr) memory_region_unref.
26 */
27static void *vring_map(MemoryRegion **mr, hwaddr phys, hwaddr len,
28 bool_Bool is_write)
29{
30 MemoryRegionSection section = memory_region_find(get_system_memory(), phys, len);
31
32 if (!section.mr || int128_get64(section.size) < len) {
33 goto out;
34 }
35 if (is_write && section.readonly) {
36 goto out;
37 }
38 if (!memory_region_is_ram(section.mr)) {
39 goto out;
40 }
41
42 /* Ignore regions with dirty logging, we cannot mark them dirty */
43 if (memory_region_is_logging(section.mr)) {
44 goto out;
45 }
46
47 *mr = section.mr;
48 return memory_region_get_ram_ptr(section.mr) + section.offset_within_region;
49
50out:
51 memory_region_unref(section.mr);
52 *mr = NULL((void*)0);
53 return NULL((void*)0);
54}
55
56static void vring_unmap(void *buffer, bool_Bool is_write)
57{
58 ram_addr_t addr;
59 MemoryRegion *mr;
60
61 mr = qemu_ram_addr_from_host(buffer, &addr);
62 memory_region_unref(mr);
63}
64
65/* Map the guest's vring to host memory */
66bool_Bool vring_setup(Vring *vring, VirtIODevice *vdev, int n)
67{
68 hwaddr vring_addr = virtio_queue_get_ring_addr(vdev, n);
69 hwaddr vring_size = virtio_queue_get_ring_size(vdev, n);
70 void *vring_ptr;
71
72 vring->broken = false0;
73
74 vring_ptr = vring_map(&vring->mr, vring_addr, vring_size, true1);
75 if (!vring_ptr) {
76 error_report("Failed to map vring "
77 "addr %#" HWADDR_PRIx"l" "x" " size %" HWADDR_PRIu"l" "u",
78 vring_addr, vring_size);
79 vring->broken = true1;
80 return false0;
81 }
82
83 vring_init(&vring->vr, virtio_queue_get_num(vdev, n), vring_ptr, 4096);
84
85 vring->last_avail_idx = virtio_queue_get_last_avail_idx(vdev, n);
86 vring->last_used_idx = vring->vr.used->idx;
87 vring->signalled_used = 0;
88 vring->signalled_used_valid = false0;
89
90 trace_vring_setup(virtio_queue_get_ring_addr(vdev, n),
91 vring->vr.desc, vring->vr.avail, vring->vr.used);
92 return true1;
93}
94
95void vring_teardown(Vring *vring, VirtIODevice *vdev, int n)
96{
97 virtio_queue_set_last_avail_idx(vdev, n, vring->last_avail_idx);
98 virtio_queue_invalidate_signalled_used(vdev, n);
99
100 memory_region_unref(vring->mr);
101}
102
103/* Disable guest->host notifies */
104void vring_disable_notification(VirtIODevice *vdev, Vring *vring)
105{
106 if (!(vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX29))) {
107 vring->vr.used->flags |= VRING_USED_F_NO_NOTIFY1;
108 }
109}
110
111/* Enable guest->host notifies
112 *
113 * Return true if the vring is empty, false if there are more requests.
114 */
115bool_Bool vring_enable_notification(VirtIODevice *vdev, Vring *vring)
116{
117 if (vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX29)) {
118 vring_avail_event(&vring->vr)(*(__u16 *)&(&vring->vr)->used->ring[(&vring
->vr)->num])
= vring->vr.avail->idx;
119 } else {
120 vring->vr.used->flags &= ~VRING_USED_F_NO_NOTIFY1;
121 }
122 smp_mb()__sync_synchronize(); /* ensure update is seen before reading avail_idx */
123 return !vring_more_avail(vring);
124}
125
126/* This is stolen from linux/drivers/vhost/vhost.c:vhost_notify() */
127bool_Bool vring_should_notify(VirtIODevice *vdev, Vring *vring)
128{
129 uint16_t old, new;
130 bool_Bool v;
131 /* Flush out used index updates. This is paired
132 * with the barrier that the Guest executes when enabling
133 * interrupts. */
134 smp_mb()__sync_synchronize();
135
136 if ((vdev->guest_features & VIRTIO_F_NOTIFY_ON_EMPTY24) &&
137 unlikely(vring->vr.avail->idx == vring->last_avail_idx)__builtin_expect(!!(vring->vr.avail->idx == vring->last_avail_idx
), 0)
) {
138 return true1;
139 }
140
141 if (!(vdev->guest_features & VIRTIO_RING_F_EVENT_IDX29)) {
142 return !(vring->vr.avail->flags & VRING_AVAIL_F_NO_INTERRUPT1);
143 }
144 old = vring->signalled_used;
145 v = vring->signalled_used_valid;
146 new = vring->signalled_used = vring->last_used_idx;
147 vring->signalled_used_valid = true1;
148
149 if (unlikely(!v)__builtin_expect(!!(!v), 0)) {
150 return true1;
151 }
152
153 return vring_need_event(vring_used_event(&vring->vr)((&vring->vr)->avail->ring[(&vring->vr)->
num])
, new, old);
154}
155
156
157static int get_desc(Vring *vring, VirtQueueElement *elem,
158 struct vring_desc *desc)
159{
160 unsigned *num;
161 struct iovec *iov;
162 hwaddr *addr;
163 MemoryRegion *mr;
164
165 if (desc->flags & VRING_DESC_F_WRITE2) {
166 num = &elem->in_num;
167 iov = &elem->in_sg[*num];
168 addr = &elem->in_addr[*num];
169 } else {
170 num = &elem->out_num;
171 iov = &elem->out_sg[*num];
172 addr = &elem->out_addr[*num];
173
174 /* If it's an output descriptor, they're all supposed
175 * to come before any input descriptors. */
176 if (unlikely(elem->in_num)__builtin_expect(!!(elem->in_num), 0)) {
177 error_report("Descriptor has out after in");
178 return -EFAULT14;
179 }
180 }
181
182 /* Stop for now if there are not enough iovecs available. */
183 if (*num >= VIRTQUEUE_MAX_SIZE1024) {
184 return -ENOBUFS105;
185 }
186
187 /* TODO handle non-contiguous memory across region boundaries */
188 iov->iov_base = vring_map(&mr, desc->addr, desc->len,
189 desc->flags & VRING_DESC_F_WRITE2);
190 if (!iov->iov_base) {
191 error_report("Failed to map descriptor addr %#" PRIx64"l" "x" " len %u",
192 (uint64_t)desc->addr, desc->len);
193 return -EFAULT14;
194 }
195
196 /* The MemoryRegion is looked up again and unref'ed later, leave the
197 * ref in place. */
198 iov->iov_len = desc->len;
199 *addr = desc->addr;
200 *num += 1;
201 return 0;
202}
203
204/* This is stolen from linux/drivers/vhost/vhost.c. */
205static int get_indirect(Vring *vring, VirtQueueElement *elem,
206 struct vring_desc *indirect)
207{
208 struct vring_desc desc;
209 unsigned int i = 0, count, found = 0;
210 int ret;
211
212 /* Sanity check */
213 if (unlikely(indirect->len % sizeof(desc))__builtin_expect(!!(indirect->len % sizeof(desc)), 0)) {
214 error_report("Invalid length in indirect descriptor: "
215 "len %#x not multiple of %#zx",
216 indirect->len, sizeof(desc));
217 vring->broken = true1;
218 return -EFAULT14;
219 }
220
221 count = indirect->len / sizeof(desc);
222 /* Buffers are chained via a 16 bit next field, so
223 * we can have at most 2^16 of these. */
224 if (unlikely(count > USHRT_MAX + 1)__builtin_expect(!!(count > (32767 *2 +1) + 1), 0)) {
225 error_report("Indirect buffer length too big: %d", indirect->len);
226 vring->broken = true1;
227 return -EFAULT14;
228 }
229
230 do {
231 struct vring_desc *desc_ptr;
232 MemoryRegion *mr;
233
234 /* Translate indirect descriptor */
235 desc_ptr = vring_map(&mr,
236 indirect->addr + found * sizeof(desc),
237 sizeof(desc), false0);
238 if (!desc_ptr) {
239 error_report("Failed to map indirect descriptor "
240 "addr %#" PRIx64"l" "x" " len %zu",
241 (uint64_t)indirect->addr + found * sizeof(desc),
242 sizeof(desc));
243 vring->broken = true1;
244 return -EFAULT14;
245 }
246 desc = *desc_ptr;
247 memory_region_unref(mr);
248
249 /* Ensure descriptor has been loaded before accessing fields */
250 barrier()({ asm volatile("" ::: "memory"); (void)0; }); /* read_barrier_depends(); */
251
252 if (unlikely(++found > count)__builtin_expect(!!(++found > count), 0)) {
253 error_report("Loop detected: last one at %u "
254 "indirect size %u", i, count);
255 vring->broken = true1;
256 return -EFAULT14;
257 }
258
259 if (unlikely(desc.flags & VRING_DESC_F_INDIRECT)__builtin_expect(!!(desc.flags & 4), 0)) {
260 error_report("Nested indirect descriptor");
261 vring->broken = true1;
262 return -EFAULT14;
263 }
264
265 ret = get_desc(vring, elem, &desc);
266 if (ret < 0) {
267 vring->broken |= (ret == -EFAULT14);
268 return ret;
269 }
270 i = desc.next;
271 } while (desc.flags & VRING_DESC_F_NEXT1);
272 return 0;
273}
274
275void vring_free_element(VirtQueueElement *elem)
276{
277 int i;
278
279 /* This assumes that the iovecs, if changed, are never moved past
280 * the end of the valid area. This is true if iovec manipulations
281 * are done with iov_discard_front and iov_discard_back.
282 */
283 for (i = 0; i < elem->out_num; i++) {
284 vring_unmap(elem->out_sg[i].iov_base, false0);
285 }
286
287 for (i = 0; i < elem->in_num; i++) {
288 vring_unmap(elem->in_sg[i].iov_base, true1);
289 }
290
291 g_slice_free(VirtQueueElement, elem)do { if (1) g_slice_free1 (sizeof (VirtQueueElement), (elem))
; else (void) ((VirtQueueElement*) 0 == (elem)); } while (0)
;
292}
293
294/* This looks in the virtqueue and for the first available buffer, and converts
295 * it to an iovec for convenient access. Since descriptors consist of some
296 * number of output then some number of input descriptors, it's actually two
297 * iovecs, but we pack them into one and note how many of each there were.
298 *
299 * This function returns the descriptor number found, or vq->num (which is
300 * never a valid descriptor number) if none was found. A negative code is
301 * returned on error.
302 *
303 * Stolen from linux/drivers/vhost/vhost.c.
304 */
305int vring_pop(VirtIODevice *vdev, Vring *vring,
306 VirtQueueElement **p_elem)
307{
308 struct vring_desc desc;
309 unsigned int i, head, found = 0, num = vring->vr.num;
310 uint16_t avail_idx, last_avail_idx;
311 VirtQueueElement *elem = NULL((void*)0);
312 int ret;
1
'ret' declared without an initial value
313
314 /* If there was a fatal error then refuse operation */
315 if (vring->broken) {
2
Taking false branch
316 ret = -EFAULT14;
317 goto out;
318 }
319
320 /* Check it isn't doing very strange things with descriptor numbers. */
321 last_avail_idx = vring->last_avail_idx;
322 avail_idx = vring->vr.avail->idx;
323 barrier()({ asm volatile("" ::: "memory"); (void)0; }); /* load indices now and not again later */
324
325 if (unlikely((uint16_t)(avail_idx - last_avail_idx) > num)__builtin_expect(!!((uint16_t)(avail_idx - last_avail_idx) >
num), 0)
) {
3
Taking false branch
326 error_report("Guest moved used index from %u to %u",
327 last_avail_idx, avail_idx);
328 ret = -EFAULT14;
329 goto out;
330 }
331
332 /* If there's nothing new since last we looked. */
333 if (avail_idx == last_avail_idx) {
4
Taking false branch
334 ret = -EAGAIN11;
335 goto out;
336 }
337
338 /* Only get avail ring entries after they have been exposed by guest. */
339 smp_rmb()__atomic_thread_fence(2);
340
341 /* Grab the next descriptor number they're advertising, and increment
342 * the index we've seen. */
343 head = vring->vr.avail->ring[last_avail_idx % num];
344
345 elem = g_slice_new(VirtQueueElement)((VirtQueueElement*) g_slice_alloc (sizeof (VirtQueueElement)
))
;
346 elem->index = head;
347 elem->in_num = elem->out_num = 0;
348
349 /* If their number is silly, that's an error. */
350 if (unlikely(head >= num)__builtin_expect(!!(head >= num), 0)) {
5
Taking false branch
351 error_report("Guest says index %u > %u is available", head, num);
352 ret = -EFAULT14;
353 goto out;
354 }
355
356 if (vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX29)) {
6
Taking false branch
357 vring_avail_event(&vring->vr)(*(__u16 *)&(&vring->vr)->used->ring[(&vring
->vr)->num])
= vring->vr.avail->idx;
358 }
359
360 i = head;
361 do {
362 if (unlikely(i >= num)__builtin_expect(!!(i >= num), 0)) {
7
Taking false branch
363 error_report("Desc index is %u > %u, head = %u", i, num, head);
364 ret = -EFAULT14;
365 goto out;
366 }
367 if (unlikely(++found > num)__builtin_expect(!!(++found > num), 0)) {
8
Taking false branch
368 error_report("Loop detected: last one at %u vq size %u head %u",
369 i, num, head);
370 ret = -EFAULT14;
371 goto out;
372 }
373 desc = vring->vr.desc[i];
374
375 /* Ensure descriptor is loaded before accessing fields */
376 barrier()({ asm volatile("" ::: "memory"); (void)0; });
377
378 if (desc.flags & VRING_DESC_F_INDIRECT4) {
9
Taking true branch
379 int ret = get_indirect(vring, elem, &desc);
380 if (ret < 0) {
10
Assuming 'ret' is < 0
11
Taking true branch
381 goto out;
12
Control jumps to line 400
382 }
383 continue;
384 }
385
386 ret = get_desc(vring, elem, &desc);
387 if (ret < 0) {
388 goto out;
389 }
390
391 i = desc.next;
392 } while (desc.flags & VRING_DESC_F_NEXT1);
393
394 /* On success, increment avail index. */
395 vring->last_avail_idx++;
396 *p_elem = elem;
397 return head;
398
399out:
400 assert(ret < 0)((ret < 0) ? (void) (0) : __assert_fail ("ret < 0", "/home/stefan/src/qemu/qemu.org/qemu/hw/virtio/dataplane/vring.c"
, 400, __PRETTY_FUNCTION__))
;
13
Within the expansion of the macro 'assert':
a
The left operand of '<' is a garbage value
401 if (ret == -EFAULT14) {
402 vring->broken = true1;
403 }
404 if (elem) {
405 vring_free_element(elem);
406 }
407 *p_elem = NULL((void*)0);
408 return ret;
409}
410
411/* After we've used one of their buffers, we tell them about it.
412 *
413 * Stolen from linux/drivers/vhost/vhost.c.
414 */
415void vring_push(Vring *vring, VirtQueueElement *elem, int len)
416{
417 struct vring_used_elem *used;
418 unsigned int head = elem->index;
419 uint16_t new;
420
421 vring_free_element(elem);
422
423 /* Don't touch vring if a fatal error occurred */
424 if (vring->broken) {
425 return;
426 }
427
428 /* The virtqueue contains a ring of used buffers. Get a pointer to the
429 * next entry in that used ring. */
430 used = &vring->vr.used->ring[vring->last_used_idx % vring->vr.num];
431 used->id = head;
432 used->len = len;
433
434 /* Make sure buffer is written before we update index. */
435 smp_wmb()__atomic_thread_fence(3);
436
437 new = vring->vr.used->idx = ++vring->last_used_idx;
438 if (unlikely((int16_t)(new - vring->signalled_used) < (uint16_t)1)__builtin_expect(!!((int16_t)(new - vring->signalled_used)
< (uint16_t)1), 0)
) {
439 vring->signalled_used_valid = false0;
440 }
441}