~ubuntu-branches/ubuntu/trusty/qemu/trusty

« back to all changes in this revision

Viewing changes to .pc/ubuntu/CVE-2013-4377.patch/hw/scsi/vhost-scsi.c

  • Committer: Package Import Robot
  • Author(s): Serge Hallyn
  • Date: 2014-02-04 12:13:08 UTC
  • mfrom: (10.1.45 sid)
  • Revision ID: package-import@ubuntu.com-20140204121308-1xq92lrfs75agw2g
Tags: 1.7.0+dfsg-3ubuntu1~ppa1
* Merge 1.7.0+dfsg-3 from debian.  Remaining changes:
  - debian/patches/ubuntu:
    * expose-vmx_qemu64cpu.patch
    * linaro (omap3) and arm64 patches
    * ubuntu/target-ppc-add-stubs-for-kvm-breakpoints: fix FTBFS
      on ppc
    * ubuntu/CVE-2013-4377.patch: fix denial of service via virtio
  - debian/qemu-system-x86.modprobe: set kvm_intel nested=1 options
  - debian/control:
    * add arm64 to Architectures
    * add qemu-common and qemu-system-aarch64 packages
  - debian/qemu-system-common.install: add debian/tmp/usr/lib
  - debian/qemu-system-common.preinst: add kvm group
  - debian/qemu-system-common.postinst: remove acl placed by udev,
    and add udevadm trigger.
  - qemu-system-x86.links: add eepro100.rom, remove pxe-virtio,
    pxe-e1000 and pxe-rtl8139.
  - add qemu-system-x86.qemu-kvm.upstart and .default
  - qemu-user-static.postinst-in: remove arm64 binfmt
  - debian/rules:
    * allow parallel build
    * add aarch64 to system_targets and sys_systems
    * add qemu-kvm-spice links
    * install qemu-system-x86.modprobe
  - add debian/qemu-system-common.links for OVMF.fd link
* Remove kvm-img, kvm-nbd, kvm-ifup and kvm-ifdown symlinks.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * vhost_scsi host device
 
3
 *
 
4
 * Copyright IBM, Corp. 2011
 
5
 *
 
6
 * Authors:
 
7
 *  Stefan Hajnoczi   <stefanha@linux.vnet.ibm.com>
 
8
 *
 
9
 * Changes for QEMU mainline + tcm_vhost kernel upstream:
 
10
 *  Nicholas Bellinger <nab@risingtidesystems.com>
 
11
 *
 
12
 * This work is licensed under the terms of the GNU LGPL, version 2 or later.
 
13
 * See the COPYING.LIB file in the top-level directory.
 
14
 *
 
15
 */
 
16
 
 
17
#include <sys/ioctl.h>
 
18
#include "config.h"
 
19
#include "qemu/queue.h"
 
20
#include "monitor/monitor.h"
 
21
#include "migration/migration.h"
 
22
#include "hw/virtio/vhost-scsi.h"
 
23
#include "hw/virtio/vhost.h"
 
24
#include "hw/virtio/virtio-scsi.h"
 
25
#include "hw/virtio/virtio-bus.h"
 
26
 
 
27
static int vhost_scsi_set_endpoint(VHostSCSI *s)
 
28
{
 
29
    VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
 
30
    struct vhost_scsi_target backend;
 
31
    int ret;
 
32
 
 
33
    memset(&backend, 0, sizeof(backend));
 
34
    pstrcpy(backend.vhost_wwpn, sizeof(backend.vhost_wwpn), vs->conf.wwpn);
 
35
    ret = ioctl(s->dev.control, VHOST_SCSI_SET_ENDPOINT, &backend);
 
36
    if (ret < 0) {
 
37
        return -errno;
 
38
    }
 
39
    return 0;
 
40
}
 
41
 
 
42
static void vhost_scsi_clear_endpoint(VHostSCSI *s)
 
43
{
 
44
    VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
 
45
    struct vhost_scsi_target backend;
 
46
 
 
47
    memset(&backend, 0, sizeof(backend));
 
48
    pstrcpy(backend.vhost_wwpn, sizeof(backend.vhost_wwpn), vs->conf.wwpn);
 
49
    ioctl(s->dev.control, VHOST_SCSI_CLEAR_ENDPOINT, &backend);
 
50
}
 
51
 
 
52
static int vhost_scsi_start(VHostSCSI *s)
 
53
{
 
54
    int ret, abi_version, i;
 
55
    VirtIODevice *vdev = VIRTIO_DEVICE(s);
 
56
    BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
 
57
    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
 
58
 
 
59
    if (!k->set_guest_notifiers) {
 
60
        error_report("binding does not support guest notifiers");
 
61
        return -ENOSYS;
 
62
    }
 
63
 
 
64
    ret = ioctl(s->dev.control, VHOST_SCSI_GET_ABI_VERSION, &abi_version);
 
65
    if (ret < 0) {
 
66
        return -errno;
 
67
    }
 
68
    if (abi_version > VHOST_SCSI_ABI_VERSION) {
 
69
        error_report("vhost-scsi: The running tcm_vhost kernel abi_version:"
 
70
                     " %d is greater than vhost_scsi userspace supports: %d, please"
 
71
                     " upgrade your version of QEMU\n", abi_version,
 
72
                     VHOST_SCSI_ABI_VERSION);
 
73
        return -ENOSYS;
 
74
    }
 
75
 
 
76
    ret = vhost_dev_enable_notifiers(&s->dev, vdev);
 
77
    if (ret < 0) {
 
78
        return ret;
 
79
    }
 
80
 
 
81
    s->dev.acked_features = vdev->guest_features;
 
82
    ret = vhost_dev_start(&s->dev, vdev);
 
83
    if (ret < 0) {
 
84
        error_report("Error start vhost dev");
 
85
        goto err_notifiers;
 
86
    }
 
87
 
 
88
    ret = vhost_scsi_set_endpoint(s);
 
89
    if (ret < 0) {
 
90
        error_report("Error set vhost-scsi endpoint");
 
91
        goto err_vhost_stop;
 
92
    }
 
93
 
 
94
    ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, true);
 
95
    if (ret < 0) {
 
96
        error_report("Error binding guest notifier");
 
97
        goto err_endpoint;
 
98
    }
 
99
 
 
100
    /* guest_notifier_mask/pending not used yet, so just unmask
 
101
     * everything here.  virtio-pci will do the right thing by
 
102
     * enabling/disabling irqfd.
 
103
     */
 
104
    for (i = 0; i < s->dev.nvqs; i++) {
 
105
        vhost_virtqueue_mask(&s->dev, vdev, i, false);
 
106
    }
 
107
 
 
108
    return ret;
 
109
 
 
110
err_endpoint:
 
111
    vhost_scsi_clear_endpoint(s);
 
112
err_vhost_stop:
 
113
    vhost_dev_stop(&s->dev, vdev);
 
114
err_notifiers:
 
115
    vhost_dev_disable_notifiers(&s->dev, vdev);
 
116
    return ret;
 
117
}
 
118
 
 
119
static void vhost_scsi_stop(VHostSCSI *s)
 
120
{
 
121
    VirtIODevice *vdev = VIRTIO_DEVICE(s);
 
122
    BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
 
123
    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
 
124
    int ret = 0;
 
125
 
 
126
    if (k->set_guest_notifiers) {
 
127
        ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false);
 
128
        if (ret < 0) {
 
129
                error_report("vhost guest notifier cleanup failed: %d\n", ret);
 
130
        }
 
131
    }
 
132
    assert(ret >= 0);
 
133
 
 
134
    vhost_scsi_clear_endpoint(s);
 
135
    vhost_dev_stop(&s->dev, vdev);
 
136
    vhost_dev_disable_notifiers(&s->dev, vdev);
 
137
}
 
138
 
 
139
static uint32_t vhost_scsi_get_features(VirtIODevice *vdev,
 
140
                                        uint32_t features)
 
141
{
 
142
    VHostSCSI *s = VHOST_SCSI(vdev);
 
143
 
 
144
    /* Clear features not supported by host kernel. */
 
145
    if (!(s->dev.features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY))) {
 
146
        features &= ~(1 << VIRTIO_F_NOTIFY_ON_EMPTY);
 
147
    }
 
148
    if (!(s->dev.features & (1 << VIRTIO_RING_F_INDIRECT_DESC))) {
 
149
        features &= ~(1 << VIRTIO_RING_F_INDIRECT_DESC);
 
150
    }
 
151
    if (!(s->dev.features & (1 << VIRTIO_RING_F_EVENT_IDX))) {
 
152
        features &= ~(1 << VIRTIO_RING_F_EVENT_IDX);
 
153
    }
 
154
    if (!(s->dev.features & (1 << VIRTIO_SCSI_F_HOTPLUG))) {
 
155
        features &= ~(1 << VIRTIO_SCSI_F_HOTPLUG);
 
156
    }
 
157
 
 
158
    return features;
 
159
}
 
160
 
 
161
static void vhost_scsi_set_config(VirtIODevice *vdev,
 
162
                                  const uint8_t *config)
 
163
{
 
164
    VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config;
 
165
    VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
 
166
 
 
167
    if ((uint32_t) ldl_raw(&scsiconf->sense_size) != vs->sense_size ||
 
168
        (uint32_t) ldl_raw(&scsiconf->cdb_size) != vs->cdb_size) {
 
169
        error_report("vhost-scsi does not support changing the sense data and CDB sizes");
 
170
        exit(1);
 
171
    }
 
172
}
 
173
 
 
174
static void vhost_scsi_set_status(VirtIODevice *vdev, uint8_t val)
 
175
{
 
176
    VHostSCSI *s = (VHostSCSI *)vdev;
 
177
    bool start = (val & VIRTIO_CONFIG_S_DRIVER_OK);
 
178
 
 
179
    if (s->dev.started == start) {
 
180
        return;
 
181
    }
 
182
 
 
183
    if (start) {
 
184
        int ret;
 
185
 
 
186
        ret = vhost_scsi_start(s);
 
187
        if (ret < 0) {
 
188
            error_report("virtio-scsi: unable to start vhost: %s\n",
 
189
                         strerror(-ret));
 
190
 
 
191
            /* There is no userspace virtio-scsi fallback so exit */
 
192
            exit(1);
 
193
        }
 
194
    } else {
 
195
        vhost_scsi_stop(s);
 
196
    }
 
197
}
 
198
 
 
199
static int vhost_scsi_init(VirtIODevice *vdev)
 
200
{
 
201
    VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
 
202
    VHostSCSI *s = VHOST_SCSI(vdev);
 
203
    int vhostfd = -1;
 
204
    int ret;
 
205
 
 
206
    if (!vs->conf.wwpn) {
 
207
        error_report("vhost-scsi: missing wwpn\n");
 
208
        return -EINVAL;
 
209
    }
 
210
 
 
211
    if (vs->conf.vhostfd) {
 
212
        vhostfd = monitor_handle_fd_param(cur_mon, vs->conf.vhostfd);
 
213
        if (vhostfd == -1) {
 
214
            error_report("vhost-scsi: unable to parse vhostfd\n");
 
215
            return -EINVAL;
 
216
        }
 
217
    }
 
218
 
 
219
    ret = virtio_scsi_common_init(vs);
 
220
    if (ret < 0) {
 
221
        return ret;
 
222
    }
 
223
 
 
224
    s->dev.nvqs = VHOST_SCSI_VQ_NUM_FIXED + vs->conf.num_queues;
 
225
    s->dev.vqs = g_new(struct vhost_virtqueue, s->dev.nvqs);
 
226
    s->dev.vq_index = 0;
 
227
 
 
228
    ret = vhost_dev_init(&s->dev, vhostfd, "/dev/vhost-scsi", true);
 
229
    if (ret < 0) {
 
230
        error_report("vhost-scsi: vhost initialization failed: %s\n",
 
231
                strerror(-ret));
 
232
        return ret;
 
233
    }
 
234
    s->dev.backend_features = 0;
 
235
 
 
236
    error_setg(&s->migration_blocker,
 
237
            "vhost-scsi does not support migration");
 
238
    migrate_add_blocker(s->migration_blocker);
 
239
 
 
240
    return 0;
 
241
}
 
242
 
 
243
static int vhost_scsi_exit(DeviceState *qdev)
 
244
{
 
245
    VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
 
246
    VHostSCSI *s = VHOST_SCSI(qdev);
 
247
    VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(qdev);
 
248
 
 
249
    migrate_del_blocker(s->migration_blocker);
 
250
    error_free(s->migration_blocker);
 
251
 
 
252
    /* This will stop vhost backend. */
 
253
    vhost_scsi_set_status(vdev, 0);
 
254
 
 
255
    g_free(s->dev.vqs);
 
256
    return virtio_scsi_common_exit(vs);
 
257
}
 
258
 
 
259
static Property vhost_scsi_properties[] = {
 
260
    DEFINE_VHOST_SCSI_PROPERTIES(VHostSCSI, parent_obj.conf),
 
261
    DEFINE_PROP_END_OF_LIST(),
 
262
};
 
263
 
 
264
static void vhost_scsi_class_init(ObjectClass *klass, void *data)
 
265
{
 
266
    DeviceClass *dc = DEVICE_CLASS(klass);
 
267
    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
 
268
    dc->exit = vhost_scsi_exit;
 
269
    dc->props = vhost_scsi_properties;
 
270
    set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
 
271
    vdc->init = vhost_scsi_init;
 
272
    vdc->get_features = vhost_scsi_get_features;
 
273
    vdc->set_config = vhost_scsi_set_config;
 
274
    vdc->set_status = vhost_scsi_set_status;
 
275
}
 
276
 
 
277
static const TypeInfo vhost_scsi_info = {
 
278
    .name = TYPE_VHOST_SCSI,
 
279
    .parent = TYPE_VIRTIO_SCSI_COMMON,
 
280
    .instance_size = sizeof(VHostSCSI),
 
281
    .class_init = vhost_scsi_class_init,
 
282
};
 
283
 
 
284
static void virtio_register_types(void)
 
285
{
 
286
    type_register_static(&vhost_scsi_info);
 
287
}
 
288
 
 
289
type_init(virtio_register_types)