Merge tag 'misc-fixes-pull-request' of https://gitlab.com/berrange/qemu into staging
* Update security triage contact address
* Check and honour failures to the blocking flag on FDs
* Don't touch blocking flags on FDs received during migration
# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEE2vOm/bJrYpEtDo4/vobrtBUQT98FAmjNQuAACgkQvobrtBUQ
# T99xaBAAr6zQPii1tjzuzLovF6MIqtldXnmVO/yjcl5NgLWonIRDt2JsxnRxi3es
# 9uNDed5+ePNXmUAYd46k81gBEjBWbv465kt5FHAZZV6BRw/PPzkoh+jzGc8NVir8
# 3GZJ2kPr51PxGEl8md2vRthg4bMuhlS5ogCEqAMDYT4f6AVemfnNQ5NttGX353T2
# etxoMhEeMtTBKjMoTBv+SVhhO4nKwZ+6CFhvuGON423EfrGlkNTXyprKTdzpr4i0
# 4KDQLxxoANlmg/1W0PxfrLiBCmGpHweMR44Piv715VYa2YNPRq0G6EC6AFGbHZ51
# N+mKmWNE0CS5rP1TEacSCX4q6If5VxjSLLj+og8LmpIlJ6tiqdrisSqA6bzCJ1f/
# lMsfUsKoMqPhqat9ZGUkYu8REgKP+O+CSGJNftYTsEEY0oKZrAW4fsoN3E9qpfcG
# Xy6eSu0TTGDWE6CEe0vkHiQwlVHMtRcWMSPwlsvrgt2TO6k97reT3AoIBK2VfygC
# WzMv0P0nBvHFKeIbqmFOk3BEI5+JECgxVRc1WXWbSFLW0PBY/xd7g6ow8uaQsd9e
# pzMA1Pwh2EuM4DTlOy+m9zBOhm9YP9An188NLldOne3TFKFYe5QO1DQpvvEGvIGB
# +4XpmyOj3g2ycelZZ5XsDJk0LumCCOcbSPSiAvHZyWwLo24EABE=
# =rrMd
# -----END PGP SIGNATURE-----
# gpg: Signature made Fri 19 Sep 2025 04:47:44 AM PDT
# gpg: using RSA key DAF3A6FDB26B62912D0E8E3FBE86EBB415104FDF
# gpg: Good signature from "Daniel P. Berrange <dan@berrange.com>" [unknown]
# gpg: aka "Daniel P. Berrange <berrange@redhat.com>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg: There is no indication that the signature belongs to the owner.
# Primary key fingerprint: DAF3 A6FD B26B 6291 2D0E 8E3F BE86 EBB4 1510 4FDF
* tag 'misc-fixes-pull-request' of https://gitlab.com/berrange/qemu:
util/vhost-user-server: vu_message_read(): improve error handling
chardev: close an fd on failure path
chardev: qemu_chr_open_fd(): add errp
treewide: use qemu_set_blocking instead of g_unix_set_fd_nonblocking
util: drop qemu_socket_set_block()
io/channel-socket: rework qio_channel_socket_copy_fds()
util: drop qemu_socket_try_set_nonblock()
util: drop qemu_socket_set_nonblock()
migration: qemu_file_set_blocking(): add errp parameter
treewide: handle result of qio_channel_set_blocking()
util: add qemu_set_blocking() function
char-socket: tcp_chr_recv(): add comment
char-socket: tcp_chr_recv(): drop extra _set_(block,cloexec)
io/channel: document how qio_channel_readv_full() handles fds
migration/qemu-file: don't make incoming fds blocking again
MAINTAINERS: list qemu-security@nongnu.org as security contact
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
diff --git a/MAINTAINERS b/MAINTAINERS
index bd417e9..70eb024 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -85,7 +85,7 @@
-------------------------------------------------
W: https://wiki.qemu.org/SecurityProcess
M: Michael S. Tsirkin <mst@redhat.com>
-L: secalert@redhat.com
+L: qemu-security@nongnu.org
Trivial patches
---------------
diff --git a/block/nbd.c b/block/nbd.c
index d5a2b21..5d231d5 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -351,7 +351,9 @@
return ret;
}
- qio_channel_set_blocking(s->ioc, false, NULL);
+ if (!qio_channel_set_blocking(s->ioc, false, errp)) {
+ return -EINVAL;
+ }
qio_channel_set_follow_coroutine_ctx(s->ioc, true);
/* successfully connected */
diff --git a/chardev/char-fd.c b/chardev/char-fd.c
index 6f03adf..4ee286f 100644
--- a/chardev/char-fd.c
+++ b/chardev/char-fd.c
@@ -206,14 +206,16 @@
}
/* open a character device to a unix fd */
-void qemu_chr_open_fd(Chardev *chr,
- int fd_in, int fd_out)
+bool qemu_chr_open_fd(Chardev *chr,
+ int fd_in, int fd_out, Error **errp)
{
FDChardev *s = FD_CHARDEV(chr);
g_autofree char *name = NULL;
- if (fd_out >= 0 && !g_unix_set_fd_nonblocking(fd_out, true, NULL)) {
- assert(!"Failed to set FD nonblocking");
+ if (fd_out >= 0) {
+ if (!qemu_set_blocking(fd_out, false, errp)) {
+ return false;
+ }
}
if (fd_out == fd_in && fd_in >= 0) {
@@ -221,7 +223,7 @@
name = g_strdup_printf("chardev-file-%s", chr->label);
qio_channel_set_name(QIO_CHANNEL(s->ioc_in), name);
s->ioc_out = QIO_CHANNEL(object_ref(s->ioc_in));
- return;
+ return true;
}
if (fd_in >= 0) {
@@ -236,6 +238,8 @@
name = g_strdup_printf("chardev-file-out-%s", chr->label);
qio_channel_set_name(QIO_CHANNEL(s->ioc_out), name);
}
+
+ return true;
}
static void char_fd_class_init(ObjectClass *oc, const void *data)
diff --git a/chardev/char-file.c b/chardev/char-file.c
index a9e8c5e..89e9cb8 100644
--- a/chardev/char-file.c
+++ b/chardev/char-file.c
@@ -92,7 +92,11 @@
}
}
- qemu_chr_open_fd(chr, in, out);
+ if (!qemu_chr_open_fd(chr, in, out, errp)) {
+ qemu_close(out);
+ qemu_close(in);
+ return;
+ }
#endif
}
diff --git a/chardev/char-pipe.c b/chardev/char-pipe.c
index 3d1b0ce..e9f3bb8 100644
--- a/chardev/char-pipe.c
+++ b/chardev/char-pipe.c
@@ -150,7 +150,14 @@
return;
}
}
- qemu_chr_open_fd(chr, fd_in, fd_out);
+
+ if (!qemu_chr_open_fd(chr, fd_in, fd_out, errp)) {
+ close(fd_in);
+ if (fd_out != fd_in) {
+ close(fd_out);
+ }
+ return;
+ }
}
#endif /* !_WIN32 */
diff --git a/chardev/char-pty.c b/chardev/char-pty.c
index 674e9b3..b066f01 100644
--- a/chardev/char-pty.c
+++ b/chardev/char-pty.c
@@ -349,8 +349,8 @@
}
close(slave_fd);
- if (!g_unix_set_fd_nonblocking(master_fd, true, NULL)) {
- error_setg_errno(errp, errno, "Failed to set FD nonblocking");
+ if (!qemu_set_blocking(master_fd, false, errp)) {
+ close(master_fd);
return;
}
diff --git a/chardev/char-serial.c b/chardev/char-serial.c
index 0a68b4b..4c6ca71 100644
--- a/chardev/char-serial.c
+++ b/chardev/char-serial.c
@@ -271,13 +271,16 @@
if (fd < 0) {
return;
}
- if (!g_unix_set_fd_nonblocking(fd, true, NULL)) {
- error_setg_errno(errp, errno, "Failed to set FD nonblocking");
+ if (!qemu_set_blocking(fd, false, errp)) {
+ close(fd);
return;
}
tty_serial_init(fd, 115200, 'N', 8, 1);
- qemu_chr_open_fd(chr, fd, fd);
+ if (!qemu_chr_open_fd(chr, fd, fd, errp)) {
+ close(fd);
+ return;
+ }
}
#endif /* __linux__ || __sun__ */
diff --git a/chardev/char-socket.c b/chardev/char-socket.c
index 1e83139..cb4ec78 100644
--- a/chardev/char-socket.c
+++ b/chardev/char-socket.c
@@ -294,7 +294,12 @@
}
if (msgfds_num) {
- /* close and clean read_msgfds */
+ /*
+ * Close and clean previous read_msgfds, they are obsolete at
+ * this point, regardless result of new call to
+ * qio_channel_readv_full().
+ */
+
for (i = 0; i < s->read_msgfds_num; i++) {
close(s->read_msgfds[i]);
}
@@ -307,20 +312,6 @@
s->read_msgfds_num = msgfds_num;
}
- for (i = 0; i < s->read_msgfds_num; i++) {
- int fd = s->read_msgfds[i];
- if (fd < 0) {
- continue;
- }
-
- /* O_NONBLOCK is preserved across SCM_RIGHTS so reset it */
- qemu_socket_set_block(fd);
-
-#ifndef MSG_CMSG_CLOEXEC
- qemu_set_cloexec(fd);
-#endif
- }
-
if (ret == QIO_CHANNEL_ERR_BLOCK) {
errno = EAGAIN;
ret = -1;
@@ -539,16 +530,24 @@
SocketChardev *s = SOCKET_CHARDEV(chr);
int size;
int saved_errno;
+ Error *local_err = NULL;
if (s->state != TCP_CHARDEV_STATE_CONNECTED) {
return 0;
}
- qio_channel_set_blocking(s->ioc, true, NULL);
+ if (!qio_channel_set_blocking(s->ioc, true, &local_err)) {
+ error_report_err(local_err);
+ return -1;
+ }
size = tcp_chr_recv(chr, (void *) buf, len);
saved_errno = errno;
if (s->state != TCP_CHARDEV_STATE_DISCONNECTED) {
- qio_channel_set_blocking(s->ioc, false, NULL);
+ if (!qio_channel_set_blocking(s->ioc, false, &local_err)) {
+ error_report_err(local_err);
+ /* failed to recover non-blocking state */
+ tcp_chr_disconnect(chr);
+ }
}
if (size == 0) {
/* connection closed */
@@ -893,18 +892,22 @@
static int tcp_chr_new_client(Chardev *chr, QIOChannelSocket *sioc)
{
SocketChardev *s = SOCKET_CHARDEV(chr);
+ Error *local_err = NULL;
if (s->state != TCP_CHARDEV_STATE_CONNECTING) {
return -1;
}
+ if (!qio_channel_set_blocking(QIO_CHANNEL(sioc), false, &local_err)) {
+ error_report_err(local_err);
+ return -1;
+ }
+
s->ioc = QIO_CHANNEL(sioc);
object_ref(OBJECT(sioc));
s->sioc = sioc;
object_ref(OBJECT(sioc));
- qio_channel_set_blocking(s->ioc, false, NULL);
-
if (s->do_nodelay) {
qio_channel_set_delay(s->ioc, false);
}
diff --git a/chardev/char-stdio.c b/chardev/char-stdio.c
index 48db8d2..2568164 100644
--- a/chardev/char-stdio.c
+++ b/chardev/char-stdio.c
@@ -107,18 +107,20 @@
old_fd0_flags = fcntl(0, F_GETFL);
old_fd1_flags = fcntl(1, F_GETFL);
tcgetattr(0, &oldtty);
- if (!g_unix_set_fd_nonblocking(0, true, NULL)) {
- error_setg_errno(errp, errno, "Failed to set FD nonblocking");
+ if (!qemu_set_blocking(0, false, errp)) {
return;
}
+
+ if (!qemu_chr_open_fd(chr, 0, 1, errp)) {
+ return;
+ }
+
atexit(term_exit);
memset(&act, 0, sizeof(act));
act.sa_handler = term_stdio_handler;
sigaction(SIGCONT, &act, NULL);
- qemu_chr_open_fd(chr, 0, 1);
-
stdio_allow_signal = !opts->has_signal || opts->signal;
qemu_chr_set_echo_stdio(chr, false);
}
diff --git a/contrib/ivshmem-server/ivshmem-server.c b/contrib/ivshmem-server/ivshmem-server.c
index 2f3c732..13cb828 100644
--- a/contrib/ivshmem-server/ivshmem-server.c
+++ b/contrib/ivshmem-server/ivshmem-server.c
@@ -6,6 +6,7 @@
* top-level directory.
*/
#include "qemu/osdep.h"
+#include "qapi/error.h"
#include "qemu/host-utils.h"
#include "qemu/sockets.h"
@@ -135,6 +136,7 @@
socklen_t unaddr_len;
int newfd;
unsigned i;
+ Error *local_err = NULL;
/* accept the incoming connection */
unaddr_len = sizeof(unaddr);
@@ -146,9 +148,14 @@
return -1;
}
- qemu_socket_set_nonblock(newfd);
IVSHMEM_SERVER_DEBUG(server, "accept()=%d\n", newfd);
+ if (!qemu_set_blocking(newfd, false, &local_err)) {
+ error_report_err(local_err);
+ close(newfd);
+ return -1;
+ }
+
/* allocate new structure for this peer */
peer = g_malloc0(sizeof(*peer));
peer->sock_fd = newfd;
diff --git a/hw/hyperv/syndbg.c b/hw/hyperv/syndbg.c
index ac7e15f..bcdfdf6 100644
--- a/hw/hyperv/syndbg.c
+++ b/hw/hyperv/syndbg.c
@@ -338,7 +338,9 @@
return;
}
- qemu_socket_set_nonblock(syndbg->socket);
+ if (!qemu_set_blocking(syndbg->socket, false, errp)) {
+ return;
+ }
syndbg->servaddr.sin_port = htons(syndbg->host_port);
syndbg->servaddr.sin_family = AF_INET;
diff --git a/hw/input/virtio-input-host.c b/hw/input/virtio-input-host.c
index bbfee9d..9f62532 100644
--- a/hw/input/virtio-input-host.c
+++ b/hw/input/virtio-input-host.c
@@ -114,8 +114,7 @@
error_setg_file_open(errp, errno, vih->evdev);
return;
}
- if (!g_unix_set_fd_nonblocking(vih->fd, true, NULL)) {
- error_setg_errno(errp, errno, "Failed to set FD nonblocking");
+ if (!qemu_set_blocking(vih->fd, false, errp)) {
goto err_close;
}
diff --git a/hw/misc/ivshmem-flat.c b/hw/misc/ivshmem-flat.c
index fe4be6b..e83e6c6 100644
--- a/hw/misc/ivshmem-flat.c
+++ b/hw/misc/ivshmem-flat.c
@@ -154,7 +154,8 @@
* peer.
*/
peer->vector[peer->vector_counter].id = peer->vector_counter;
- g_unix_set_fd_nonblocking(vector_fd, true, NULL);
+ /* WARNING: qemu_socket_set_nonblock() return code ignored */
+ qemu_set_blocking(vector_fd, false, &error_warn);
event_notifier_init_fd(&peer->vector[peer->vector_counter].event_notifier,
vector_fd);
diff --git a/hw/misc/ivshmem-pci.c b/hw/misc/ivshmem-pci.c
index d47ae73..2748db9 100644
--- a/hw/misc/ivshmem-pci.c
+++ b/hw/misc/ivshmem-pci.c
@@ -540,7 +540,12 @@
IVSHMEM_DPRINTF("eventfds[%d][%d] = %d\n", posn, vector, fd);
event_notifier_init_fd(&peer->eventfds[vector], fd);
- g_unix_set_fd_nonblocking(fd, true, NULL); /* msix/irqfd poll non block */
+
+ /* msix/irqfd poll non block */
+ if (!qemu_set_blocking(fd, false, errp)) {
+ close(fd);
+ return;
+ }
if (posn == s->vm_id) {
setup_interrupt(s, vector, errp);
diff --git a/hw/remote/proxy.c b/hw/remote/proxy.c
index b0165aa..18e0f7a 100644
--- a/hw/remote/proxy.c
+++ b/hw/remote/proxy.c
@@ -112,8 +112,12 @@
return;
}
+ if (!qio_channel_set_blocking(dev->ioc, true, errp)) {
+ object_unref(dev->ioc);
+ return;
+ }
+
qemu_mutex_init(&dev->io_mutex);
- qio_channel_set_blocking(dev->ioc, true, NULL);
pci_conf[PCI_LATENCY_TIMER] = 0xff;
pci_conf[PCI_INTERRUPT_PIN] = 0x01;
diff --git a/hw/remote/remote-obj.c b/hw/remote/remote-obj.c
index 8588290..3402068 100644
--- a/hw/remote/remote-obj.c
+++ b/hw/remote/remote-obj.c
@@ -107,7 +107,11 @@
error_report_err(err);
return;
}
- qio_channel_set_blocking(ioc, false, NULL);
+ if (!qio_channel_set_blocking(ioc, false, &err)) {
+ error_report_err(err);
+ object_unref(OBJECT(ioc));
+ return;
+ }
o->dev = dev;
diff --git a/hw/vfio-user/proxy.c b/hw/vfio-user/proxy.c
index 2c03d49..bbd7ec2 100644
--- a/hw/vfio-user/proxy.c
+++ b/hw/vfio-user/proxy.c
@@ -886,10 +886,11 @@
sioc = qio_channel_socket_new();
ioc = QIO_CHANNEL(sioc);
if (qio_channel_socket_connect_sync(sioc, addr, errp) < 0) {
- object_unref(OBJECT(ioc));
- return NULL;
+ goto fail;
}
- qio_channel_set_blocking(ioc, false, NULL);
+ if (!qio_channel_set_blocking(ioc, false, errp)) {
+ goto fail;
+ }
proxy = g_malloc0(sizeof(VFIOUserProxy));
proxy->sockname = g_strdup_printf("unix:%s", sockname);
@@ -923,6 +924,10 @@
QLIST_INSERT_HEAD(&vfio_user_sockets, proxy, next);
return proxy;
+
+fail:
+ object_unref(OBJECT(ioc));
+ return NULL;
}
void vfio_user_set_handler(VFIODevice *vbasedev,
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 1e1d6b0..36c9c2e 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -2039,7 +2039,10 @@
error_setg(errp, "%s: Failed to get ufd", __func__);
return -EIO;
}
- qemu_socket_set_nonblock(ufd);
+ if (!qemu_set_blocking(ufd, false, errp)) {
+ close(ufd);
+ return -EINVAL;
+ }
/* register ufd with userfault thread */
u->postcopy_fd.fd = ufd;
diff --git a/hw/virtio/vhost-vsock.c b/hw/virtio/vhost-vsock.c
index 6e40888..107d88b 100644
--- a/hw/virtio/vhost-vsock.c
+++ b/hw/virtio/vhost-vsock.c
@@ -147,9 +147,7 @@
return;
}
- if (!g_unix_set_fd_nonblocking(vhostfd, true, NULL)) {
- error_setg_errno(errp, errno,
- "vhost-vsock: unable to set non-blocking mode");
+ if (!qemu_set_blocking(vhostfd, false, errp)) {
return;
}
} else {
@@ -160,9 +158,7 @@
return;
}
- if (!g_unix_set_fd_nonblocking(vhostfd, true, NULL)) {
- error_setg_errno(errp, errno,
- "Failed to set FD nonblocking");
+ if (!qemu_set_blocking(vhostfd, false, errp)) {
return;
}
}
diff --git a/include/chardev/char-fd.h b/include/chardev/char-fd.h
index 9de0e44..6fe4306 100644
--- a/include/chardev/char-fd.h
+++ b/include/chardev/char-fd.h
@@ -41,7 +41,7 @@
DECLARE_INSTANCE_CHECKER(FDChardev, FD_CHARDEV,
TYPE_CHARDEV_FD)
-void qemu_chr_open_fd(Chardev *chr, int fd_in, int fd_out);
+bool qemu_chr_open_fd(Chardev *chr, int fd_in, int fd_out, Error **errp);
int qmp_chardev_open_file_source(char *src, int flags, Error **errp);
#endif /* CHAR_FD_H */
diff --git a/include/io/channel.h b/include/io/channel.h
index 234e5db..0f25ae0 100644
--- a/include/io/channel.h
+++ b/include/io/channel.h
@@ -36,6 +36,7 @@
#define QIO_CHANNEL_READ_FLAG_MSG_PEEK 0x1
#define QIO_CHANNEL_READ_FLAG_RELAXED_EOF 0x2
+#define QIO_CHANNEL_READ_FLAG_FD_PRESERVE_BLOCKING 0x4
typedef enum QIOChannelFeature QIOChannelFeature;
@@ -117,6 +118,15 @@
size_t nfds,
int flags,
Error **errp);
+
+ /*
+ * The io_readv handler must guarantee that all
+ * incoming fds are set BLOCKING (unless
+ * QIO_CHANNEL_READ_FLAG_FD_PRESERVE_BLOCKING flag is set) and
+ * CLOEXEC (if available).
+ * @fds and @nfds are set only on success path. Still, setting
+ * @fds and @nfds to zero is acceptable on failure path.
+ */
ssize_t (*io_readv)(QIOChannel *ioc,
const struct iovec *iov,
size_t niov,
@@ -124,6 +134,7 @@
size_t *nfds,
int flags,
Error **errp);
+
int (*io_close)(QIOChannel *ioc,
Error **errp);
GSource * (*io_create_watch)(QIOChannel *ioc,
@@ -234,6 +245,13 @@
* was allocated. It is the callers responsibility
* to call close() on each file descriptor and to
* call g_free() on the array pointer in @fds.
+ * @fds allocated and set (and @nfds is set too)
+ * _only_ on success path. Still, @fds and @nfds
+ * may be set to zero on failure path.
+ * qio_channel_readv_full() guarantees that all
+ * incoming fds are set BLOCKING (unless
+ * QIO_CHANNEL_READ_FLAG_FD_PRESERVE_BLOCKING flag
+ * is set) and CLOEXEC (if available).
*
* It is an error to pass a non-NULL @fds parameter
* unless qio_channel_has_feature() returns a true
@@ -513,9 +531,9 @@
* return QIO_CHANNEL_ERR_BLOCK if they would otherwise
* block on I/O
*/
-int qio_channel_set_blocking(QIOChannel *ioc,
- bool enabled,
- Error **errp);
+bool qio_channel_set_blocking(QIOChannel *ioc,
+ bool enabled,
+ Error **errp);
/**
* qio_channel_set_follow_coroutine_ctx:
diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h
index be3460b..1b38cb7 100644
--- a/include/qemu/osdep.h
+++ b/include/qemu/osdep.h
@@ -687,6 +687,7 @@
G_GNUC_WARN_UNUSED_RESULT;
void qemu_set_cloexec(int fd);
+bool qemu_set_blocking(int fd, bool block, Error **errp);
/* Return a dynamically allocated directory path that is appropriate for storing
* local state.
diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h
index c562690..be351d8 100644
--- a/include/qemu/sockets.h
+++ b/include/qemu/sockets.h
@@ -46,9 +46,6 @@
G_GNUC_WARN_UNUSED_RESULT;
int socket_set_cork(int fd, int v);
int socket_set_nodelay(int fd);
-void qemu_socket_set_block(int fd);
-int qemu_socket_try_set_nonblock(int fd);
-void qemu_socket_set_nonblock(int fd);
int socket_set_fast_reuse(int fd);
#ifdef WIN32
diff --git a/io/channel-command.c b/io/channel-command.c
index 8966dd3..8ae9a02 100644
--- a/io/channel-command.c
+++ b/io/channel-command.c
@@ -277,9 +277,12 @@
cioc->blocking = enabled;
#else
- if ((cioc->writefd >= 0 && !g_unix_set_fd_nonblocking(cioc->writefd, !enabled, NULL)) ||
- (cioc->readfd >= 0 && !g_unix_set_fd_nonblocking(cioc->readfd, !enabled, NULL))) {
- error_setg_errno(errp, errno, "Failed to set FD nonblocking");
+ if (cioc->writefd >= 0 &&
+ !qemu_set_blocking(cioc->writefd, enabled, errp)) {
+ return -1;
+ }
+ if (cioc->readfd >= 0 &&
+ !qemu_set_blocking(cioc->readfd, enabled, errp)) {
return -1;
}
#endif
diff --git a/io/channel-file.c b/io/channel-file.c
index ca3f180..5cef75a 100644
--- a/io/channel-file.c
+++ b/io/channel-file.c
@@ -223,8 +223,7 @@
#else
QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
- if (!g_unix_set_fd_nonblocking(fioc->fd, !enabled, NULL)) {
- error_setg_errno(errp, errno, "Failed to set FD nonblocking");
+ if (!qemu_set_blocking(fioc->fd, enabled, errp)) {
return -1;
}
return 0;
diff --git a/io/channel-socket.c b/io/channel-socket.c
index 3b7ca92..e53d9ac 100644
--- a/io/channel-socket.c
+++ b/io/channel-socket.c
@@ -472,7 +472,7 @@
*fds = NULL;
for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
- int fd_size, i;
+ int fd_size;
int gotfds;
if (cmsg->cmsg_len < CMSG_LEN(sizeof(int)) ||
@@ -490,24 +490,55 @@
gotfds = fd_size / sizeof(int);
*fds = g_renew(int, *fds, *nfds + gotfds);
memcpy(*fds + *nfds, CMSG_DATA(cmsg), fd_size);
-
- for (i = 0; i < gotfds; i++) {
- int fd = (*fds)[*nfds + i];
- if (fd < 0) {
- continue;
- }
-
- /* O_NONBLOCK is preserved across SCM_RIGHTS so reset it */
- qemu_socket_set_block(fd);
-
-#ifndef MSG_CMSG_CLOEXEC
- qemu_set_cloexec(fd);
-#endif
- }
*nfds += gotfds;
}
}
+static bool qio_channel_handle_fds(int *fds, size_t nfds,
+ bool preserve_blocking, Error **errp)
+{
+ int *end = fds + nfds, *fd;
+
+#ifdef MSG_CMSG_CLOEXEC
+ if (preserve_blocking) {
+ /* Nothing to do */
+ return true;
+ }
+#endif
+
+ for (fd = fds; fd != end; fd++) {
+ if (*fd < 0) {
+ continue;
+ }
+
+ if (!preserve_blocking) {
+ /* O_NONBLOCK is preserved across SCM_RIGHTS so reset it */
+ if (!qemu_set_blocking(*fd, true, errp)) {
+ return false;
+ }
+ }
+
+#ifndef MSG_CMSG_CLOEXEC
+ qemu_set_cloexec(*fd);
+#endif
+ }
+
+ return true;
+}
+
+static void qio_channel_cleanup_fds(int **fds, size_t *nfds)
+{
+ for (size_t i = 0; i < *nfds; i++) {
+ if ((*fds)[i] < 0) {
+ continue;
+ }
+ close((*fds)[i]);
+ }
+
+ g_clear_pointer(fds, g_free);
+ *nfds = 0;
+}
+
static ssize_t qio_channel_socket_readv(QIOChannel *ioc,
const struct iovec *iov,
@@ -556,7 +587,16 @@
}
if (fds && nfds) {
+ bool preserve_blocking =
+ flags & QIO_CHANNEL_READ_FLAG_FD_PRESERVE_BLOCKING;
+
qio_channel_socket_copy_fds(&msg, fds, nfds);
+
+ if (!qio_channel_handle_fds(*fds, *nfds,
+ preserve_blocking, errp)) {
+ qio_channel_cleanup_fds(fds, nfds);
+ return -1;
+ }
}
return ret;
@@ -820,11 +860,10 @@
{
QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
- if (enabled) {
- qemu_socket_set_block(sioc->fd);
- } else {
- qemu_socket_set_nonblock(sioc->fd);
+ if (!qemu_set_blocking(sioc->fd, enabled, errp)) {
+ return -1;
}
+
return 0;
}
diff --git a/io/channel-tls.c b/io/channel-tls.c
index a8248a9..7135896 100644
--- a/io/channel-tls.c
+++ b/io/channel-tls.c
@@ -425,7 +425,7 @@
{
QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
- return qio_channel_set_blocking(tioc->master, enabled, errp);
+ return qio_channel_set_blocking(tioc->master, enabled, errp) ? 0 : -1;
}
static void qio_channel_tls_set_delay(QIOChannel *ioc,
diff --git a/io/channel-websock.c b/io/channel-websock.c
index 08ddb27..0a8c5c4 100644
--- a/io/channel-websock.c
+++ b/io/channel-websock.c
@@ -1184,8 +1184,7 @@
{
QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(ioc);
- qio_channel_set_blocking(wioc->master, enabled, errp);
- return 0;
+ return qio_channel_set_blocking(wioc->master, enabled, errp) ? 0 : -1;
}
static void qio_channel_websock_set_delay(QIOChannel *ioc,
diff --git a/io/channel.c b/io/channel.c
index ebd9322..852e684 100644
--- a/io/channel.c
+++ b/io/channel.c
@@ -359,12 +359,12 @@
}
-int qio_channel_set_blocking(QIOChannel *ioc,
+bool qio_channel_set_blocking(QIOChannel *ioc,
bool enabled,
Error **errp)
{
QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
- return klass->io_set_blocking(ioc, enabled, errp);
+ return klass->io_set_blocking(ioc, enabled, errp) == 0;
}
diff --git a/migration/colo.c b/migration/colo.c
index e0f713c..cf4d71d 100644
--- a/migration/colo.c
+++ b/migration/colo.c
@@ -859,7 +859,10 @@
* coroutine, and here we are in the COLO incoming thread, so it is ok to
* set the fd back to blocked.
*/
- qemu_file_set_blocking(mis->from_src_file, true);
+ if (!qemu_file_set_blocking(mis->from_src_file, true, &local_err)) {
+ error_report_err(local_err);
+ goto out;
+ }
colo_incoming_start_dirty_log();
diff --git a/migration/migration.c b/migration/migration.c
index 10c216d..e1ac4d7 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -951,7 +951,7 @@
assert(!mis->from_src_file);
mis->from_src_file = f;
- qemu_file_set_blocking(f, false);
+ qemu_file_set_blocking(f, false, &error_abort);
}
void migration_incoming_process(void)
@@ -971,7 +971,7 @@
/* This should be set already in migration_incoming_setup() */
assert(mis->from_src_file);
/* Postcopy has standalone thread to do vm load */
- qemu_file_set_blocking(mis->from_src_file, true);
+ qemu_file_set_blocking(mis->from_src_file, true, &error_abort);
/* Re-configure the return path */
mis->to_src_file = qemu_file_get_return_path(mis->from_src_file);
@@ -4002,7 +4002,9 @@
}
migration_rate_set(rate_limit);
- qemu_file_set_blocking(s->to_dst_file, true);
+ if (!qemu_file_set_blocking(s->to_dst_file, true, &local_err)) {
+ goto fail;
+ }
/*
* Open the return path. For postcopy, it is used exclusively. For
diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c
index 45af9a3..0172172 100644
--- a/migration/postcopy-ram.c
+++ b/migration/postcopy-ram.c
@@ -1909,7 +1909,7 @@
* The new loading channel has its own threads, so it needs to be
* blocked too. It's by default true, just be explicit.
*/
- qemu_file_set_blocking(file, true);
+ qemu_file_set_blocking(file, true, &error_abort);
mis->postcopy_qemufile_dst = file;
qemu_sem_post(&mis->postcopy_qemufile_dst_done);
trace_postcopy_preempt_new_channel();
diff --git a/migration/qemu-file.c b/migration/qemu-file.c
index b6ac190..0f4280d 100644
--- a/migration/qemu-file.c
+++ b/migration/qemu-file.c
@@ -340,7 +340,8 @@
do {
struct iovec iov = { f->buf + pending, IO_BUF_SIZE - pending };
- len = qio_channel_readv_full(f->ioc, &iov, 1, pfds, pnfd, 0,
+ len = qio_channel_readv_full(f->ioc, &iov, 1, pfds, pnfd,
+ QIO_CHANNEL_READ_FLAG_FD_PRESERVE_BLOCKING,
&local_error);
if (len == QIO_CHANNEL_ERR_BLOCK) {
if (qemu_in_coroutine()) {
@@ -887,9 +888,9 @@
* both directions, and thus changing the blocking on the main
* QEMUFile can also affect the return path.
*/
-void qemu_file_set_blocking(QEMUFile *f, bool block)
+bool qemu_file_set_blocking(QEMUFile *f, bool block, Error **errp)
{
- qio_channel_set_blocking(f->ioc, block, NULL);
+ return qio_channel_set_blocking(f->ioc, block, errp);
}
/*
diff --git a/migration/qemu-file.h b/migration/qemu-file.h
index f5b9f43..c13c967 100644
--- a/migration/qemu-file.h
+++ b/migration/qemu-file.h
@@ -71,7 +71,7 @@
int qemu_file_shutdown(QEMUFile *f);
QEMUFile *qemu_file_get_return_path(QEMUFile *f);
int qemu_fflush(QEMUFile *f);
-void qemu_file_set_blocking(QEMUFile *f, bool block);
+bool qemu_file_set_blocking(QEMUFile *f, bool block, Error **errp);
int qemu_file_get_to_fd(QEMUFile *f, int fd, size_t size);
void qemu_set_offset(QEMUFile *f, off_t off, int whence);
off_t qemu_get_offset(QEMUFile *f);
diff --git a/migration/savevm.c b/migration/savevm.c
index fabbeb2..abe0547 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -2095,7 +2095,7 @@
* Because we're a thread and not a coroutine we can't yield
* in qemu_file, and thus we must be blocking now.
*/
- qemu_file_set_blocking(f, true);
+ qemu_file_set_blocking(f, true, &error_fatal);
/* TODO: sanity check that only postcopiable data will be loaded here */
load_res = qemu_loadvm_state_main(f, mis);
@@ -2108,7 +2108,7 @@
f = mis->from_src_file;
/* And non-blocking again so we don't block in any cleanup */
- qemu_file_set_blocking(f, false);
+ qemu_file_set_blocking(f, false, &error_fatal);
trace_postcopy_ram_listen_thread_exit();
if (load_res < 0) {
diff --git a/nbd/server.c b/nbd/server.c
index d242be9..acec048 100644
--- a/nbd/server.c
+++ b/nbd/server.c
@@ -1411,7 +1411,9 @@
....options sent, ending in NBD_OPT_EXPORT_NAME or NBD_OPT_GO....
*/
- qio_channel_set_blocking(client->ioc, false, NULL);
+ if (!qio_channel_set_blocking(client->ioc, false, errp)) {
+ return -EINVAL;
+ }
qio_channel_set_follow_coroutine_ctx(client->ioc, true);
trace_nbd_negotiate_begin();
diff --git a/net/dgram.c b/net/dgram.c
index 48f653b..baa126d 100644
--- a/net/dgram.c
+++ b/net/dgram.c
@@ -226,7 +226,10 @@
}
}
- qemu_socket_set_nonblock(fd);
+ if (!qemu_set_blocking(fd, false, errp)) {
+ goto fail;
+ }
+
return fd;
fail:
if (fd >= 0) {
@@ -284,7 +287,7 @@
Error **errp)
{
NetDgramState *s;
- int fd, ret;
+ int fd;
struct sockaddr_in *saddr;
if (remote->type != SOCKET_ADDRESS_TYPE_INET) {
@@ -332,11 +335,8 @@
g_free(saddr);
return -1;
}
- ret = qemu_socket_try_set_nonblock(fd);
- if (ret < 0) {
+ if (!qemu_set_blocking(fd, false, errp)) {
g_free(saddr);
- error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d",
- name, fd);
return -1;
}
@@ -504,7 +504,11 @@
close(fd);
return -1;
}
- qemu_socket_set_nonblock(fd);
+
+ if (!qemu_set_blocking(fd, false, errp)) {
+ close(fd);
+ return -1;
+ }
dest_len = sizeof(raddr_in);
dest_addr = g_malloc(dest_len);
@@ -551,7 +555,10 @@
close(fd);
return -1;
}
- qemu_socket_set_nonblock(fd);
+ if (!qemu_set_blocking(fd, false, errp)) {
+ close(fd);
+ return -1;
+ }
dest_len = sizeof(raddr_un);
dest_addr = g_malloc(dest_len);
@@ -562,10 +569,7 @@
if (fd == -1) {
return -1;
}
- ret = qemu_socket_try_set_nonblock(fd);
- if (ret < 0) {
- error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d",
- name, fd);
+ if (!qemu_set_blocking(fd, false, errp)) {
return -1;
}
dest_addr = NULL;
diff --git a/net/l2tpv3.c b/net/l2tpv3.c
index b5547cb..cdfc641 100644
--- a/net/l2tpv3.c
+++ b/net/l2tpv3.c
@@ -648,6 +648,9 @@
error_setg(errp, "could not bind socket err=%i", errno);
goto outerr;
}
+ if (!qemu_set_blocking(fd, false, errp)) {
+ goto outerr;
+ }
freeaddrinfo(result);
@@ -709,8 +712,6 @@
s->vec = g_new(struct iovec, MAX_L2TPV3_IOVCNT);
s->header_buf = g_malloc(s->header_size);
- qemu_socket_set_nonblock(fd);
-
s->fd = fd;
s->counter = 0;
diff --git a/net/socket.c b/net/socket.c
index 784dda6..1ad03fc 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -295,7 +295,10 @@
}
}
- qemu_socket_set_nonblock(fd);
+ if (!qemu_set_blocking(fd, false, errp)) {
+ goto fail;
+ }
+
return fd;
fail:
if (fd >= 0)
@@ -508,7 +511,10 @@
error_setg_errno(errp, errno, "can't create stream socket");
return -1;
}
- qemu_socket_set_nonblock(fd);
+ if (!qemu_set_blocking(fd, false, errp)) {
+ close(fd);
+ return -1;
+ }
socket_set_fast_reuse(fd);
@@ -556,7 +562,10 @@
error_setg_errno(errp, errno, "can't create stream socket");
return -1;
}
- qemu_socket_set_nonblock(fd);
+ if (!qemu_set_blocking(fd, false, errp)) {
+ close(fd);
+ return -1;
+ }
connected = 0;
for(;;) {
@@ -671,7 +680,10 @@
close(fd);
return -1;
}
- qemu_socket_set_nonblock(fd);
+ if (!qemu_set_blocking(fd, false, errp)) {
+ close(fd);
+ return -1;
+ }
s = net_socket_fd_init_dgram(peer, model, name, fd, 0, NULL, errp);
if (!s) {
@@ -706,7 +718,7 @@
}
if (sock->fd) {
- int fd, ret, so_type;
+ int fd, so_type;
fd = monitor_fd_param(monitor_cur(), sock->fd, errp);
if (fd == -1) {
@@ -716,10 +728,7 @@
if (so_type < 0) {
return -1;
}
- ret = qemu_socket_try_set_nonblock(fd);
- if (ret < 0) {
- error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d",
- name, fd);
+ if (!qemu_set_blocking(fd, false, errp)) {
return -1;
}
switch (so_type) {
diff --git a/net/stream.c b/net/stream.c
index d893f02..94f823a 100644
--- a/net/stream.c
+++ b/net/stream.c
@@ -138,7 +138,6 @@
NetStreamData *d = opaque;
QIOChannelSocket *listen_sioc = QIO_CHANNEL_SOCKET(d->listen_ioc);
SocketAddress *addr;
- int ret;
Error *err = NULL;
if (qio_task_propagate_error(task, &err)) {
@@ -149,13 +148,11 @@
addr = qio_channel_socket_get_local_address(listen_sioc, NULL);
g_assert(addr != NULL);
- ret = qemu_socket_try_set_nonblock(listen_sioc->fd);
- if (addr->type == SOCKET_ADDRESS_TYPE_FD && ret < 0) {
- qemu_set_info_str(&d->nc, "can't use file descriptor %s (errno %d)",
- addr->u.fd.str, -ret);
+ if (!qemu_set_blocking(listen_sioc->fd, false, &err)) {
+ qemu_set_info_str(&d->nc, "error: %s", error_get_pretty(err));
+ error_free(err);
return;
}
- g_assert(ret == 0);
qapi_free_SocketAddress(addr);
d->nc.link_down = true;
diff --git a/net/stream_data.c b/net/stream_data.c
index 5af27e0..03740e9 100644
--- a/net/stream_data.c
+++ b/net/stream_data.c
@@ -12,6 +12,7 @@
#include "net/net.h"
#include "io/channel.h"
#include "io/net-listener.h"
+#include "qemu/sockets.h"
#include "stream_data.h"
@@ -154,7 +155,6 @@
{
QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(d->ioc);
SocketAddress *addr;
- int ret;
Error *err = NULL;
if (qio_task_propagate_error(task, &err)) {
@@ -166,14 +166,12 @@
addr = qio_channel_socket_get_remote_address(sioc, NULL);
g_assert(addr != NULL);
- ret = qemu_socket_try_set_nonblock(sioc->fd);
- if (addr->type == SOCKET_ADDRESS_TYPE_FD && ret < 0) {
- qemu_set_info_str(&d->nc, "can't use file descriptor %s (errno %d)",
- addr->u.fd.str, -ret);
+ if (!qemu_set_blocking(sioc->fd, false, &err)) {
+ qemu_set_info_str(&d->nc, "error: %s", error_get_pretty(err));
+ error_free(err);
qapi_free_SocketAddress(addr);
goto error;
}
- g_assert(ret == 0);
qapi_free_SocketAddress(addr);
net_socket_rs_init(&d->rs, net_stream_data_rs_finalize, false);
diff --git a/net/tap-bsd.c b/net/tap-bsd.c
index b4c8444..3f98d0e 100644
--- a/net/tap-bsd.c
+++ b/net/tap-bsd.c
@@ -98,7 +98,12 @@
return -1;
}
}
- g_unix_set_fd_nonblocking(fd, true, NULL);
+
+ if (!qemu_set_blocking(fd, false, errp)) {
+ close(fd);
+ return -1;
+ }
+
return fd;
}
@@ -189,7 +194,10 @@
goto error;
}
- g_unix_set_fd_nonblocking(fd, true, NULL);
+ if (!qemu_set_blocking(fd, false, errp)) {
+ goto error;
+ }
+
return fd;
error:
diff --git a/net/tap-linux.c b/net/tap-linux.c
index 22ec2f4..e832810 100644
--- a/net/tap-linux.c
+++ b/net/tap-linux.c
@@ -124,7 +124,12 @@
return -1;
}
pstrcpy(ifname, ifname_size, ifr.ifr_name);
- g_unix_set_fd_nonblocking(fd, true, NULL);
+
+ if (!qemu_set_blocking(fd, false, errp)) {
+ close(fd);
+ return -1;
+ }
+
return fd;
}
diff --git a/net/tap-solaris.c b/net/tap-solaris.c
index 51b7830..af2ebb1 100644
--- a/net/tap-solaris.c
+++ b/net/tap-solaris.c
@@ -198,7 +198,12 @@
return -1;
}
}
- g_unix_set_fd_nonblocking(fd, true, NULL);
+
+ if (!qemu_set_blocking(fd, false, errp)) {
+ close(fd);
+ return -1;
+ }
+
return fd;
}
diff --git a/net/tap.c b/net/tap.c
index f7df702..f37133e 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -627,8 +627,7 @@
return -1;
}
- if (!g_unix_set_fd_nonblocking(fd, true, NULL)) {
- error_setg_errno(errp, errno, "Failed to set FD nonblocking");
+ if (!qemu_set_blocking(fd, false, errp)) {
return -1;
}
vnet_hdr = tap_probe_vnet_hdr(fd, errp);
@@ -729,9 +728,7 @@
error_propagate(errp, err);
goto failed;
}
- if (!g_unix_set_fd_nonblocking(vhostfd, true, NULL)) {
- error_setg_errno(errp, errno, "%s: Can't use file descriptor %d",
- name, fd);
+ if (!qemu_set_blocking(vhostfd, false, errp)) {
goto failed;
}
} else {
@@ -741,8 +738,7 @@
"tap: open vhost char device failed");
goto failed;
}
- if (!g_unix_set_fd_nonblocking(vhostfd, true, NULL)) {
- error_setg_errno(errp, errno, "Failed to set FD nonblocking");
+ if (!qemu_set_blocking(vhostfd, false, errp)) {
goto failed;
}
}
@@ -839,9 +835,7 @@
return -1;
}
- if (!g_unix_set_fd_nonblocking(fd, true, NULL)) {
- error_setg_errno(errp, errno, "%s: Can't use file descriptor %d",
- name, fd);
+ if (!qemu_set_blocking(fd, false, errp)) {
close(fd);
return -1;
}
@@ -895,10 +889,8 @@
goto free_fail;
}
- if (!g_unix_set_fd_nonblocking(fd, true, NULL)) {
+ if (!qemu_set_blocking(fd, false, errp)) {
ret = -1;
- error_setg_errno(errp, errno, "%s: Can't use file descriptor %d",
- name, fd);
goto free_fail;
}
@@ -951,8 +943,7 @@
return -1;
}
- if (!g_unix_set_fd_nonblocking(fd, true, NULL)) {
- error_setg_errno(errp, errno, "Failed to set FD nonblocking");
+ if (!qemu_set_blocking(fd, false, errp)) {
return -1;
}
vnet_hdr = tap_probe_vnet_hdr(fd, errp);
diff --git a/qga/channel-posix.c b/qga/channel-posix.c
index 465d688..9ccc8b7 100644
--- a/qga/channel-posix.c
+++ b/qga/channel-posix.c
@@ -28,6 +28,7 @@
GAChannel *c = data;
int ret, client_fd;
bool accepted = false;
+ Error *err = NULL;
g_assert(channel != NULL);
@@ -36,7 +37,11 @@
g_warning("error converting fd to gsocket: %s", strerror(errno));
goto out;
}
- qemu_socket_set_nonblock(client_fd);
+ if (!qemu_set_blocking(client_fd, false, &err)) {
+ g_warning("%s", error_get_pretty(err));
+ error_free(err);
+ goto out;
+ }
ret = ga_channel_client_add(c, client_fd);
if (ret) {
g_warning("error setting up connection");
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 12bc086..5070f27 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -503,9 +503,8 @@
/* set fd non-blocking to avoid common use cases (like reading from a
* named pipe) from hanging the agent
*/
- if (!g_unix_set_fd_nonblocking(fileno(fh), true, NULL)) {
+ if (!qemu_set_blocking(fileno(fh), false, errp)) {
fclose(fh);
- error_setg_errno(errp, errno, "Failed to set FD nonblocking");
return -1;
}
diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c
index b69dd98..074b4db 100644
--- a/scsi/qemu-pr-helper.c
+++ b/scsi/qemu-pr-helper.c
@@ -733,8 +733,11 @@
uint32_t flags;
int r;
- qio_channel_set_blocking(QIO_CHANNEL(client->ioc),
- false, NULL);
+ if (!qio_channel_set_blocking(QIO_CHANNEL(client->ioc),
+ false, &local_err)) {
+ goto out;
+ }
+
qio_channel_set_follow_coroutine_ctx(QIO_CHANNEL(client->ioc), true);
/* A very simple negotiation for future extensibility. No features
@@ -786,6 +789,7 @@
}
}
+out:
if (local_err) {
if (verbose == 0) {
error_free(local_err);
@@ -794,7 +798,6 @@
}
}
-out:
object_unref(OBJECT(client->ioc));
g_free(client);
}
diff --git a/tests/qtest/fuzz/virtio_net_fuzz.c b/tests/qtest/fuzz/virtio_net_fuzz.c
index e239875..e9b13d3 100644
--- a/tests/qtest/fuzz/virtio_net_fuzz.c
+++ b/tests/qtest/fuzz/virtio_net_fuzz.c
@@ -132,7 +132,7 @@
{
int ret = socketpair(PF_UNIX, SOCK_STREAM, 0, sockfds);
g_assert_cmpint(ret, !=, -1);
- g_unix_set_fd_nonblocking(sockfds[0], true, NULL);
+ qemu_set_blocking(sockfds[0], false, &error_abort);
sockfds_initialized = true;
g_string_append_printf(cmd_line, " -netdev socket,fd=%d,id=hs0 ",
sockfds[1]);
diff --git a/tests/qtest/vhost-user-test.c b/tests/qtest/vhost-user-test.c
index 56472ca..6ec4ec2 100644
--- a/tests/qtest/vhost-user-test.c
+++ b/tests/qtest/vhost-user-test.c
@@ -330,7 +330,6 @@
static void chr_read(void *opaque, const uint8_t *buf, int size)
{
- g_autoptr(GError) err = NULL;
TestServer *s = opaque;
CharBackend *chr = &s->chr;
VhostUserMsg msg;
@@ -471,8 +470,7 @@
* The receive function forces it to be blocking,
* so revert it back to non-blocking.
*/
- g_unix_set_fd_nonblocking(fd, true, &err);
- g_assert_no_error(err);
+ qemu_set_blocking(fd, false, &error_abort);
break;
case VHOST_USER_SET_LOG_BASE:
diff --git a/tests/unit/io-channel-helpers.c b/tests/unit/io-channel-helpers.c
index c0799c2..22b42d1 100644
--- a/tests/unit/io-channel-helpers.c
+++ b/tests/unit/io-channel-helpers.c
@@ -20,6 +20,7 @@
#include "qemu/osdep.h"
#include "io-channel-helpers.h"
+#include "qapi/error.h"
#include "qemu/iov.h"
struct QIOChannelTest {
@@ -109,8 +110,8 @@
test->src = src;
test->dst = dst;
- qio_channel_set_blocking(test->dst, blocking, NULL);
- qio_channel_set_blocking(test->src, blocking, NULL);
+ qio_channel_set_blocking(test->dst, blocking, &error_abort);
+ qio_channel_set_blocking(test->src, blocking, &error_abort);
reader = g_thread_new("reader",
test_io_thread_reader,
diff --git a/tests/unit/socket-helpers.c b/tests/unit/socket-helpers.c
index 37db24f..46d2ff1 100644
--- a/tests/unit/socket-helpers.c
+++ b/tests/unit/socket-helpers.c
@@ -19,6 +19,7 @@
*/
#include "qemu/osdep.h"
+#include "qapi/error.h"
#include "qemu/sockets.h"
#include "socket-helpers.h"
@@ -88,7 +89,8 @@
goto cleanup;
}
- qemu_socket_set_nonblock(cfd);
+ qemu_set_blocking(cfd, false, &error_abort);
+
if (connect(cfd, (struct sockaddr *)&ss, sslen) < 0) {
if (errno == EINPROGRESS) {
check_soerr = true;
diff --git a/tests/unit/test-crypto-tlssession.c b/tests/unit/test-crypto-tlssession.c
index 554054e..61311cb 100644
--- a/tests/unit/test-crypto-tlssession.c
+++ b/tests/unit/test-crypto-tlssession.c
@@ -112,8 +112,8 @@
* thread, so we need these non-blocking to avoid deadlock
* of ourselves
*/
- qemu_socket_set_nonblock(channel[0]);
- qemu_socket_set_nonblock(channel[1]);
+ qemu_set_blocking(channel[0], false, &error_abort);
+ qemu_set_blocking(channel[1], false, &error_abort);
clientCreds = test_tls_creds_psk_create(
QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT,
@@ -264,8 +264,8 @@
* thread, so we need these non-blocking to avoid deadlock
* of ourselves
*/
- qemu_socket_set_nonblock(channel[0]);
- qemu_socket_set_nonblock(channel[1]);
+ qemu_set_blocking(channel[0], false, &error_abort);
+ qemu_set_blocking(channel[1], false, &error_abort);
#define CLIENT_CERT_DIR "tests/test-crypto-tlssession-client/"
#define SERVER_CERT_DIR "tests/test-crypto-tlssession-server/"
diff --git a/tests/unit/test-io-channel-tls.c b/tests/unit/test-io-channel-tls.c
index e036ac5..6f282ad 100644
--- a/tests/unit/test-io-channel-tls.c
+++ b/tests/unit/test-io-channel-tls.c
@@ -184,8 +184,8 @@
* thread, so we need these non-blocking to avoid deadlock
* of ourselves
*/
- qio_channel_set_blocking(QIO_CHANNEL(clientChanSock), false, NULL);
- qio_channel_set_blocking(QIO_CHANNEL(serverChanSock), false, NULL);
+ qio_channel_set_blocking(QIO_CHANNEL(clientChanSock), false, &error_abort);
+ qio_channel_set_blocking(QIO_CHANNEL(serverChanSock), false, &error_abort);
/* Now the real part of the test, setup the sessions */
clientChanTLS = qio_channel_tls_new_client(
diff --git a/tests/unit/test-iov.c b/tests/unit/test-iov.c
index 75bc3be..63e2b15 100644
--- a/tests/unit/test-iov.c
+++ b/tests/unit/test-iov.c
@@ -1,4 +1,5 @@
#include "qemu/osdep.h"
+#include "qapi/error.h"
#include "qemu/iov.h"
#include "qemu/sockets.h"
@@ -186,7 +187,7 @@
close(sv[0]);
FD_SET(sv[1], &fds);
- g_unix_set_fd_nonblocking(sv[1], true, NULL);
+ qemu_set_blocking(sv[1], false, &error_abort);
r = g_test_rand_int_range(sz / 2, sz);
setsockopt(sv[1], SOL_SOCKET, SO_SNDBUF, &r, sizeof(r));
@@ -222,7 +223,7 @@
close(sv[1]);
FD_SET(sv[0], &fds);
- g_unix_set_fd_nonblocking(sv[0], true, NULL);
+ qemu_set_blocking(sv[0], false, &error_abort);
r = g_test_rand_int_range(sz / 2, sz);
setsockopt(sv[0], SOL_SOCKET, SO_RCVBUF, &r, sizeof(r));
usleep(500000);
diff --git a/tools/i386/qemu-vmsr-helper.c b/tools/i386/qemu-vmsr-helper.c
index 5f19a48..6c0f4fe 100644
--- a/tools/i386/qemu-vmsr-helper.c
+++ b/tools/i386/qemu-vmsr-helper.c
@@ -213,8 +213,10 @@
uint64_t vmsr;
int r;
- qio_channel_set_blocking(QIO_CHANNEL(client->ioc),
- false, NULL);
+ if (!qio_channel_set_blocking(QIO_CHANNEL(client->ioc),
+ false, &local_err)) {
+ goto out;
+ }
qio_channel_set_follow_coroutine_ctx(QIO_CHANNEL(client->ioc), true);
diff --git a/ui/input-linux.c b/ui/input-linux.c
index 92e1a1a..44d0c15 100644
--- a/ui/input-linux.c
+++ b/ui/input-linux.c
@@ -316,8 +316,7 @@
error_setg_file_open(errp, errno, il->evdev);
return;
}
- if (!g_unix_set_fd_nonblocking(il->fd, true, NULL)) {
- error_setg_errno(errp, errno, "Failed to set FD nonblocking");
+ if (!qemu_set_blocking(il->fd, false, errp)) {
return;
}
diff --git a/ui/vnc.c b/ui/vnc.c
index 9054fc8..77c823b 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -3337,7 +3337,7 @@
VNC_DEBUG("New client on socket %p\n", vs->sioc);
update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
- qio_channel_set_blocking(vs->ioc, false, NULL);
+ qio_channel_set_blocking(vs->ioc, false, &error_abort);
if (vs->ioc_tag) {
g_source_remove(vs->ioc_tag);
}
diff --git a/util/event_notifier-posix.c b/util/event_notifier-posix.c
index 76420c5..83fdbb9 100644
--- a/util/event_notifier-posix.c
+++ b/util/event_notifier-posix.c
@@ -11,6 +11,7 @@
*/
#include "qemu/osdep.h"
+#include "qapi/error.h"
#include "qemu/cutils.h"
#include "qemu/event_notifier.h"
#include "qemu/main-loop.h"
@@ -36,6 +37,7 @@
{
int fds[2];
int ret;
+ Error *local_err = NULL;
#ifdef CONFIG_EVENTFD
ret = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
@@ -52,11 +54,11 @@
if (!g_unix_open_pipe(fds, FD_CLOEXEC, NULL)) {
return -errno;
}
- if (!g_unix_set_fd_nonblocking(fds[0], true, NULL)) {
+ if (!qemu_set_blocking(fds[0], false, &local_err)) {
ret = -errno;
goto fail;
}
- if (!g_unix_set_fd_nonblocking(fds[1], true, NULL)) {
+ if (!qemu_set_blocking(fds[1], false, &local_err)) {
ret = -errno;
goto fail;
}
@@ -70,6 +72,7 @@
return 0;
fail:
+ error_report_err(local_err);
close(fds[0]);
close(fds[1]);
return ret;
diff --git a/util/main-loop.c b/util/main-loop.c
index 51aeb24..b8ddda8 100644
--- a/util/main-loop.c
+++ b/util/main-loop.c
@@ -114,7 +114,10 @@
return -errno;
}
- g_unix_set_fd_nonblocking(sigfd, true, NULL);
+ if (!qemu_set_blocking(sigfd, false, errp)) {
+ close(sigfd);
+ return -EINVAL;
+ }
qemu_set_fd_handler(sigfd, sigfd_handler, NULL, (void *)(intptr_t)sigfd);
diff --git a/util/oslib-posix.c b/util/oslib-posix.c
index 4ff577e..14cf94a 100644
--- a/util/oslib-posix.c
+++ b/util/oslib-posix.c
@@ -250,21 +250,19 @@
#endif
}
-void qemu_socket_set_block(int fd)
+bool qemu_set_blocking(int fd, bool block, Error **errp)
{
- g_unix_set_fd_nonblocking(fd, false, NULL);
-}
+ g_autoptr(GError) err = NULL;
-int qemu_socket_try_set_nonblock(int fd)
-{
- return g_unix_set_fd_nonblocking(fd, true, NULL) ? 0 : -errno;
-}
+ if (!g_unix_set_fd_nonblocking(fd, !block, &err)) {
+ error_setg_errno(errp, errno,
+ "Can't set file descriptor %d %s: %s", fd,
+ block ? "blocking" : "non-blocking",
+ err->message);
+ return false;
+ }
-void qemu_socket_set_nonblock(int fd)
-{
- int f;
- f = qemu_socket_try_set_nonblock(fd);
- assert(f == 0);
+ return true;
}
int socket_set_fast_reuse(int fd)
diff --git a/util/oslib-win32.c b/util/oslib-win32.c
index b735163..b9ce2f9 100644
--- a/util/oslib-win32.c
+++ b/util/oslib-win32.c
@@ -177,25 +177,22 @@
}
}
-void qemu_socket_set_block(int fd)
+bool qemu_set_blocking(int fd, bool block, Error **errp)
{
- unsigned long opt = 0;
- qemu_socket_unselect(fd, NULL);
- ioctlsocket(fd, FIONBIO, &opt);
-}
+ unsigned long opt = block ? 0 : 1;
-int qemu_socket_try_set_nonblock(int fd)
-{
- unsigned long opt = 1;
- if (ioctlsocket(fd, FIONBIO, &opt) != NO_ERROR) {
- return -socket_error();
+ if (block) {
+ qemu_socket_unselect(fd, NULL);
}
- return 0;
-}
-void qemu_socket_set_nonblock(int fd)
-{
- (void)qemu_socket_try_set_nonblock(fd);
+ if (ioctlsocket(fd, FIONBIO, &opt) != NO_ERROR) {
+ error_setg_errno(errp, socket_error(),
+ "Can't set file descriptor %d %s", fd,
+ block ? "blocking" : "non-blocking");
+ return false;
+ }
+
+ return true;
}
int socket_set_fast_reuse(int fd)
diff --git a/util/vhost-user-server.c b/util/vhost-user-server.c
index b192290..1dbe409 100644
--- a/util/vhost-user-server.c
+++ b/util/vhost-user-server.c
@@ -62,7 +62,7 @@
}
}
-static void vmsg_unblock_fds(VhostUserMsg *vmsg)
+static bool vmsg_unblock_fds(VhostUserMsg *vmsg, Error **errp)
{
int i;
@@ -74,12 +74,16 @@
*/
if (vmsg->request == VHOST_USER_ADD_MEM_REG ||
vmsg->request == VHOST_USER_SET_MEM_TABLE) {
- return;
+ return true;
}
for (i = 0; i < vmsg->fd_num; i++) {
- qemu_socket_set_nonblock(vmsg->fds[i]);
+ if (!qemu_set_blocking(vmsg->fds[i], false, errp)) {
+ return false;
+ }
}
+
+ return true;
}
static void panic_cb(VuDev *vu_dev, const char *buf)
@@ -122,7 +126,6 @@
vmsg->fd_num = 0;
if (!ioc) {
- error_report_err(local_err);
goto fail;
}
@@ -176,7 +179,10 @@
} while (read_bytes != VHOST_USER_HDR_SIZE);
/* qio_channel_readv_full will make socket fds blocking, unblock them */
- vmsg_unblock_fds(vmsg);
+ if (!vmsg_unblock_fds(vmsg, &local_err)) {
+ error_report_err(local_err);
+ goto fail;
+ }
if (vmsg->size > sizeof(vmsg->payload)) {
error_report("Error: too big message request: %d, "
"size: vmsg->size: %u, "
@@ -303,7 +309,8 @@
vu_fd_watch->fd = fd;
vu_fd_watch->cb = cb;
- qemu_socket_set_nonblock(fd);
+ /* TODO: handle error more gracefully than aborting */
+ qemu_set_blocking(fd, false, &error_abort);
aio_set_fd_handler(server->ctx, fd, kick_handler,
NULL, NULL, NULL, vu_fd_watch);
vu_fd_watch->vu_dev = vu_dev;
@@ -336,6 +343,7 @@
gpointer opaque)
{
VuServer *server = opaque;
+ Error *local_err = NULL;
if (server->sioc) {
warn_report("Only one vhost-user client is allowed to "
@@ -368,7 +376,11 @@
object_ref(OBJECT(server->ioc));
/* TODO vu_message_write() spins if non-blocking! */
- qio_channel_set_blocking(server->ioc, false, NULL);
+ if (!qio_channel_set_blocking(server->ioc, false, &local_err)) {
+ error_report_err(local_err);
+ vu_deinit(&server->vu_dev);
+ return;
+ }
qio_channel_set_follow_coroutine_ctx(server->ioc, true);