aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile3
-rw-r--r--block/nbd-client.c3
-rw-r--r--block/nbd-client.h1
-rw-r--r--block/nbd.c2
-rw-r--r--blockdev-nbd.c6
-rw-r--r--cpus.c2
-rw-r--r--exec.c6
-rw-r--r--hw/pci/pcie.c2
-rw-r--r--hw/pci/pcie_aer.c12
-rw-r--r--hw/scsi/virtio-scsi-dataplane.c4
-rw-r--r--hw/scsi/virtio-scsi.c8
-rw-r--r--hw/virtio/virtio.c3
-rw-r--r--include/block/nbd.h11
-rw-r--r--include/hw/pci/pci.h2
-rw-r--r--include/hw/pci/pcie_aer.h2
-rw-r--r--include/hw/pci/pcie_regs.h2
-rw-r--r--include/qemu/timer.h5
-rw-r--r--kvm-all.c24
-rw-r--r--monitor.c6
-rw-r--r--nbd.c112
-rw-r--r--qemu-coroutine-io.c2
-rw-r--r--qemu-nbd.c30
-rw-r--r--scripts/make_device_config.sh18
-rw-r--r--target-mips/translate.c22
-rw-r--r--ui/vnc-auth-vencrypt.c1
-rw-r--r--ui/vnc-tls.c72
-rw-r--r--ui/vnc-tls.h7
-rw-r--r--ui/vnc-ws.c46
-rw-r--r--ui/vnc-ws.h2
-rw-r--r--ui/vnc.c289
-rw-r--r--ui/vnc.h9
-rw-r--r--util/uri.c24
32 files changed, 431 insertions, 307 deletions
diff --git a/Makefile b/Makefile
index 884b59dc06..88bce561a8 100644
--- a/Makefile
+++ b/Makefile
@@ -112,7 +112,8 @@ endif
-include $(SUBDIR_DEVICES_MAK_DEP)
%/config-devices.mak: default-configs/%.mak
- $(call quiet-command,$(SHELL) $(SRC_PATH)/scripts/make_device_config.sh $@.tmp $<, " GEN $@.tmp")
+ $(call quiet-command, \
+ $(SHELL) $(SRC_PATH)/scripts/make_device_config.sh $< $*-config-devices.mak.d $@ > $@.tmp, " GEN $@.tmp")
$(call quiet-command, if test -f $@; then \
if cmp -s $@.old $@; then \
mv $@.tmp $@; \
diff --git a/block/nbd-client.c b/block/nbd-client.c
index 259f5a3cb6..e1bb9198c5 100644
--- a/block/nbd-client.c
+++ b/block/nbd-client.c
@@ -386,8 +386,7 @@ int nbd_client_init(BlockDriverState *bs, int sock, const char *export,
logout("session init %s\n", export);
qemu_set_block(sock);
ret = nbd_receive_negotiate(sock, export,
- &client->nbdflags, &client->size,
- &client->blocksize, errp);
+ &client->nbdflags, &client->size, errp);
if (ret < 0) {
logout("Failed to negotiate with the NBD server\n");
closesocket(sock);
diff --git a/block/nbd-client.h b/block/nbd-client.h
index fa4ff42d22..e8413408b5 100644
--- a/block/nbd-client.h
+++ b/block/nbd-client.h
@@ -20,7 +20,6 @@ typedef struct NbdClientSession {
int sock;
uint32_t nbdflags;
off_t size;
- size_t blocksize;
CoMutex send_mutex;
CoMutex free_sema;
diff --git a/block/nbd.c b/block/nbd.c
index 6634a69664..217618612d 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -248,7 +248,7 @@ static int nbd_establish_connection(BlockDriverState *bs, Error **errp)
/* Failed to establish connection */
if (sock < 0) {
logout("Failed to establish connection to NBD server\n");
- return -errno;
+ return -EIO;
}
return sock;
diff --git a/blockdev-nbd.c b/blockdev-nbd.c
index 22e95d17ee..b29e456f1f 100644
--- a/blockdev-nbd.c
+++ b/blockdev-nbd.c
@@ -105,7 +105,11 @@ void qmp_nbd_server_add(const char *device, bool has_writable, bool writable,
writable = false;
}
- exp = nbd_export_new(blk, 0, -1, writable ? 0 : NBD_FLAG_READ_ONLY, NULL);
+ exp = nbd_export_new(blk, 0, -1, writable ? 0 : NBD_FLAG_READ_ONLY, NULL,
+ errp);
+ if (!exp) {
+ return;
+ }
nbd_export_set_name(exp, device);
diff --git a/cpus.c b/cpus.c
index 1ce90a12e8..314df16190 100644
--- a/cpus.c
+++ b/cpus.c
@@ -1353,7 +1353,7 @@ static int tcg_cpu_exec(CPUArchState *env)
}
ret = cpu_exec(env);
#ifdef CONFIG_PROFILER
- qemu_time += profile_getclock() - ti;
+ tcg_time += profile_getclock() - ti;
#endif
if (use_icount) {
/* Fold pending instructions back into the
diff --git a/exec.c b/exec.c
index e97071a3ec..8b922db612 100644
--- a/exec.c
+++ b/exec.c
@@ -380,7 +380,6 @@ MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr,
IOMMUTLBEntry iotlb;
MemoryRegionSection *section;
MemoryRegion *mr;
- hwaddr len = *plen;
rcu_read_lock();
for (;;) {
@@ -395,7 +394,7 @@ MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr,
iotlb = mr->iommu_ops->translate(mr, addr, is_write);
addr = ((iotlb.translated_addr & ~iotlb.addr_mask)
| (addr & iotlb.addr_mask));
- len = MIN(len, (addr | iotlb.addr_mask) - addr + 1);
+ *plen = MIN(*plen, (addr | iotlb.addr_mask) - addr + 1);
if (!(iotlb.perm & (1 << is_write))) {
mr = &io_mem_unassigned;
break;
@@ -406,10 +405,9 @@ MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr,
if (xen_enabled() && memory_access_is_direct(mr, is_write)) {
hwaddr page = ((addr & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE) - addr;
- len = MIN(page, len);
+ *plen = MIN(page, *plen);
}
- *plen = len;
*xlat = addr;
rcu_read_unlock();
return mr;
diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c
index 1abbbb192e..1463e65b5d 100644
--- a/hw/pci/pcie.c
+++ b/hw/pci/pcie.c
@@ -84,7 +84,7 @@ int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port)
pci_set_long(exp_cap + PCI_EXP_DEVCAP2,
PCI_EXP_DEVCAP2_EFF | PCI_EXP_DEVCAP2_EETLPP);
- pci_set_word(dev->wmask + pos, PCI_EXP_DEVCTL2_EETLPPB);
+ pci_set_word(dev->wmask + pos + PCI_EXP_DEVCTL2, PCI_EXP_DEVCTL2_EETLPPB);
return pos;
}
diff --git a/hw/pci/pcie_aer.c b/hw/pci/pcie_aer.c
index 5a25c32a3d..eaa3e6ea94 100644
--- a/hw/pci/pcie_aer.c
+++ b/hw/pci/pcie_aer.c
@@ -123,7 +123,7 @@ int pcie_aer_init(PCIDevice *dev, uint16_t offset)
PCI_ERR_UNC_SUPPORTED);
pci_long_test_and_set_mask(dev->w1cmask + offset + PCI_ERR_COR_STATUS,
- PCI_ERR_COR_STATUS);
+ PCI_ERR_COR_SUPPORTED);
pci_set_long(dev->config + offset + PCI_ERR_COR_MASK,
PCI_ERR_COR_MASK_DEFAULT);
@@ -433,7 +433,7 @@ static void pcie_aer_update_log(PCIDevice *dev, const PCIEAERErr *err)
}
if ((err->flags & PCIE_AER_ERR_TLP_PREFIX_PRESENT) &&
- (pci_get_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2) &
+ (pci_get_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCAP2) &
PCI_EXP_DEVCAP2_EETLPP)) {
for (i = 0; i < ARRAY_SIZE(err->prefix); ++i) {
/* 7.10.12 tlp prefix log register */
@@ -618,12 +618,12 @@ static bool pcie_aer_inject_uncor_error(PCIEAERInject *inj, bool is_fatal)
* non-Function specific error must be recorded in all functions.
* It is the responsibility of the caller of this function.
* It is also caller's responsibility to determine which function should
- * report the rerror.
+ * report the error.
*
* 6.2.4 Error Logging
- * 6.2.5 Sqeunce of Device Error Signaling and Logging Operations
- * table 6-2: Flowchard Showing Sequence of Device Error Signaling and Logging
- * Operations
+ * 6.2.5 Sequence of Device Error Signaling and Logging Operations
+ * Figure 6-2: Flowchart Showing Sequence of Device Error Signaling and Logging
+ * Operations
*/
int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err)
{
diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c
index 3f40ff090f..c069cd764c 100644
--- a/hw/scsi/virtio-scsi-dataplane.c
+++ b/hw/scsi/virtio-scsi-dataplane.c
@@ -45,7 +45,7 @@ static VirtIOSCSIVring *virtio_scsi_vring_init(VirtIOSCSI *s,
{
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s)));
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
- VirtIOSCSIVring *r = g_slice_new(VirtIOSCSIVring);
+ VirtIOSCSIVring *r;
int rc;
/* Set up virtqueue notify */
@@ -56,6 +56,8 @@ static VirtIOSCSIVring *virtio_scsi_vring_init(VirtIOSCSI *s,
s->dataplane_fenced = true;
return NULL;
}
+
+ r = g_slice_new(VirtIOSCSIVring);
r->host_notifier = *virtio_queue_get_host_notifier(vq);
r->guest_notifier = *virtio_queue_get_guest_notifier(vq);
aio_set_event_notifier(s->ctx, &r->host_notifier, handler);
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index da0cff83f7..c9bea067e1 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -146,8 +146,12 @@ static int virtio_scsi_parse_req(VirtIOSCSIReq *req,
* TODO: always disable this workaround for virtio 1.0 devices.
*/
if (!virtio_has_feature(vdev, VIRTIO_F_ANY_LAYOUT)) {
- req_size = req->elem.out_sg[0].iov_len;
- resp_size = req->elem.in_sg[0].iov_len;
+ if (req->elem.out_num) {
+ req_size = req->elem.out_sg[0].iov_len;
+ }
+ if (req->elem.in_num) {
+ resp_size = req->elem.in_sg[0].iov_len;
+ }
}
out_size = qemu_sgl_concat(req, req->elem.out_sg,
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 3c6e430048..17c1260c0d 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -759,8 +759,9 @@ void virtio_queue_set_align(VirtIODevice *vdev, int n, int align)
void virtio_queue_notify_vq(VirtQueue *vq)
{
- if (vq->vring.desc) {
+ if (vq->vring.desc && vq->handle_output) {
VirtIODevice *vdev = vq->vdev;
+
trace_virtio_queue_notify(vdev, vq - vdev->vq, vq);
vq->handle_output(vdev, vq);
}
diff --git a/include/block/nbd.h b/include/block/nbd.h
index ca9a5ac5b3..65f409d804 100644
--- a/include/block/nbd.h
+++ b/include/block/nbd.h
@@ -54,8 +54,8 @@ struct nbd_reply {
/* Reply types. */
#define NBD_REP_ACK (1) /* Data sending finished. */
#define NBD_REP_SERVER (2) /* Export description. */
-#define NBD_REP_ERR_UNSUP ((1 << 31) | 1) /* Unknown option. */
-#define NBD_REP_ERR_INVALID ((1 << 31) | 3) /* Invalid length. */
+#define NBD_REP_ERR_UNSUP ((UINT32_C(1) << 31) | 1) /* Unknown option. */
+#define NBD_REP_ERR_INVALID ((UINT32_C(1) << 31) | 3) /* Invalid length. */
#define NBD_CMD_MASK_COMMAND 0x0000ffff
#define NBD_CMD_FLAG_FUA (1 << 16)
@@ -75,8 +75,8 @@ enum {
ssize_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read);
int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
- off_t *size, size_t *blocksize, Error **errp);
-int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize);
+ off_t *size, Error **errp);
+int nbd_init(int fd, int csock, uint32_t flags, off_t size);
ssize_t nbd_send_request(int csock, struct nbd_request *request);
ssize_t nbd_receive_reply(int csock, struct nbd_reply *reply);
int nbd_client(int fd);
@@ -86,7 +86,8 @@ typedef struct NBDExport NBDExport;
typedef struct NBDClient NBDClient;
NBDExport *nbd_export_new(BlockBackend *blk, off_t dev_offset, off_t size,
- uint32_t nbdflags, void (*close)(NBDExport *));
+ uint32_t nbdflags, void (*close)(NBDExport *),
+ Error **errp);
void nbd_export_close(NBDExport *exp);
void nbd_export_get(NBDExport *exp);
void nbd_export_put(NBDExport *exp);
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
index be2d9b8703..b97c2956ec 100644
--- a/include/hw/pci/pci.h
+++ b/include/hw/pci/pci.h
@@ -137,7 +137,7 @@ enum {
#define PCI_CONFIG_HEADER_SIZE 0x40
/* Size of the standard PCI config space */
#define PCI_CONFIG_SPACE_SIZE 0x100
-/* Size of the standart PCIe config space: 4KB */
+/* Size of the standard PCIe config space: 4KB */
#define PCIE_CONFIG_SPACE_SIZE 0x1000
#define PCI_NUM_PINS 4 /* A-D */
diff --git a/include/hw/pci/pcie_aer.h b/include/hw/pci/pcie_aer.h
index bcac80a7b0..2fb83882be 100644
--- a/include/hw/pci/pcie_aer.h
+++ b/include/hw/pci/pcie_aer.h
@@ -51,7 +51,7 @@ struct PCIEAERLog {
PCIEAERErr *log;
};
-/* aer error message: error signaling message has only error sevirity and
+/* aer error message: error signaling message has only error severity and
source id. See 2.2.8.3 error signaling messages */
struct PCIEAERMsg {
/*
diff --git a/include/hw/pci/pcie_regs.h b/include/hw/pci/pcie_regs.h
index 652d9fc58c..848ab1c206 100644
--- a/include/hw/pci/pcie_regs.h
+++ b/include/hw/pci/pcie_regs.h
@@ -72,7 +72,7 @@
#define PCI_EXP_DEVCAP2_EFF 0x100000
#define PCI_EXP_DEVCAP2_EETLPP 0x200000
-#define PCI_EXP_DEVCTL2_EETLPPB 0x80
+#define PCI_EXP_DEVCTL2_EETLPPB 0x8000
/* ARI */
#define PCI_ARI_VER 1
diff --git a/include/qemu/timer.h b/include/qemu/timer.h
index eba8b2109c..e5bd494c07 100644
--- a/include/qemu/timer.h
+++ b/include/qemu/timer.h
@@ -999,11 +999,10 @@ static inline int64_t cpu_get_real_ticks (void)
#ifdef CONFIG_PROFILER
static inline int64_t profile_getclock(void)
{
- return cpu_get_real_ticks();
+ return get_clock();
}
-extern int64_t qemu_time, qemu_time_start;
-extern int64_t tlb_flush_time;
+extern int64_t tcg_time;
extern int64_t dev_time;
#endif
diff --git a/kvm-all.c b/kvm-all.c
index 55025cc366..335438adb5 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -528,13 +528,33 @@ int kvm_vm_check_extension(KVMState *s, unsigned int extension)
return ret;
}
+static uint32_t adjust_ioeventfd_endianness(uint32_t val, uint32_t size)
+{
+#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
+ /* The kernel expects ioeventfd values in HOST_WORDS_BIGENDIAN
+ * endianness, but the memory core hands them in target endianness.
+ * For example, PPC is always treated as big-endian even if running
+ * on KVM and on PPC64LE. Correct here.
+ */
+ switch (size) {
+ case 2:
+ val = bswap16(val);
+ break;
+ case 4:
+ val = bswap32(val);
+ break;
+ }
+#endif
+ return val;
+}
+
static int kvm_set_ioeventfd_mmio(int fd, hwaddr addr, uint32_t val,
bool assign, uint32_t size, bool datamatch)
{
int ret;
struct kvm_ioeventfd iofd;
- iofd.datamatch = datamatch ? val : 0;
+ iofd.datamatch = datamatch ? adjust_ioeventfd_endianness(val, size) : 0;
iofd.addr = addr;
iofd.len = size;
iofd.flags = 0;
@@ -564,7 +584,7 @@ static int kvm_set_ioeventfd_pio(int fd, uint16_t addr, uint16_t val,
bool assign, uint32_t size, bool datamatch)
{
struct kvm_ioeventfd kick = {
- .datamatch = datamatch ? val : 0,
+ .datamatch = datamatch ? adjust_ioeventfd_endianness(val, size) : 0,
.addr = addr,
.flags = KVM_IOEVENTFD_FLAG_PIO,
.len = size,
diff --git a/monitor.c b/monitor.c
index f7e473981a..432db9503a 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1975,7 +1975,7 @@ static void hmp_info_numa(Monitor *mon, const QDict *qdict)
#ifdef CONFIG_PROFILER
-int64_t qemu_time;
+int64_t tcg_time;
int64_t dev_time;
static void hmp_info_profile(Monitor *mon, const QDict *qdict)
@@ -1983,8 +1983,8 @@ static void hmp_info_profile(Monitor *mon, const QDict *qdict)
monitor_printf(mon, "async time %" PRId64 " (%0.3f)\n",
dev_time, dev_time / (double)get_ticks_per_sec());
monitor_printf(mon, "qemu time %" PRId64 " (%0.3f)\n",
- qemu_time, qemu_time / (double)get_ticks_per_sec());
- qemu_time = 0;
+ tcg_time, tcg_time / (double)get_ticks_per_sec());
+ tcg_time = 0;
dev_time = 0;
}
#else
diff --git a/nbd.c b/nbd.c
index 71159aff6a..91b7d56239 100644
--- a/nbd.c
+++ b/nbd.c
@@ -193,6 +193,26 @@ static ssize_t read_sync(int fd, void *buffer, size_t size)
return nbd_wr_sync(fd, buffer, size, true);
}
+static ssize_t drop_sync(int fd, size_t size)
+{
+ ssize_t ret, dropped = size;
+ uint8_t *buffer = g_malloc(MIN(65536, size));
+
+ while (size > 0) {
+ ret = read_sync(fd, buffer, MIN(65536, size));
+ if (ret < 0) {
+ g_free(buffer);
+ return ret;
+ }
+
+ assert(ret <= size);
+ size -= ret;
+ }
+
+ g_free(buffer);
+ return dropped;
+}
+
static ssize_t write_sync(int fd, void *buffer, size_t size)
{
int ret;
@@ -303,6 +323,9 @@ static int nbd_handle_list(NBDClient *client, uint32_t length)
csock = client->sock;
if (length) {
+ if (drop_sync(csock, length) != length) {
+ return -EIO;
+ }
return nbd_send_rep(csock, NBD_REP_ERR_INVALID, NBD_OPT_LIST);
}
@@ -350,30 +373,39 @@ fail:
static int nbd_receive_options(NBDClient *client)
{
+ int csock = client->sock;
+ uint32_t flags;
+
+ /* Client sends:
+ [ 0 .. 3] client flags
+
+ [ 0 .. 7] NBD_OPTS_MAGIC
+ [ 8 .. 11] NBD option
+ [12 .. 15] Data length
+ ... Rest of request
+
+ [ 0 .. 7] NBD_OPTS_MAGIC
+ [ 8 .. 11] Second NBD option
+ [12 .. 15] Data length
+ ... Rest of request
+ */
+
+ if (read_sync(csock, &flags, sizeof(flags)) != sizeof(flags)) {
+ LOG("read failed");
+ return -EIO;
+ }
+ TRACE("Checking client flags");
+ be32_to_cpus(&flags);
+ if (flags != 0 && flags != NBD_FLAG_C_FIXED_NEWSTYLE) {
+ LOG("Bad client flags received");
+ return -EIO;
+ }
+
while (1) {
- int csock = client->sock;
+ int ret;
uint32_t tmp, length;
uint64_t magic;
- /* Client sends:
- [ 0 .. 3] client flags
- [ 4 .. 11] NBD_OPTS_MAGIC
- [12 .. 15] NBD option
- [16 .. 19] length
- ... Rest of request
- */
-
- if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
- LOG("read failed");
- return -EINVAL;
- }
- TRACE("Checking client flags");
- tmp = be32_to_cpu(tmp);
- if (tmp != 0 && tmp != NBD_FLAG_C_FIXED_NEWSTYLE) {
- LOG("Bad client flags received");
- return -EINVAL;
- }
-
if (read_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) {
LOG("read failed");
return -EINVAL;
@@ -398,8 +430,9 @@ static int nbd_receive_options(NBDClient *client)
TRACE("Checking option");
switch (be32_to_cpu(tmp)) {
case NBD_OPT_LIST:
- if (nbd_handle_list(client, length) < 0) {
- return 1;
+ ret = nbd_handle_list(client, length);
+ if (ret < 0) {
+ return ret;
}
break;
@@ -494,7 +527,7 @@ fail:
}
int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
- off_t *size, size_t *blocksize, Error **errp)
+ off_t *size, Error **errp)
{
char buf[256];
uint64_t magic, s;
@@ -602,7 +635,6 @@ int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
goto fail;
}
*size = be64_to_cpu(s);
- *blocksize = 1024;
TRACE("Size is %" PRIu64, *size);
if (!name) {
@@ -616,7 +648,7 @@ int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
error_setg(errp, "Failed to read export flags");
goto fail;
}
- *flags |= be32_to_cpu(tmp);
+ *flags |= be16_to_cpu(tmp);
}
if (read_sync(csock, &buf, 124) != 124) {
error_setg(errp, "Failed to read reserved block");
@@ -629,7 +661,7 @@ fail:
}
#ifdef __linux__
-int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
+int nbd_init(int fd, int csock, uint32_t flags, off_t size)
{
TRACE("Setting NBD socket");
@@ -639,17 +671,17 @@ int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
return -serrno;
}
- TRACE("Setting block size to %lu", (unsigned long)blocksize);
+ TRACE("Setting block size to %lu", (unsigned long)BDRV_SECTOR_SIZE);
- if (ioctl(fd, NBD_SET_BLKSIZE, blocksize) < 0) {
+ if (ioctl(fd, NBD_SET_BLKSIZE, (size_t)BDRV_SECTOR_SIZE) < 0) {
int serrno = errno;
LOG("Failed setting NBD block size");
return -serrno;
}
- TRACE("Setting size to %zd block(s)", (size_t)(size / blocksize));
+ TRACE("Setting size to %zd block(s)", (size_t)(size / BDRV_SECTOR_SIZE));
- if (ioctl(fd, NBD_SET_SIZE_BLOCKS, size / blocksize) < 0) {
+ if (ioctl(fd, NBD_SET_SIZE_BLOCKS, size / (size_t)BDRV_SECTOR_SIZE) < 0) {
int serrno = errno;
LOG("Failed setting size (in blocks)");
return -serrno;
@@ -714,7 +746,7 @@ int nbd_client(int fd)
return ret;
}
#else
-int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
+int nbd_init(int fd, int csock, uint32_t flags, off_t size)
{
return -ENOTSUP;
}
@@ -965,7 +997,8 @@ static void blk_aio_detach(void *opaque)
}
NBDExport *nbd_export_new(BlockBackend *blk, off_t dev_offset, off_t size,
- uint32_t nbdflags, void (*close)(NBDExport *))
+ uint32_t nbdflags, void (*close)(NBDExport *),
+ Error **errp)
{
NBDExport *exp = g_malloc0(sizeof(NBDExport));
exp->refcount = 1;
@@ -973,7 +1006,14 @@ NBDExport *nbd_export_new(BlockBackend *blk, off_t dev_offset, off_t size,
exp->blk = blk;
exp->dev_offset = dev_offset;
exp->nbdflags = nbdflags;
- exp->size = size == -1 ? blk_getlength(blk) : size;
+ exp->size = size < 0 ? blk_getlength(blk) : size;
+ if (exp->size < 0) {
+ error_setg_errno(errp, -exp->size,
+ "Failed to determine the NBD export's length");
+ goto fail;
+ }
+ exp->size -= exp->size % BDRV_SECTOR_SIZE;
+
exp->close = close;
exp->ctx = blk_get_aio_context(blk);
blk_ref(blk);
@@ -985,6 +1025,10 @@ NBDExport *nbd_export_new(BlockBackend *blk, off_t dev_offset, off_t size,
*/
blk_invalidate_cache(blk, NULL);
return exp;
+
+fail:
+ g_free(exp);
+ return NULL;
}
NBDExport *nbd_export_find(const char *name)
@@ -1295,7 +1339,7 @@ static void nbd_trip(void *opaque)
default:
LOG("invalid request type (%u) received", request.type);
invalid_request:
- reply.error = -EINVAL;
+ reply.error = EINVAL;
error_reply:
if (nbd_co_send_reply(req, &reply, 0) < 0) {
goto out;
diff --git a/qemu-coroutine-io.c b/qemu-coroutine-io.c
index d4049260da..28dc7351ac 100644
--- a/qemu-coroutine-io.c
+++ b/qemu-coroutine-io.c
@@ -45,7 +45,7 @@ qemu_co_sendv_recvv(int sockfd, struct iovec *iov, unsigned iov_cnt,
if (err == EAGAIN || err == EWOULDBLOCK) {
qemu_coroutine_yield();
} else if (done == 0) {
- return -1;
+ return -err;
} else {
break;
}
diff --git a/qemu-nbd.c b/qemu-nbd.c
index 064b000b43..7e690fff7e 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -142,8 +142,9 @@ static void read_partition(uint8_t *p, struct partition_record *r)
r->end_head = p[5];
r->end_cylinder = p[7] | ((p[6] << 2) & 0x300);
r->end_sector = p[6] & 0x3f;
- r->start_sector_abs = p[8] | p[9] << 8 | p[10] << 16 | p[11] << 24;
- r->nb_sectors_abs = p[12] | p[13] << 8 | p[14] << 16 | p[15] << 24;
+
+ r->start_sector_abs = le32_to_cpup((uint32_t *)(p + 8));
+ r->nb_sectors_abs = le32_to_cpup((uint32_t *)(p + 12));
}
static int find_partition(BlockBackend *blk, int partition,
@@ -167,8 +168,9 @@ static int find_partition(BlockBackend *blk, int partition,
for (i = 0; i < 4; i++) {
read_partition(&data[446 + 16 * i], &mbr[i]);
- if (!mbr[i].nb_sectors_abs)
+ if (!mbr[i].system || !mbr[i].nb_sectors_abs) {
continue;
+ }
if (mbr[i].system == 0xF || mbr[i].system == 0x5) {
struct partition_record ext[4];
@@ -182,8 +184,9 @@ static int find_partition(BlockBackend *blk, int partition,
for (j = 0; j < 4; j++) {
read_partition(&data1[446 + 16 * j], &ext[j]);
- if (!ext[j].nb_sectors_abs)
+ if (!ext[j].system || !ext[j].nb_sectors_abs) {
continue;
+ }
if ((ext_partnum + j + 1) == partition) {
*offset = (uint64_t)ext[j].start_sector_abs << 9;
@@ -276,7 +279,6 @@ static void *nbd_client_thread(void *arg)
{
char *device = arg;
off_t size;
- size_t blocksize;
uint32_t nbdflags;
int fd, sock;
int ret;
@@ -289,7 +291,7 @@ static void *nbd_client_thread(void *arg)
}
ret = nbd_receive_negotiate(sock, NULL, &nbdflags,
- &size, &blocksize, &local_error);
+ &size, &local_error);
if (ret < 0) {
if (local_error) {
fprintf(stderr, "%s\n", error_get_pretty(local_error));
@@ -305,7 +307,7 @@ static void *nbd_client_thread(void *arg)
goto out_socket;
}
- ret = nbd_init(fd, sock, nbdflags, size, blocksize);
+ ret = nbd_init(fd, sock, nbdflags, size);
if (ret < 0) {
goto out_fd;
}
@@ -633,7 +635,9 @@ int main(int argc, char **argv)
* print errors and exit with the proper status code.
*/
pid = fork();
- if (pid == 0) {
+ if (pid < 0) {
+ err(EXIT_FAILURE, "Failed to fork");
+ } else if (pid == 0) {
close(stderr_fd[0]);
ret = qemu_daemon(1, 0);
@@ -715,6 +719,10 @@ int main(int argc, char **argv)
bs->detect_zeroes = detect_zeroes;
fd_size = blk_getlength(blk);
+ if (fd_size < 0) {
+ errx(EXIT_FAILURE, "Failed to determine the image length: %s",
+ strerror(-fd_size));
+ }
if (partition != -1) {
ret = find_partition(blk, partition, &dev_offset, &fd_size);
@@ -724,7 +732,11 @@ int main(int argc, char **argv)
}
}
- exp = nbd_export_new(blk, dev_offset, fd_size, nbdflags, nbd_export_closed);
+ exp = nbd_export_new(blk, dev_offset, fd_size, nbdflags, nbd_export_closed,
+ &local_err);
+ if (!exp) {
+ errx(EXIT_FAILURE, "%s", error_get_pretty(local_err));
+ }
if (sockpath) {
fd = unix_socket_incoming(sockpath);
diff --git a/scripts/make_device_config.sh b/scripts/make_device_config.sh
index 7958086132..c1afb3ffaa 100644
--- a/scripts/make_device_config.sh
+++ b/scripts/make_device_config.sh
@@ -1,10 +1,12 @@
#! /bin/sh
-# Construct a target device config file from a default, pulling in any
-# files from include directives.
+# Writes a target device config file to stdout, from a default and from
+# include directives therein. Also emits Makefile dependencies.
+#
+# Usage: make_device_config.sh SRC DEPFILE-NAME DEPFILE-TARGET > DEST
-dest=$1
-dep=`dirname $1`-`basename $1`.d
-src=$2
+src=$1
+dep=$2
+target=$3
src_dir=`dirname $src`
all_includes=
@@ -22,7 +24,7 @@ while [ -n "$f" ] ; do
[ $? = 0 ] || exit 1
all_includes="$all_includes $f"
done
-process_includes $src > $dest
+process_includes $src
-cat $src $all_includes | grep -v '^include' > $dest
-echo "$1: $all_includes" > $dep
+cat $src $all_includes | grep -v '^include'
+echo "$target: $all_includes" > $dep
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 9059bfd9f1..fd063a2aae 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -10531,14 +10531,25 @@ static void gen_rdhwr(DisasContext *ctx, int rt, int rd)
tcg_temp_free(t0);
}
+static inline void clear_branch_hflags(DisasContext *ctx)
+{
+ ctx->hflags &= ~MIPS_HFLAG_BMASK;
+ if (ctx->bstate == BS_NONE) {
+ save_cpu_state(ctx, 0);
+ } else {
+ /* it is not safe to save ctx->hflags as hflags may be changed
+ in execution time by the instruction in delay / forbidden slot. */
+ tcg_gen_andi_i32(hflags, hflags, ~MIPS_HFLAG_BMASK);
+ }
+}
+
static void gen_branch(DisasContext *ctx, int insn_bytes)
{
if (ctx->hflags & MIPS_HFLAG_BMASK) {
int proc_hflags = ctx->hflags & MIPS_HFLAG_BMASK;
/* Branches completion */
- ctx->hflags &= ~MIPS_HFLAG_BMASK;
+ clear_branch_hflags(ctx);
ctx->bstate = BS_BRANCH;
- save_cpu_state(ctx, 0);
/* FIXME: Need to clear can_do_io. */
switch (proc_hflags & MIPS_HFLAG_BMASK_BASE) {
case MIPS_HFLAG_FBNSLOT:
@@ -10596,8 +10607,8 @@ static void gen_branch(DisasContext *ctx, int insn_bytes)
tcg_gen_exit_tb(0);
break;
default:
- MIPS_DEBUG("unknown branch");
- break;
+ fprintf(stderr, "unknown branch 0x%x\n", proc_hflags);
+ abort();
}
}
}
@@ -18403,12 +18414,14 @@ static void gen_msa(CPUMIPSState *env, DisasContext *ctx)
case OPC_LD_H:
case OPC_LD_W:
case OPC_LD_D:
+ save_cpu_state(ctx, 1);
gen_helper_msa_ld_df(cpu_env, tdf, twd, trs, ts10);
break;
case OPC_ST_B:
case OPC_ST_H:
case OPC_ST_W:
case OPC_ST_D:
+ save_cpu_state(ctx, 1);
gen_helper_msa_st_df(cpu_env, tdf, twd, trs, ts10);
break;
}
@@ -18438,6 +18451,7 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx)
if (ctx->pc & 0x3) {
env->CP0_BadVAddr = ctx->pc;
generate_exception_err(ctx, EXCP_AdEL, EXCP_INST_NOTAVAIL);
+ ctx->bstate = BS_STOP;
return;
}
diff --git a/ui/vnc-auth-vencrypt.c b/ui/vnc-auth-vencrypt.c
index bc7032e695..a420ccbd1d 100644
--- a/ui/vnc-auth-vencrypt.c
+++ b/ui/vnc-auth-vencrypt.c
@@ -93,7 +93,6 @@ static int vnc_start_vencrypt_handshake(struct VncState *vs) {
}
VNC_DEBUG("Handshake done, switching to TLS data mode\n");
- vs->tls.wiremode = VNC_WIREMODE_TLS;
qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
start_auth_vencrypt_subauth(vs);
diff --git a/ui/vnc-tls.c b/ui/vnc-tls.c
index 0f59f9b28e..eddd39b08e 100644
--- a/ui/vnc-tls.c
+++ b/ui/vnc-tls.c
@@ -334,82 +334,77 @@ static int vnc_set_gnutls_priority(gnutls_session_t s, int x509)
int vnc_tls_client_setup(struct VncState *vs,
int needX509Creds) {
- VncStateTLS *tls;
-
VNC_DEBUG("Do TLS setup\n");
-#ifdef CONFIG_VNC_WS
- if (vs->websocket) {
- tls = &vs->ws_tls;
- } else
-#endif /* CONFIG_VNC_WS */
- {
- tls = &vs->tls;
- }
if (vnc_tls_initialize() < 0) {
VNC_DEBUG("Failed to init TLS\n");
vnc_client_error(vs);
return -1;
}
- if (tls->session == NULL) {
- if (gnutls_init(&tls->session, GNUTLS_SERVER) < 0) {
+ if (vs->tls.session == NULL) {
+ if (gnutls_init(&vs->tls.session, GNUTLS_SERVER) < 0) {
vnc_client_error(vs);
return -1;
}
- if (gnutls_set_default_priority(tls->session) < 0) {
- gnutls_deinit(tls->session);
- tls->session = NULL;
+ if (gnutls_set_default_priority(vs->tls.session) < 0) {
+ gnutls_deinit(vs->tls.session);
+ vs->tls.session = NULL;
vnc_client_error(vs);
return -1;
}
- if (vnc_set_gnutls_priority(tls->session, needX509Creds) < 0) {
- gnutls_deinit(tls->session);
- tls->session = NULL;
+ if (vnc_set_gnutls_priority(vs->tls.session, needX509Creds) < 0) {
+ gnutls_deinit(vs->tls.session);
+ vs->tls.session = NULL;
vnc_client_error(vs);
return -1;
}
if (needX509Creds) {
- gnutls_certificate_server_credentials x509_cred = vnc_tls_initialize_x509_cred(vs->vd);
+ gnutls_certificate_server_credentials x509_cred =
+ vnc_tls_initialize_x509_cred(vs->vd);
if (!x509_cred) {
- gnutls_deinit(tls->session);
- tls->session = NULL;
+ gnutls_deinit(vs->tls.session);
+ vs->tls.session = NULL;
vnc_client_error(vs);
return -1;
}
- if (gnutls_credentials_set(tls->session, GNUTLS_CRD_CERTIFICATE, x509_cred) < 0) {
- gnutls_deinit(tls->session);
- tls->session = NULL;
+ if (gnutls_credentials_set(vs->tls.session,
+ GNUTLS_CRD_CERTIFICATE, x509_cred) < 0) {
+ gnutls_deinit(vs->tls.session);
+ vs->tls.session = NULL;
gnutls_certificate_free_credentials(x509_cred);
vnc_client_error(vs);
return -1;
}
if (vs->vd->tls.x509verify) {
VNC_DEBUG("Requesting a client certificate\n");
- gnutls_certificate_server_set_request (tls->session, GNUTLS_CERT_REQUEST);
+ gnutls_certificate_server_set_request(vs->tls.session,
+ GNUTLS_CERT_REQUEST);
}
} else {
- gnutls_anon_server_credentials_t anon_cred = vnc_tls_initialize_anon_cred();
+ gnutls_anon_server_credentials_t anon_cred =
+ vnc_tls_initialize_anon_cred();
if (!anon_cred) {
- gnutls_deinit(tls->session);
- tls->session = NULL;
+ gnutls_deinit(vs->tls.session);
+ vs->tls.session = NULL;
vnc_client_error(vs);
return -1;
}
- if (gnutls_credentials_set(tls->session, GNUTLS_CRD_ANON, anon_cred) < 0) {
- gnutls_deinit(tls->session);
- tls->session = NULL;
+ if (gnutls_credentials_set(vs->tls.session,
+ GNUTLS_CRD_ANON, anon_cred) < 0) {
+ gnutls_deinit(vs->tls.session);
+ vs->tls.session = NULL;
gnutls_anon_free_server_credentials(anon_cred);
vnc_client_error(vs);
return -1;
}
}
- gnutls_transport_set_ptr(tls->session, (gnutls_transport_ptr_t)vs);
- gnutls_transport_set_push_function(tls->session, vnc_tls_push);
- gnutls_transport_set_pull_function(tls->session, vnc_tls_pull);
+ gnutls_transport_set_ptr(vs->tls.session, (gnutls_transport_ptr_t)vs);
+ gnutls_transport_set_push_function(vs->tls.session, vnc_tls_push);
+ gnutls_transport_set_pull_function(vs->tls.session, vnc_tls_pull);
}
return 0;
}
@@ -421,16 +416,7 @@ void vnc_tls_client_cleanup(struct VncState *vs)
gnutls_deinit(vs->tls.session);
vs->tls.session = NULL;
}
- vs->tls.wiremode = VNC_WIREMODE_CLEAR;
g_free(vs->tls.dname);
-#ifdef CONFIG_VNC_WS
- if (vs->ws_tls.session) {
- gnutls_deinit(vs->ws_tls.session);
- vs->ws_tls.session = NULL;
- }
- vs->ws_tls.wiremode = VNC_WIREMODE_CLEAR;
- g_free(vs->ws_tls.dname);
-#endif /* CONFIG_VNC_WS */
}
diff --git a/ui/vnc-tls.h b/ui/vnc-tls.h
index 36a2227fec..f9829c7824 100644
--- a/ui/vnc-tls.h
+++ b/ui/vnc-tls.h
@@ -33,11 +33,6 @@
#include "qemu/acl.h"
-enum {
- VNC_WIREMODE_CLEAR,
- VNC_WIREMODE_TLS,
-};
-
typedef struct VncDisplayTLS VncDisplayTLS;
typedef struct VncStateTLS VncStateTLS;
@@ -55,8 +50,6 @@ struct VncDisplayTLS {
/* Per client state */
struct VncStateTLS {
- /* Whether data is being TLS encrypted yet */
- int wiremode;
gnutls_session_t session;
/* Client's Distinguished Name from the x509 cert */
diff --git a/ui/vnc-ws.c b/ui/vnc-ws.c
index d75950d7b1..85dbb7e6ae 100644
--- a/ui/vnc-ws.c
+++ b/ui/vnc-ws.c
@@ -24,16 +24,14 @@
#ifdef CONFIG_VNC_TLS
#include "qemu/sockets.h"
-static void vncws_tls_handshake_io(void *opaque);
-
static int vncws_start_tls_handshake(struct VncState *vs)
{
- int ret = gnutls_handshake(vs->ws_tls.session);
+ int ret = gnutls_handshake(vs->tls.session);
if (ret < 0) {
if (!gnutls_error_is_fatal(ret)) {
VNC_DEBUG("Handshake interrupted (blocking)\n");
- if (!gnutls_record_get_direction(vs->ws_tls.session)) {
+ if (!gnutls_record_get_direction(vs->tls.session)) {
qemu_set_fd_handler(vs->csock, vncws_tls_handshake_io,
NULL, vs);
} else {
@@ -47,40 +45,34 @@ static int vncws_start_tls_handshake(struct VncState *vs)
return -1;
}
+ if (vs->vd->tls.x509verify) {
+ if (vnc_tls_validate_certificate(vs) < 0) {
+ VNC_DEBUG("Client verification failed\n");
+ vnc_client_error(vs);
+ return -1;
+ } else {
+ VNC_DEBUG("Client verification passed\n");
+ }
+ }
+
VNC_DEBUG("Handshake done, switching to TLS data mode\n");
- vs->ws_tls.wiremode = VNC_WIREMODE_TLS;
qemu_set_fd_handler2(vs->csock, NULL, vncws_handshake_read, NULL, vs);
return 0;
}
-static void vncws_tls_handshake_io(void *opaque)
+void vncws_tls_handshake_io(void *opaque)
{
struct VncState *vs = (struct VncState *)opaque;
- VNC_DEBUG("Handshake IO continue\n");
- vncws_start_tls_handshake(vs);
-}
-
-void vncws_tls_handshake_peek(void *opaque)
-{
- VncState *vs = opaque;
- long ret;
-
- if (!vs->ws_tls.session) {
- char peek[4];
- ret = qemu_recv(vs->csock, peek, sizeof(peek), MSG_PEEK);
- if (ret && (strncmp(peek, "\x16", 1) == 0
- || strncmp(peek, "\x80", 1) == 0)) {
- VNC_DEBUG("TLS Websocket connection recognized");
- vnc_tls_client_setup(vs, 1);
- vncws_start_tls_handshake(vs);
- } else {
- vncws_handshake_read(vs);
+ if (!vs->tls.session) {
+ VNC_DEBUG("TLS Websocket setup\n");
+ if (vnc_tls_client_setup(vs, vs->vd->tls.x509cert != NULL) < 0) {
+ return;
}
- } else {
- qemu_set_fd_handler2(vs->csock, NULL, vncws_handshake_read, NULL, vs);
}
+ VNC_DEBUG("Handshake IO continue\n");
+ vncws_start_tls_handshake(vs);
}
#endif /* CONFIG_VNC_TLS */
diff --git a/ui/vnc-ws.h b/ui/vnc-ws.h
index 95c1b0aeae..ef229b7c0c 100644
--- a/ui/vnc-ws.h
+++ b/ui/vnc-ws.h
@@ -75,7 +75,7 @@ enum {
};
#ifdef CONFIG_VNC_TLS
-void vncws_tls_handshake_peek(void *opaque);
+void vncws_tls_handshake_io(void *opaque);
#endif /* CONFIG_VNC_TLS */
void vncws_handshake_read(void *opaque);
long vnc_client_write_ws(VncState *vs);
diff --git a/ui/vnc.c b/ui/vnc.c
index 6f9b718814..cffb5b74b3 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -1343,15 +1343,8 @@ long vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen)
if (vs->tls.session) {
ret = vnc_client_write_tls(&vs->tls.session, data, datalen);
} else {
-#ifdef CONFIG_VNC_WS
- if (vs->ws_tls.session) {
- ret = vnc_client_write_tls(&vs->ws_tls.session, data, datalen);
- } else
-#endif /* CONFIG_VNC_WS */
#endif /* CONFIG_VNC_TLS */
- {
- ret = send(vs->csock, (const void *)data, datalen, 0);
- }
+ ret = send(vs->csock, (const void *)data, datalen, 0);
#ifdef CONFIG_VNC_TLS
}
#endif /* CONFIG_VNC_TLS */
@@ -1491,15 +1484,8 @@ long vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen)
if (vs->tls.session) {
ret = vnc_client_read_tls(&vs->tls.session, data, datalen);
} else {
-#ifdef CONFIG_VNC_WS
- if (vs->ws_tls.session) {
- ret = vnc_client_read_tls(&vs->ws_tls.session, data, datalen);
- } else
-#endif /* CONFIG_VNC_WS */
#endif /* CONFIG_VNC_TLS */
- {
- ret = qemu_recv(vs->csock, data, datalen, 0);
- }
+ ret = qemu_recv(vs->csock, data, datalen, 0);
#ifdef CONFIG_VNC_TLS
}
#endif /* CONFIG_VNC_TLS */
@@ -2400,34 +2386,34 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
case 4: vs->as.fmt = AUD_FMT_U32; break;
case 5: vs->as.fmt = AUD_FMT_S32; break;
default:
- printf("Invalid audio format %d\n", read_u8(data, 4));
+ VNC_DEBUG("Invalid audio format %d\n", read_u8(data, 4));
vnc_client_error(vs);
break;
}
vs->as.nchannels = read_u8(data, 5);
if (vs->as.nchannels != 1 && vs->as.nchannels != 2) {
- printf("Invalid audio channel coount %d\n",
- read_u8(data, 5));
+ VNC_DEBUG("Invalid audio channel coount %d\n",
+ read_u8(data, 5));
vnc_client_error(vs);
break;
}
vs->as.freq = read_u32(data, 6);
break;
default:
- printf ("Invalid audio message %d\n", read_u8(data, 4));
+ VNC_DEBUG("Invalid audio message %d\n", read_u8(data, 4));
vnc_client_error(vs);
break;
}
break;
default:
- printf("Msg: %d\n", read_u16(data, 0));
+ VNC_DEBUG("Msg: %d\n", read_u16(data, 0));
vnc_client_error(vs);
break;
}
break;
default:
- printf("Msg: %d\n", data[0]);
+ VNC_DEBUG("Msg: %d\n", data[0]);
vnc_client_error(vs);
break;
}
@@ -3010,15 +2996,18 @@ static void vnc_connect(VncDisplay *vd, int csock,
if (skipauth) {
vs->auth = VNC_AUTH_NONE;
-#ifdef CONFIG_VNC_TLS
vs->subauth = VNC_AUTH_INVALID;
-#endif
} else {
- vs->auth = vd->auth;
-#ifdef CONFIG_VNC_TLS
- vs->subauth = vd->subauth;
-#endif
+ if (websocket) {
+ vs->auth = vd->ws_auth;
+ vs->subauth = VNC_AUTH_INVALID;
+ } else {
+ vs->auth = vd->auth;
+ vs->subauth = vd->subauth;
+ }
}
+ VNC_DEBUG("Client sock=%d ws=%d auth=%d subauth=%d\n",
+ csock, websocket, vs->auth, vs->subauth);
vs->lossy_rect = g_malloc0(VNC_STAT_ROWS * sizeof (*vs->lossy_rect));
for (i = 0; i < VNC_STAT_ROWS; ++i) {
@@ -3032,8 +3021,8 @@ static void vnc_connect(VncDisplay *vd, int csock,
if (websocket) {
vs->websocket = 1;
#ifdef CONFIG_VNC_TLS
- if (vd->tls.x509cert) {
- qemu_set_fd_handler2(vs->csock, NULL, vncws_tls_handshake_peek,
+ if (vd->ws_tls) {
+ qemu_set_fd_handler2(vs->csock, NULL, vncws_tls_handshake_io,
NULL, vs);
} else
#endif /* CONFIG_VNC_TLS */
@@ -3206,8 +3195,8 @@ static void vnc_display_close(VncDisplay *vs)
}
#endif /* CONFIG_VNC_WS */
vs->auth = VNC_AUTH_INVALID;
-#ifdef CONFIG_VNC_TLS
vs->subauth = VNC_AUTH_INVALID;
+#ifdef CONFIG_VNC_TLS
vs->tls.x509verify = 0;
#endif
}
@@ -3318,6 +3307,134 @@ static QemuOptsList qemu_vnc_opts = {
},
};
+
+static void
+vnc_display_setup_auth(VncDisplay *vs,
+ bool password,
+ bool sasl,
+ bool tls,
+ bool x509,
+ bool websocket)
+{
+ /*
+ * We have a choice of 3 authentication options
+ *
+ * 1. none
+ * 2. vnc
+ * 3. sasl
+ *
+ * The channel can be run in 2 modes
+ *
+ * 1. clear
+ * 2. tls
+ *
+ * And TLS can use 2 types of credentials
+ *
+ * 1. anon
+ * 2. x509
+ *
+ * We thus have 9 possible logical combinations
+ *
+ * 1. clear + none
+ * 2. clear + vnc
+ * 3. clear + sasl
+ * 4. tls + anon + none
+ * 5. tls + anon + vnc
+ * 6. tls + anon + sasl
+ * 7. tls + x509 + none
+ * 8. tls + x509 + vnc
+ * 9. tls + x509 + sasl
+ *
+ * These need to be mapped into the VNC auth schemes
+ * in an appropriate manner. In regular VNC, all the
+ * TLS options get mapped into VNC_AUTH_VENCRYPT
+ * sub-auth types.
+ *
+ * In websockets, the https:// protocol already provides
+ * TLS support, so there is no need to make use of the
+ * VeNCrypt extension. Furthermore, websockets browser
+ * clients could not use VeNCrypt even if they wanted to,
+ * as they cannot control when the TLS handshake takes
+ * place. Thus there is no option but to rely on https://,
+ * meaning combinations 4->6 and 7->9 will be mapped to
+ * VNC auth schemes in the same way as combos 1->3.
+ *
+ * Regardless of fact that we have a different mapping to
+ * VNC auth mechs for plain VNC vs websockets VNC, the end
+ * result has the same security characteristics.
+ */
+ if (password) {
+ if (tls) {
+ vs->auth = VNC_AUTH_VENCRYPT;
+ if (websocket) {
+ vs->ws_tls = true;
+ }
+ if (x509) {
+ VNC_DEBUG("Initializing VNC server with x509 password auth\n");
+ vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
+ } else {
+ VNC_DEBUG("Initializing VNC server with TLS password auth\n");
+ vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
+ }
+ } else {
+ VNC_DEBUG("Initializing VNC server with password auth\n");
+ vs->auth = VNC_AUTH_VNC;
+ vs->subauth = VNC_AUTH_INVALID;
+ }
+ if (websocket) {
+ vs->ws_auth = VNC_AUTH_VNC;
+ } else {
+ vs->ws_auth = VNC_AUTH_INVALID;
+ }
+ } else if (sasl) {
+ if (tls) {
+ vs->auth = VNC_AUTH_VENCRYPT;
+ if (websocket) {
+ vs->ws_tls = true;
+ }
+ if (x509) {
+ VNC_DEBUG("Initializing VNC server with x509 SASL auth\n");
+ vs->subauth = VNC_AUTH_VENCRYPT_X509SASL;
+ } else {
+ VNC_DEBUG("Initializing VNC server with TLS SASL auth\n");
+ vs->subauth = VNC_AUTH_VENCRYPT_TLSSASL;
+ }
+ } else {
+ VNC_DEBUG("Initializing VNC server with SASL auth\n");
+ vs->auth = VNC_AUTH_SASL;
+ vs->subauth = VNC_AUTH_INVALID;
+ }
+ if (websocket) {
+ vs->ws_auth = VNC_AUTH_SASL;
+ } else {
+ vs->ws_auth = VNC_AUTH_INVALID;
+ }
+ } else {
+ if (tls) {
+ vs->auth = VNC_AUTH_VENCRYPT;
+ if (websocket) {
+ vs->ws_tls = true;
+ }
+ if (x509) {
+ VNC_DEBUG("Initializing VNC server with x509 no auth\n");
+ vs->subauth = VNC_AUTH_VENCRYPT_X509NONE;
+ } else {
+ VNC_DEBUG("Initializing VNC server with TLS no auth\n");
+ vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE;
+ }
+ } else {
+ VNC_DEBUG("Initializing VNC server with no auth\n");
+ vs->auth = VNC_AUTH_NONE;
+ vs->subauth = VNC_AUTH_INVALID;
+ }
+ if (websocket) {
+ vs->ws_auth = VNC_AUTH_NONE;
+ } else {
+ vs->ws_auth = VNC_AUTH_INVALID;
+ }
+ }
+}
+
void vnc_display_open(const char *id, Error **errp)
{
VncDisplay *vs = vnc_display_find(id);
@@ -3332,15 +3449,13 @@ void vnc_display_open(const char *id, Error **errp)
char *h;
bool has_ipv4 = false;
bool has_ipv6 = false;
-#ifdef CONFIG_VNC_WS
const char *websocket;
-#endif
-#ifdef CONFIG_VNC_TLS
bool tls = false, x509 = false;
+#ifdef CONFIG_VNC_TLS
const char *path;
#endif
-#ifdef CONFIG_VNC_SASL
bool sasl = false;
+#ifdef CONFIG_VNC_SASL
int saslErr;
#endif
#if defined(CONFIG_VNC_TLS) || defined(CONFIG_VNC_SASL)
@@ -3404,11 +3519,15 @@ void vnc_display_open(const char *id, Error **errp)
reverse = qemu_opt_get_bool(opts, "reverse", false);
lock_key_sync = qemu_opt_get_bool(opts, "lock-key-sync", true);
-#ifdef CONFIG_VNC_SASL
sasl = qemu_opt_get_bool(opts, "sasl", false);
-#endif
-#ifdef CONFIG_VNC_TLS
+#ifndef CONFIG_VNC_SASL
+ if (sasl) {
+ error_setg(errp, "VNC SASL auth requires cyrus-sasl support");
+ goto fail;
+ }
+#endif /* CONFIG_VNC_SASL */
tls = qemu_opt_get_bool(opts, "tls", false);
+#ifdef CONFIG_VNC_TLS
path = qemu_opt_get(opts, "x509");
if (!path) {
path = qemu_opt_get(opts, "x509verify");
@@ -3424,7 +3543,12 @@ void vnc_display_open(const char *id, Error **errp)
goto fail;
}
}
-#endif
+#else /* ! CONFIG_VNC_TLS */
+ if (tls) {
+ error_setg(errp, "VNC TLS auth requires gnutls support");
+ goto fail;
+ }
+#endif /* ! CONFIG_VNC_TLS */
#if defined(CONFIG_VNC_TLS) || defined(CONFIG_VNC_SASL)
acl = qemu_opt_get_bool(opts, "acl", false);
#endif
@@ -3446,14 +3570,16 @@ void vnc_display_open(const char *id, Error **errp)
}
vs->connections_limit = qemu_opt_get_number(opts, "connections", 32);
- #ifdef CONFIG_VNC_WS
websocket = qemu_opt_get(opts, "websocket");
if (websocket) {
+#ifdef CONFIG_VNC_WS
vs->ws_enabled = true;
qemu_opt_set(wsopts, "port", websocket, &error_abort);
-
+#else /* ! CONFIG_VNC_WS */
+ error_setg(errp, "Websockets protocol requires gnutls support");
+ goto fail;
+#endif /* ! CONFIG_VNC_WS */
}
-#endif /* CONFIG_VNC_WS */
#ifdef CONFIG_VNC_JPEG
vs->lossy = qemu_opt_get_bool(opts, "lossy", false);
@@ -3501,82 +3627,7 @@ void vnc_display_open(const char *id, Error **errp)
}
#endif
- /*
- * Combinations we support here:
- *
- * - no-auth (clear text, no auth)
- * - password (clear text, weak auth)
- * - sasl (encrypt, good auth *IF* using Kerberos via GSSAPI)
- * - tls (encrypt, weak anonymous creds, no auth)
- * - tls + password (encrypt, weak anonymous creds, weak auth)
- * - tls + sasl (encrypt, weak anonymous creds, good auth)
- * - tls + x509 (encrypt, good x509 creds, no auth)
- * - tls + x509 + password (encrypt, good x509 creds, weak auth)
- * - tls + x509 + sasl (encrypt, good x509 creds, good auth)
- *
- * NB1. TLS is a stackable auth scheme.
- * NB2. the x509 schemes have option to validate a client cert dname
- */
- if (password) {
-#ifdef CONFIG_VNC_TLS
- if (tls) {
- vs->auth = VNC_AUTH_VENCRYPT;
- if (x509) {
- VNC_DEBUG("Initializing VNC server with x509 password auth\n");
- vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
- } else {
- VNC_DEBUG("Initializing VNC server with TLS password auth\n");
- vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
- }
- } else {
-#endif /* CONFIG_VNC_TLS */
- VNC_DEBUG("Initializing VNC server with password auth\n");
- vs->auth = VNC_AUTH_VNC;
-#ifdef CONFIG_VNC_TLS
- vs->subauth = VNC_AUTH_INVALID;
- }
-#endif /* CONFIG_VNC_TLS */
-#ifdef CONFIG_VNC_SASL
- } else if (sasl) {
-#ifdef CONFIG_VNC_TLS
- if (tls) {
- vs->auth = VNC_AUTH_VENCRYPT;
- if (x509) {
- VNC_DEBUG("Initializing VNC server with x509 SASL auth\n");
- vs->subauth = VNC_AUTH_VENCRYPT_X509SASL;
- } else {
- VNC_DEBUG("Initializing VNC server with TLS SASL auth\n");
- vs->subauth = VNC_AUTH_VENCRYPT_TLSSASL;
- }
- } else {
-#endif /* CONFIG_VNC_TLS */
- VNC_DEBUG("Initializing VNC server with SASL auth\n");
- vs->auth = VNC_AUTH_SASL;
-#ifdef CONFIG_VNC_TLS
- vs->subauth = VNC_AUTH_INVALID;
- }
-#endif /* CONFIG_VNC_TLS */
-#endif /* CONFIG_VNC_SASL */
- } else {
-#ifdef CONFIG_VNC_TLS
- if (tls) {
- vs->auth = VNC_AUTH_VENCRYPT;
- if (x509) {
- VNC_DEBUG("Initializing VNC server with x509 no auth\n");
- vs->subauth = VNC_AUTH_VENCRYPT_X509NONE;
- } else {
- VNC_DEBUG("Initializing VNC server with TLS no auth\n");
- vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE;
- }
- } else {
-#endif
- VNC_DEBUG("Initializing VNC server with no auth\n");
- vs->auth = VNC_AUTH_NONE;
-#ifdef CONFIG_VNC_TLS
- vs->subauth = VNC_AUTH_INVALID;
- }
-#endif
- }
+ vnc_display_setup_auth(vs, password, sasl, tls, x509, websocket);
#ifdef CONFIG_VNC_SASL
if ((saslErr = sasl_server_init(NULL, "qemu")) != SASL_OK) {
@@ -3594,7 +3645,7 @@ void vnc_display_open(const char *id, Error **errp)
dev = qdev_find_recursive(sysbus_get_default(), device_id);
if (dev == NULL) {
- error_set(errp, QERR_DEVICE_NOT_FOUND, device_id);
+ error_setg(errp, "Device '%s' not found", device_id);
goto fail;
}
diff --git a/ui/vnc.h b/ui/vnc.h
index 66a02986c7..e19ac396f2 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -180,10 +180,12 @@ struct VncDisplay
char *password;
time_t expires;
int auth;
+ int subauth; /* Used by VeNCrypt */
+ int ws_auth; /* Used by websockets */
+ bool ws_tls; /* Used by websockets */
bool lossy;
bool non_adaptive;
#ifdef CONFIG_VNC_TLS
- int subauth; /* Used by VeNCrypt */
VncDisplayTLS tls;
#endif
#ifdef CONFIG_VNC_SASL
@@ -284,18 +286,15 @@ struct VncState
int minor;
int auth;
+ int subauth; /* Used by VeNCrypt */
char challenge[VNC_AUTH_CHALLENGE_SIZE];
#ifdef CONFIG_VNC_TLS
- int subauth; /* Used by VeNCrypt */
VncStateTLS tls;
#endif
#ifdef CONFIG_VNC_SASL
VncStateSASL sasl;
#endif
#ifdef CONFIG_VNC_WS
-#ifdef CONFIG_VNC_TLS
- VncStateTLS ws_tls;
-#endif /* CONFIG_VNC_TLS */
bool encode_ws;
bool websocket;
#endif /* CONFIG_VNC_WS */
diff --git a/util/uri.c b/util/uri.c
index 1cfd78bdb5..550b984587 100644
--- a/util/uri.c
+++ b/util/uri.c
@@ -320,19 +320,23 @@ static int
rfc3986_parse_port(URI *uri, const char **str)
{
const char *cur = *str;
+ int port = 0;
if (ISA_DIGIT(cur)) {
- if (uri != NULL)
- uri->port = 0;
- while (ISA_DIGIT(cur)) {
- if (uri != NULL)
- uri->port = uri->port * 10 + (*cur - '0');
- cur++;
- }
- *str = cur;
- return(0);
+ while (ISA_DIGIT(cur)) {
+ port = port * 10 + (*cur - '0');
+ if (port > 65535) {
+ return 1;
+ }
+ cur++;
+ }
+ if (uri) {
+ uri->port = port;
+ }
+ *str = cur;
+ return 0;
}
- return(1);
+ return 1;
}
/**