aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAric Belsito <lluixhi@gmail.com>2017-07-27 10:59:01 -0700
committerAric Belsito <lluixhi@gmail.com>2017-07-27 10:59:01 -0700
commit9212f510625a88c624d5d8d9456842091ee93305 (patch)
treedbd836e73bfc2186f86aa133c7ceddb0a4d92899 /app-emulation
parentapp-emulation/qemu: sync with tree (diff)
downloadmusl-9212f510625a88c624d5d8d9456842091ee93305.tar.gz
musl-9212f510625a88c624d5d8d9456842091ee93305.tar.bz2
musl-9212f510625a88c624d5d8d9456842091ee93305.zip
app-emulation/qemu: restore patch
deleted the wrong one..
Diffstat (limited to 'app-emulation')
-rw-r--r--app-emulation/qemu/Manifest2
-rw-r--r--app-emulation/qemu/files/qemu-2.9.0-CVE-2017-7493.patch174
-rw-r--r--app-emulation/qemu/files/qemu-2.9.0-CVE-2017-7539.patch601
3 files changed, 175 insertions, 602 deletions
diff --git a/app-emulation/qemu/Manifest b/app-emulation/qemu/Manifest
index e4a3f794..e3f4bd29 100644
--- a/app-emulation/qemu/Manifest
+++ b/app-emulation/qemu/Manifest
@@ -9,7 +9,7 @@ AUX qemu-2.9.0-CVE-2017-10664.patch 1613 SHA256 5941cc41f0c02b185be3f6ba450f155d
AUX qemu-2.9.0-CVE-2017-10806.patch 1450 SHA256 ef884e2ed3adb618273af1d036ed0c7e3a09599e3d042080bb4b5014c6bc54d7 SHA512 38fea2c1a2a5a224585a07a028a8c4cfc1bec4d943e85c13e01228062bf306a502b0948270863b226bc974832e3af18158904fbfc08ccdf1f72f06e7830780d5 WHIRLPOOL f02fb957016af684dc894f93ec0b7dcca3febb8d37882aae1e17d2aca9948e200a013ae467cb54c5555e76c73f124a37c95fde189a4492d88322802d8160310c
AUX qemu-2.9.0-CVE-2017-11334.patch 1362 SHA256 bc2f3a50ad174e5453d0e4d1e14e9723b316e2339dc25ff31e27060ee13242bb SHA512 422296269ec29b3313c984947ac48b7179ce8e169131624d316589a621778f846b883e76cdfba50c62dc63ab5fede0ad0292704c1ca1cc9e1e7b3b01a153b8c8 WHIRLPOOL 504cf6b2ebfb11bf1471f920d101df28df59f1a585eac31ac278a366f2b769386bc7d100aa8386b3f8f45d5f5f700aa6625be3192eb4f1f3b77e69c6684cf74f
AUX qemu-2.9.0-CVE-2017-11434.patch 912 SHA256 e8be3cb9261f8735ff2a50fb8b79ccfea85456c7a2e5a5702fcc5339463dc05a SHA512 db95d9459b9669e0981195fe15f16c4e74d5f00c03e1ce5e33541e005260e77fa114b1b3f30bc06d80b723a6361b704fb58709b25773c168c8aa8f5f96580ac9 WHIRLPOOL c68e25024ab3c1d01e5b53d0a7b1591110b96d78079bc940ec28da2e2770dac6b1f9bbaaeb97c88ea0e1b46db886f7035d81bde582750e560d136916ecdab8a2
-AUX qemu-2.9.0-CVE-2017-7539.patch 22018 SHA256 523d41e08a2aab888e3e63b4dda6a19e535fe6fba2bf08b6ead06498ca923f29 SHA512 5c81488aeae78307bee551a3a037f3b9cf55971a17c5df17f89f31224bdfa0a5e79141341314546256bffe542b781ad25151c54340a63c766086a578e5465825 WHIRLPOOL 085fc7e7d40c803a3caf15cdee77ce553b385919678ecf4bbcc3f532af5e482ca804a167af43e4f393da93aed88285690d84a3054c7f0df61d603d0046029dbc
+AUX qemu-2.9.0-CVE-2017-7493.patch 5656 SHA256 77462d39e811e58d3761523a6c580485bdfca0e74adbd10cf24c254e0ece262a SHA512 2b01f2878c98e77997b645ba80e69b5db398ef1e8f2b66344818d3c9af35dd66d49041ef9ee8aa152bf3e94970b4db282cf53909cb13b2532bc0a104251b2e81 WHIRLPOOL 23c788c5a78e126a61bd277e9fa1511cc71b8fbdc83a5bf319c5fc424219cbcceefad737844e45c11a76e047f8a49853d0a85b267f24f7b23bb7276d0edf0451
AUX qemu-2.9.0-CVE-2017-8112.patch 696 SHA256 a4dcc2a94749a5c20ef38d4c7ce13cd1ffe46017c77eea29ced0bec5c232e6aa SHA512 840f5270332729e0149a4705bae5fcc16e9503a995d6bfa5033904a544add337ca8ccb1d2a36bb57cc198f6354f5253403f1c4f04cbd18c08b4e1a9d6af9e07f WHIRLPOOL 1ba4e75fdd0c767254c85754612da9e8ff9ba2e7ea0811f723844bec190946805cd59db83f347a3dea4296d2b58d2df4a8d99a492335ba818824348bcebdd556
AUX qemu-2.9.0-CVE-2017-8309.patch 595 SHA256 8231747fe4d9c97392fe44b117caccd07d320313dc27fad17ac658122113ced9 SHA512 4415c36acb4f0594de7fe0de2b669d03d6b54ae44eb7f1f285c36223a02cca887b57db27a43ab1cc2e7e193ee5bce2748f9d2056aa925e0cc8f2133e67168a74 WHIRLPOOL af4c5e9763a0e114e554a1c8be99ea79da0b634fdc9d87922c7713187f1f904bfcce103648d549bbb190e92443664dbb9bd7592d8137f2337be0f4b22d1f9bd1
AUX qemu-2.9.0-CVE-2017-8379.patch 2736 SHA256 f2f8910c8e1ce9fc9804f4fbbe978fee20ccbfccc5efe49f42cdaafa63c511ce SHA512 79e32f75d98ca4a92a5069b65c5b9cff16064255ed4d161e4e292b97373742c25d5ddc12dfffa627197fdb5e0808108b30d0182a9c060cd181723bd90c618d15 WHIRLPOOL 545c00189da3b252c80bb35c6b6d3368a02b36b06f2866838ddd9ebb9ccf2b608ae278ee192b6b3aef2966736afe9bcdd646c80c228ec5daef76b92bd2721bd5
diff --git a/app-emulation/qemu/files/qemu-2.9.0-CVE-2017-7493.patch b/app-emulation/qemu/files/qemu-2.9.0-CVE-2017-7493.patch
new file mode 100644
index 00000000..346e7713
--- /dev/null
+++ b/app-emulation/qemu/files/qemu-2.9.0-CVE-2017-7493.patch
@@ -0,0 +1,174 @@
+From 7a95434e0ca8a037fd8aa1a2e2461f92585eb77b Mon Sep 17 00:00:00 2001
+From: Greg Kurz <groug@kaod.org>
+Date: Fri, 5 May 2017 14:48:08 +0200
+Subject: [PATCH] 9pfs: local: forbid client access to metadata (CVE-2017-7493)
+
+When using the mapped-file security mode, we shouldn't let the client mess
+with the metadata. The current code already tries to hide the metadata dir
+from the client by skipping it in local_readdir(). But the client can still
+access or modify it through several other operations. This can be used to
+escalate privileges in the guest.
+
+Affected backend operations are:
+- local_mknod()
+- local_mkdir()
+- local_open2()
+- local_symlink()
+- local_link()
+- local_unlinkat()
+- local_renameat()
+- local_rename()
+- local_name_to_path()
+
+Other operations are safe because they are only passed a fid path, which
+is computed internally in local_name_to_path().
+
+This patch converts all the functions listed above to fail and return
+EINVAL when being passed the name of the metadata dir. This may look
+like a poor choice for errno, but there's no such thing as an illegal
+path name on Linux and I could not think of anything better.
+
+This fixes CVE-2017-7493.
+
+Reported-by: Leo Gaspard <leo@gaspard.io>
+Signed-off-by: Greg Kurz <groug@kaod.org>
+Reviewed-by: Eric Blake <eblake@redhat.com>
+---
+ hw/9pfs/9p-local.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 56 insertions(+), 2 deletions(-)
+
+diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c
+index f3ebca4f7a..a2486566af 100644
+--- a/hw/9pfs/9p-local.c
++++ b/hw/9pfs/9p-local.c
+@@ -452,6 +452,11 @@ static off_t local_telldir(FsContext *ctx, V9fsFidOpenState *fs)
+ return telldir(fs->dir.stream);
+ }
+
++static bool local_is_mapped_file_metadata(FsContext *fs_ctx, const char *name)
++{
++ return !strcmp(name, VIRTFS_META_DIR);
++}
++
+ static struct dirent *local_readdir(FsContext *ctx, V9fsFidOpenState *fs)
+ {
+ struct dirent *entry;
+@@ -465,8 +470,8 @@ again:
+ if (ctx->export_flags & V9FS_SM_MAPPED) {
+ entry->d_type = DT_UNKNOWN;
+ } else if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
+- if (!strcmp(entry->d_name, VIRTFS_META_DIR)) {
+- /* skp the meta data directory */
++ if (local_is_mapped_file_metadata(ctx, entry->d_name)) {
++ /* skip the meta data directory */
+ goto again;
+ }
+ entry->d_type = DT_UNKNOWN;
+@@ -559,6 +564,12 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
+ int err = -1;
+ int dirfd;
+
++ if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE &&
++ local_is_mapped_file_metadata(fs_ctx, name)) {
++ errno = EINVAL;
++ return -1;
++ }
++
+ dirfd = local_opendir_nofollow(fs_ctx, dir_path->data);
+ if (dirfd == -1) {
+ return -1;
+@@ -605,6 +616,12 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
+ int err = -1;
+ int dirfd;
+
++ if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE &&
++ local_is_mapped_file_metadata(fs_ctx, name)) {
++ errno = EINVAL;
++ return -1;
++ }
++
+ dirfd = local_opendir_nofollow(fs_ctx, dir_path->data);
+ if (dirfd == -1) {
+ return -1;
+@@ -694,6 +711,12 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
+ int err = -1;
+ int dirfd;
+
++ if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE &&
++ local_is_mapped_file_metadata(fs_ctx, name)) {
++ errno = EINVAL;
++ return -1;
++ }
++
+ /*
+ * Mark all the open to not follow symlinks
+ */
+@@ -752,6 +775,12 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
+ int err = -1;
+ int dirfd;
+
++ if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE &&
++ local_is_mapped_file_metadata(fs_ctx, name)) {
++ errno = EINVAL;
++ return -1;
++ }
++
+ dirfd = local_opendir_nofollow(fs_ctx, dir_path->data);
+ if (dirfd == -1) {
+ return -1;
+@@ -826,6 +855,12 @@ static int local_link(FsContext *ctx, V9fsPath *oldpath,
+ int ret = -1;
+ int odirfd, ndirfd;
+
++ if (ctx->export_flags & V9FS_SM_MAPPED_FILE &&
++ local_is_mapped_file_metadata(ctx, name)) {
++ errno = EINVAL;
++ return -1;
++ }
++
+ odirfd = local_opendir_nofollow(ctx, odirpath);
+ if (odirfd == -1) {
+ goto out;
+@@ -1096,6 +1131,12 @@ static int local_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
+ static int local_name_to_path(FsContext *ctx, V9fsPath *dir_path,
+ const char *name, V9fsPath *target)
+ {
++ if (ctx->export_flags & V9FS_SM_MAPPED_FILE &&
++ local_is_mapped_file_metadata(ctx, name)) {
++ errno = EINVAL;
++ return -1;
++ }
++
+ if (dir_path) {
+ v9fs_path_sprintf(target, "%s/%s", dir_path->data, name);
+ } else if (strcmp(name, "/")) {
+@@ -1116,6 +1157,13 @@ static int local_renameat(FsContext *ctx, V9fsPath *olddir,
+ int ret;
+ int odirfd, ndirfd;
+
++ if (ctx->export_flags & V9FS_SM_MAPPED_FILE &&
++ (local_is_mapped_file_metadata(ctx, old_name) ||
++ local_is_mapped_file_metadata(ctx, new_name))) {
++ errno = EINVAL;
++ return -1;
++ }
++
+ odirfd = local_opendir_nofollow(ctx, olddir->data);
+ if (odirfd == -1) {
+ return -1;
+@@ -1206,6 +1254,12 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
+ int ret;
+ int dirfd;
+
++ if (ctx->export_flags & V9FS_SM_MAPPED_FILE &&
++ local_is_mapped_file_metadata(ctx, name)) {
++ errno = EINVAL;
++ return -1;
++ }
++
+ dirfd = local_opendir_nofollow(ctx, dir->data);
+ if (dirfd == -1) {
+ return -1;
+--
+2.13.0
+
diff --git a/app-emulation/qemu/files/qemu-2.9.0-CVE-2017-7539.patch b/app-emulation/qemu/files/qemu-2.9.0-CVE-2017-7539.patch
deleted file mode 100644
index 3af16977..00000000
--- a/app-emulation/qemu/files/qemu-2.9.0-CVE-2017-7539.patch
+++ /dev/null
@@ -1,601 +0,0 @@
-From 2b0bbc4f8809c972bad134bc1a2570dbb01dea0b Mon Sep 17 00:00:00 2001
-From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
-Date: Fri, 2 Jun 2017 18:01:41 +0300
-Subject: [PATCH] nbd/server: get rid of nbd_negotiate_read and friends
-
-Functions nbd_negotiate_{read,write,drop_sync} were introduced in
-1a6245a5b, when nbd_rwv (was nbd_wr_sync) was working through
-qemu_co_sendv_recvv (the path is nbd_wr_sync -> qemu_co_{recv/send} ->
-qemu_co_send_recv -> qemu_co_sendv_recvv), which just yields, without
-setting any handlers. But starting from ff82911cd nbd_rwv (was
-nbd_wr_syncv) works through qio_channel_yield() which sets handlers, so
-watchers are redundant in nbd_negotiate_{read,write,drop_sync}, then,
-let's just use nbd_{read,write,drop} functions.
-
-Functions nbd_{read,write,drop} has errp parameter, which is unused in
-this patch. This will be fixed later.
-
-Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
-Reviewed-by: Eric Blake <eblake@redhat.com>
-Message-Id: <20170602150150.258222-4-vsementsov@virtuozzo.com>
-Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
----
- nbd/server.c | 107 ++++++++++++-----------------------------------------------
- 1 file changed, 22 insertions(+), 85 deletions(-)
-
-diff --git a/nbd/client.c b/nbd/client.c
-index a58fb02..6b74a62 100644
---- a/nbd/client.c
-+++ b/nbd/client.c
-@@ -86,9 +86,9 @@ static QTAILQ_HEAD(, NBDExport) exports = QTAILQ_HEAD_INITIALIZER(exports);
-
- */
-
--/* Discard length bytes from channel. Return -errno on failure, or
-- * the amount of bytes consumed. */
--static ssize_t drop_sync(QIOChannel *ioc, size_t size)
-+/* Discard length bytes from channel. Return -errno on failure and 0 on
-+ * success*/
-+static int drop_sync(QIOChannel *ioc, size_t size)
- {
- ssize_t ret = 0;
- char small[1024];
-@@ -96,14 +96,13 @@ static ssize_t drop_sync(QIOChannel *ioc, size_t size)
-
- buffer = sizeof(small) >= size ? small : g_malloc(MIN(65536, size));
- while (size > 0) {
-- ssize_t count = read_sync(ioc, buffer, MIN(65536, size));
-+ ssize_t count = MIN(65536, size);
-+ ret = read_sync(ioc, buffer, MIN(65536, size));
-
-- if (count <= 0) {
-+ if (ret < 0) {
- goto cleanup;
- }
-- assert(count <= size);
- size -= count;
-- ret += count;
- }
-
- cleanup:
-@@ -136,12 +135,12 @@ static int nbd_send_option_request(QIOChannel *ioc, uint32_t opt,
- stl_be_p(&req.option, opt);
- stl_be_p(&req.length, len);
-
-- if (write_sync(ioc, &req, sizeof(req)) != sizeof(req)) {
-+ if (write_sync(ioc, &req, sizeof(req)) < 0) {
- error_setg(errp, "Failed to send option request header");
- return -1;
- }
-
-- if (len && write_sync(ioc, (char *) data, len) != len) {
-+ if (len && write_sync(ioc, (char *) data, len) < 0) {
- error_setg(errp, "Failed to send option request data");
- return -1;
- }
-@@ -170,7 +169,7 @@ static int nbd_receive_option_reply(QIOChannel *ioc, uint32_t opt,
- nbd_opt_reply *reply, Error **errp)
- {
- QEMU_BUILD_BUG_ON(sizeof(*reply) != 20);
-- if (read_sync(ioc, reply, sizeof(*reply)) != sizeof(*reply)) {
-+ if (read_sync(ioc, reply, sizeof(*reply)) < 0) {
- error_setg(errp, "failed to read option reply");
- nbd_send_opt_abort(ioc);
- return -1;
-@@ -219,7 +218,7 @@ static int nbd_handle_reply_err(QIOChannel *ioc, nbd_opt_reply *reply,
- goto cleanup;
- }
- msg = g_malloc(reply->length + 1);
-- if (read_sync(ioc, msg, reply->length) != reply->length) {
-+ if (read_sync(ioc, msg, reply->length) < 0) {
- error_setg(errp, "failed to read option error message");
- goto cleanup;
- }
-@@ -321,7 +320,7 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match,
- nbd_send_opt_abort(ioc);
- return -1;
- }
-- if (read_sync(ioc, &namelen, sizeof(namelen)) != sizeof(namelen)) {
-+ if (read_sync(ioc, &namelen, sizeof(namelen)) < 0) {
- error_setg(errp, "failed to read option name length");
- nbd_send_opt_abort(ioc);
- return -1;
-@@ -334,7 +333,7 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match,
- return -1;
- }
- if (namelen != strlen(want)) {
-- if (drop_sync(ioc, len) != len) {
-+ if (drop_sync(ioc, len) < 0) {
- error_setg(errp, "failed to skip export name with wrong length");
- nbd_send_opt_abort(ioc);
- return -1;
-@@ -343,14 +342,14 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match,
- }
-
- assert(namelen < sizeof(name));
-- if (read_sync(ioc, name, namelen) != namelen) {
-+ if (read_sync(ioc, name, namelen) < 0) {
- error_setg(errp, "failed to read export name");
- nbd_send_opt_abort(ioc);
- return -1;
- }
- name[namelen] = '\0';
- len -= namelen;
-- if (drop_sync(ioc, len) != len) {
-+ if (drop_sync(ioc, len) < 0) {
- error_setg(errp, "failed to read export description");
- nbd_send_opt_abort(ioc);
- return -1;
-@@ -477,7 +476,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags,
- goto fail;
- }
-
-- if (read_sync(ioc, buf, 8) != 8) {
-+ if (read_sync(ioc, buf, 8) < 0) {
- error_setg(errp, "Failed to read data");
- goto fail;
- }
-@@ -503,7 +502,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags,
- goto fail;
- }
-
-- if (read_sync(ioc, &magic, sizeof(magic)) != sizeof(magic)) {
-+ if (read_sync(ioc, &magic, sizeof(magic)) < 0) {
- error_setg(errp, "Failed to read magic");
- goto fail;
- }
-@@ -515,8 +514,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags,
- uint16_t globalflags;
- bool fixedNewStyle = false;
-
-- if (read_sync(ioc, &globalflags, sizeof(globalflags)) !=
-- sizeof(globalflags)) {
-+ if (read_sync(ioc, &globalflags, sizeof(globalflags)) < 0) {
- error_setg(errp, "Failed to read server flags");
- goto fail;
- }
-@@ -534,8 +532,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags,
- }
- /* client requested flags */
- clientflags = cpu_to_be32(clientflags);
-- if (write_sync(ioc, &clientflags, sizeof(clientflags)) !=
-- sizeof(clientflags)) {
-+ if (write_sync(ioc, &clientflags, sizeof(clientflags)) < 0) {
- error_setg(errp, "Failed to send clientflags field");
- goto fail;
- }
-@@ -573,13 +570,13 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags,
- }
-
- /* Read the response */
-- if (read_sync(ioc, &s, sizeof(s)) != sizeof(s)) {
-+ if (read_sync(ioc, &s, sizeof(s)) < 0) {
- error_setg(errp, "Failed to read export length");
- goto fail;
- }
- *size = be64_to_cpu(s);
-
-- if (read_sync(ioc, flags, sizeof(*flags)) != sizeof(*flags)) {
-+ if (read_sync(ioc, flags, sizeof(*flags)) < 0) {
- error_setg(errp, "Failed to read export flags");
- goto fail;
- }
-@@ -596,14 +593,14 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags,
- goto fail;
- }
-
-- if (read_sync(ioc, &s, sizeof(s)) != sizeof(s)) {
-+ if (read_sync(ioc, &s, sizeof(s)) < 0) {
- error_setg(errp, "Failed to read export length");
- goto fail;
- }
- *size = be64_to_cpu(s);
- TRACE("Size is %" PRIu64, *size);
-
-- if (read_sync(ioc, &oldflags, sizeof(oldflags)) != sizeof(oldflags)) {
-+ if (read_sync(ioc, &oldflags, sizeof(oldflags)) < 0) {
- error_setg(errp, "Failed to read export flags");
- goto fail;
- }
-@@ -619,7 +616,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags,
- }
-
- TRACE("Size is %" PRIu64 ", export flags %" PRIx16, *size, *flags);
-- if (zeroes && drop_sync(ioc, 124) != 124) {
-+ if (zeroes && drop_sync(ioc, 124) < 0) {
- error_setg(errp, "Failed to read reserved block");
- goto fail;
- }
-@@ -744,7 +741,6 @@ int nbd_disconnect(int fd)
- ssize_t nbd_send_request(QIOChannel *ioc, NBDRequest *request)
- {
- uint8_t buf[NBD_REQUEST_SIZE];
-- ssize_t ret;
-
- TRACE("Sending request to server: "
- "{ .from = %" PRIu64", .len = %" PRIu32 ", .handle = %" PRIu64
-@@ -759,16 +755,7 @@ ssize_t nbd_send_request(QIOChannel *ioc, NBDRequest *request)
- stq_be_p(buf + 16, request->from);
- stl_be_p(buf + 24, request->len);
-
-- ret = write_sync(ioc, buf, sizeof(buf));
-- if (ret < 0) {
-- return ret;
-- }
--
-- if (ret != sizeof(buf)) {
-- LOG("writing to socket failed");
-- return -EINVAL;
-- }
-- return 0;
-+ return write_sync(ioc, buf, sizeof(buf));
- }
-
- ssize_t nbd_receive_reply(QIOChannel *ioc, NBDReply *reply)
-@@ -777,7 +764,7 @@ ssize_t nbd_receive_reply(QIOChannel *ioc, NBDReply *reply)
- uint32_t magic;
- ssize_t ret;
-
-- ret = read_sync(ioc, buf, sizeof(buf));
-+ ret = read_sync_eof(ioc, buf, sizeof(buf));
- if (ret <= 0) {
- return ret;
- }
-diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h
-index f43d990..e6bbc7c 100644
---- a/nbd/nbd-internal.h
-+++ b/nbd/nbd-internal.h
-@@ -94,7 +94,13 @@
- #define NBD_ENOSPC 28
- #define NBD_ESHUTDOWN 108
-
--static inline ssize_t read_sync(QIOChannel *ioc, void *buffer, size_t size)
-+/* read_sync_eof
-+ * Tries to read @size bytes from @ioc. Returns number of bytes actually read.
-+ * May return a value >= 0 and < size only on EOF, i.e. when iteratively called
-+ * qio_channel_readv() returns 0. So, there are no needs to call read_sync_eof
-+ * iteratively.
-+ */
-+static inline ssize_t read_sync_eof(QIOChannel *ioc, void *buffer, size_t size)
- {
- struct iovec iov = { .iov_base = buffer, .iov_len = size };
- /* Sockets are kept in blocking mode in the negotiation phase. After
-@@ -105,12 +111,32 @@ static inline ssize_t read_sync(QIOChannel *ioc, void *buffer, size_t size)
- return nbd_wr_syncv(ioc, &iov, 1, size, true);
- }
-
--static inline ssize_t write_sync(QIOChannel *ioc, const void *buffer,
-- size_t size)
-+/* read_sync
-+ * Reads @size bytes from @ioc. Returns 0 on success.
-+ */
-+static inline int read_sync(QIOChannel *ioc, void *buffer, size_t size)
-+{
-+ ssize_t ret = read_sync_eof(ioc, buffer, size);
-+
-+ if (ret >= 0 && ret != size) {
-+ ret = -EINVAL;
-+ }
-+
-+ return ret < 0 ? ret : 0;
-+}
-+
-+/* write_sync
-+ * Writes @size bytes to @ioc. Returns 0 on success.
-+ */
-+static inline int write_sync(QIOChannel *ioc, const void *buffer, size_t size)
- {
- struct iovec iov = { .iov_base = (void *) buffer, .iov_len = size };
-
-- return nbd_wr_syncv(ioc, &iov, 1, size, false);
-+ ssize_t ret = nbd_wr_syncv(ioc, &iov, 1, size, false);
-+
-+ assert(ret < 0 || ret == size);
-+
-+ return ret < 0 ? ret : 0;
- }
-
- struct NBDTLSHandshakeData {
-diff --git a/nbd/server.c b/nbd/server.c
-index 924a1fe..a1f106b 100644
---- a/nbd/server.c
-+++ b/nbd/server.c
-@@ -104,69 +104,6 @@ struct NBDClient {
-
- static void nbd_client_receive_next_request(NBDClient *client);
-
--static gboolean nbd_negotiate_continue(QIOChannel *ioc,
-- GIOCondition condition,
-- void *opaque)
--{
-- qemu_coroutine_enter(opaque);
-- return TRUE;
--}
--
--static ssize_t nbd_negotiate_read(QIOChannel *ioc, void *buffer, size_t size)
--{
-- ssize_t ret;
-- guint watch;
--
-- assert(qemu_in_coroutine());
-- /* Negotiation are always in main loop. */
-- watch = qio_channel_add_watch(ioc,
-- G_IO_IN,
-- nbd_negotiate_continue,
-- qemu_coroutine_self(),
-- NULL);
-- ret = read_sync(ioc, buffer, size);
-- g_source_remove(watch);
-- return ret;
--
--}
--
--static ssize_t nbd_negotiate_write(QIOChannel *ioc, const void *buffer,
-- size_t size)
--{
-- ssize_t ret;
-- guint watch;
--
-- assert(qemu_in_coroutine());
-- /* Negotiation are always in main loop. */
-- watch = qio_channel_add_watch(ioc,
-- G_IO_OUT,
-- nbd_negotiate_continue,
-- qemu_coroutine_self(),
-- NULL);
-- ret = write_sync(ioc, buffer, size);
-- g_source_remove(watch);
-- return ret;
--}
--
--static ssize_t nbd_negotiate_drop_sync(QIOChannel *ioc, size_t size)
--{
-- ssize_t ret, dropped = size;
-- uint8_t *buffer = g_malloc(MIN(65536, size));
--
-- while (size > 0) {
-- ret = nbd_negotiate_read(ioc, buffer, MIN(65536, size));
-- if (ret < 0) {
-- g_free(buffer);
-- return ret;
-- }
--
-- assert(ret <= size);
-- size -= ret;
-- }
--
-- g_free(buffer);
-- return dropped;
--}
-
- /* Basic flow for negotiation
-
-@@ -206,22 +143,22 @@ static int nbd_negotiate_send_rep_len(QIOChannel *ioc, uint32_t type,
- type, opt, len);
-
- magic = cpu_to_be64(NBD_REP_MAGIC);
-- if (nbd_negotiate_write(ioc, &magic, sizeof(magic)) != sizeof(magic)) {
-+ if (nbd_write(ioc, &magic, sizeof(magic), NULL) < 0) {
- LOG("write failed (rep magic)");
- return -EINVAL;
- }
- opt = cpu_to_be32(opt);
-- if (nbd_negotiate_write(ioc, &opt, sizeof(opt)) != sizeof(opt)) {
-+ if (nbd_write(ioc, &opt, sizeof(opt), NULL) < 0) {
- LOG("write failed (rep opt)");
- return -EINVAL;
- }
- type = cpu_to_be32(type);
-- if (nbd_negotiate_write(ioc, &type, sizeof(type)) != sizeof(type)) {
-+ if (nbd_write(ioc, &type, sizeof(type), NULL) < 0) {
- LOG("write failed (rep type)");
- return -EINVAL;
- }
- len = cpu_to_be32(len);
-- if (nbd_negotiate_write(ioc, &len, sizeof(len)) != sizeof(len)) {
-+ if (nbd_write(ioc, &len, sizeof(len), NULL) < 0) {
- LOG("write failed (rep data length)");
- return -EINVAL;
- }
-@@ -256,7 +193,7 @@ nbd_negotiate_send_rep_err(QIOChannel *ioc, uint32_t type,
- if (ret < 0) {
- goto out;
- }
-- if (nbd_negotiate_write(ioc, msg, len) != len) {
-+ if (nbd_write(ioc, msg, len, NULL) < 0) {
- LOG("write failed (error message)");
- ret = -EIO;
- } else {
-@@ -287,15 +224,15 @@ static int nbd_negotiate_send_rep_list(QIOChannel *ioc, NBDExport *exp)
- }
-
- len = cpu_to_be32(name_len);
-- if (nbd_negotiate_write(ioc, &len, sizeof(len)) != sizeof(len)) {
-+ if (nbd_write(ioc, &len, sizeof(len), NULL) < 0) {
- LOG("write failed (name length)");
- return -EINVAL;
- }
-- if (nbd_negotiate_write(ioc, name, name_len) != name_len) {
-+ if (nbd_write(ioc, name, name_len, NULL) < 0) {
- LOG("write failed (name buffer)");
- return -EINVAL;
- }
-- if (nbd_negotiate_write(ioc, desc, desc_len) != desc_len) {
-+ if (nbd_write(ioc, desc, desc_len, NULL) < 0) {
- LOG("write failed (description buffer)");
- return -EINVAL;
- }
-@@ -309,7 +246,7 @@ static int nbd_negotiate_handle_list(NBDClient *client, uint32_t length)
- NBDExport *exp;
-
- if (length) {
-- if (nbd_negotiate_drop_sync(client->ioc, length) != length) {
-+ if (nbd_drop(client->ioc, length, NULL) < 0) {
- return -EIO;
- }
- return nbd_negotiate_send_rep_err(client->ioc,
-@@ -340,7 +277,7 @@ static int nbd_negotiate_handle_export_name(NBDClient *client, uint32_t length)
- LOG("Bad length received");
- goto fail;
- }
-- if (nbd_negotiate_read(client->ioc, name, length) != length) {
-+ if (nbd_read(client->ioc, name, length, NULL) < 0) {
- LOG("read failed");
- goto fail;
- }
-@@ -373,7 +310,7 @@ static QIOChannel *nbd_negotiate_handle_starttls(NBDClient *client,
- TRACE("Setting up TLS");
- ioc = client->ioc;
- if (length) {
-- if (nbd_negotiate_drop_sync(ioc, length) != length) {
-+ if (nbd_drop(ioc, length, NULL) < 0) {
- return NULL;
- }
- nbd_negotiate_send_rep_err(ioc, NBD_REP_ERR_INVALID, NBD_OPT_STARTTLS,
-@@ -437,8 +374,7 @@ static int nbd_negotiate_options(NBDClient *client)
- ... Rest of request
- */
-
-- if (nbd_negotiate_read(client->ioc, &flags, sizeof(flags)) !=
-- sizeof(flags)) {
-+ if (nbd_read(client->ioc, &flags, sizeof(flags), NULL) < 0) {
- LOG("read failed");
- return -EIO;
- }
-@@ -464,8 +400,7 @@ static int nbd_negotiate_options(NBDClient *client)
- uint32_t clientflags, length;
- uint64_t magic;
-
-- if (nbd_negotiate_read(client->ioc, &magic, sizeof(magic)) !=
-- sizeof(magic)) {
-+ if (nbd_read(client->ioc, &magic, sizeof(magic), NULL) < 0) {
- LOG("read failed");
- return -EINVAL;
- }
-@@ -475,15 +410,15 @@ static int nbd_negotiate_options(NBDClient *client)
- return -EINVAL;
- }
-
-- if (nbd_negotiate_read(client->ioc, &clientflags,
-- sizeof(clientflags)) != sizeof(clientflags)) {
-+ if (nbd_read(client->ioc, &clientflags,
-+ sizeof(clientflags), NULL) < 0)
-+ {
- LOG("read failed");
- return -EINVAL;
- }
- clientflags = be32_to_cpu(clientflags);
-
-- if (nbd_negotiate_read(client->ioc, &length, sizeof(length)) !=
-- sizeof(length)) {
-+ if (nbd_read(client->ioc, &length, sizeof(length), NULL) < 0) {
- LOG("read failed");
- return -EINVAL;
- }
-@@ -513,7 +448,7 @@ static int nbd_negotiate_options(NBDClient *client)
- return -EINVAL;
-
- default:
-- if (nbd_negotiate_drop_sync(client->ioc, length) != length) {
-+ if (nbd_drop(client->ioc, length, NULL) < 0) {
- return -EIO;
- }
- ret = nbd_negotiate_send_rep_err(client->ioc,
-@@ -551,7 +486,7 @@ static int nbd_negotiate_options(NBDClient *client)
- return nbd_negotiate_handle_export_name(client, length);
-
- case NBD_OPT_STARTTLS:
-- if (nbd_negotiate_drop_sync(client->ioc, length) != length) {
-+ if (nbd_drop(client->ioc, length, NULL) < 0) {
- return -EIO;
- }
- if (client->tlscreds) {
-@@ -570,7 +505,7 @@ static int nbd_negotiate_options(NBDClient *client)
- }
- break;
- default:
-- if (nbd_negotiate_drop_sync(client->ioc, length) != length) {
-+ if (nbd_drop(client->ioc, length, NULL) < 0) {
- return -EIO;
- }
- ret = nbd_negotiate_send_rep_err(client->ioc,
-@@ -659,12 +594,12 @@ static coroutine_fn int nbd_negotiate(NBDClientNewData *data)
- TRACE("TLS cannot be enabled with oldstyle protocol");
- goto fail;
- }
-- if (nbd_negotiate_write(client->ioc, buf, sizeof(buf)) != sizeof(buf)) {
-+ if (nbd_write(client->ioc, buf, sizeof(buf), NULL) < 0) {
- LOG("write failed");
- goto fail;
- }
- } else {
-- if (nbd_negotiate_write(client->ioc, buf, 18) != 18) {
-+ if (nbd_write(client->ioc, buf, 18, NULL) < 0) {
- LOG("write failed");
- goto fail;
- }
-@@ -679,7 +614,7 @@ static coroutine_fn int nbd_negotiate(NBDClientNewData *data)
- stq_be_p(buf + 18, client->exp->size);
- stw_be_p(buf + 26, client->exp->nbdflags | myflags);
- len = client->no_zeroes ? 10 : sizeof(buf) - 18;
-- if (nbd_negotiate_write(client->ioc, buf + 18, len) != len) {
-+ if (nbd_write(client->ioc, buf + 18, len, NULL) < 0) {
- LOG("write failed");
- goto fail;
- }
-@@ -702,11 +637,6 @@ static ssize_t nbd_receive_request(QIOChannel *ioc, NBDRequest *request)
- return ret;
- }
-
-- if (ret != sizeof(buf)) {
-- LOG("read failed");
-- return -EINVAL;
-- }
--
- /* Request
- [ 0 .. 3] magic (NBD_REQUEST_MAGIC)
- [ 4 .. 5] flags (NBD_CMD_FLAG_FUA, ...)
-@@ -737,7 +667,6 @@ static ssize_t nbd_receive_request(QIOChannel *ioc, NBDRequest *request)
- static ssize_t nbd_send_reply(QIOChannel *ioc, NBDReply *reply)
- {
- uint8_t buf[NBD_REPLY_SIZE];
-- ssize_t ret;
-
- reply->error = system_errno_to_nbd_errno(reply->error);
-
-@@ -754,16 +683,7 @@ static ssize_t nbd_send_reply(QIOChannel *ioc, NBDReply *reply)
- stl_be_p(buf + 4, reply->error);
- stq_be_p(buf + 8, reply->handle);
-
-- ret = write_sync(ioc, buf, sizeof(buf));
-- if (ret < 0) {
-- return ret;
-- }
--
-- if (ret != sizeof(buf)) {
-- LOG("writing to socket failed");
-- return -EINVAL;
-- }
-- return 0;
-+ return write_sync(ioc, buf, sizeof(buf));
- }
-
- #define MAX_NBD_REQUESTS 16
-@@ -1067,7 +987,7 @@ static ssize_t nbd_co_send_reply(NBDRequestData *req, NBDReply *reply,
- rc = nbd_send_reply(client->ioc, reply);
- if (rc >= 0) {
- ret = write_sync(client->ioc, req->data, len);
-- if (ret != len) {
-+ if (ret < 0) {
- rc = -EIO;
- }
- }
-@@ -1141,7 +1061,7 @@ static ssize_t nbd_co_receive_request(NBDRequestData *req,
- if (request->type == NBD_CMD_WRITE) {
- TRACE("Reading %" PRIu32 " byte(s)", request->len);
-
-- if (read_sync(client->ioc, req->data, request->len) != request->len) {
-+ if (read_sync(client->ioc, req->data, request->len) < 0) {
- LOG("reading from socket failed");
- rc = -EIO;
- goto out;