From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.gentoo.org (pigeon.gentoo.org [208.92.234.80]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by finch.gentoo.org (Postfix) with ESMTPS id 6BF0D139083 for ; Thu, 27 Jul 2017 17:59:44 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id B26BF1FC044; Thu, 27 Jul 2017 17:59:43 +0000 (UTC) Received: from smtp.gentoo.org (dev.gentoo.org [IPv6:2001:470:ea4a:1:5054:ff:fec7:86e4]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id 81E331FC044 for ; Thu, 27 Jul 2017 17:59:43 +0000 (UTC) Received: from oystercatcher.gentoo.org (oystercatcher.gentoo.org [148.251.78.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 13D9134191D for ; Thu, 27 Jul 2017 17:59:42 +0000 (UTC) Received: from localhost.localdomain (localhost [IPv6:::1]) by oystercatcher.gentoo.org (Postfix) with ESMTP id 949F42FA for ; Thu, 27 Jul 2017 17:59:40 +0000 (UTC) From: "Aric Belsito" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Aric Belsito" Message-ID: <1501178341.9212f510625a88c624d5d8d9456842091ee93305.lluixhi@gentoo> Subject: [gentoo-commits] proj/musl:master commit in: app-emulation/qemu/, app-emulation/qemu/files/ X-VCS-Repository: proj/musl X-VCS-Files: app-emulation/qemu/Manifest app-emulation/qemu/files/qemu-2.9.0-CVE-2017-7493.patch app-emulation/qemu/files/qemu-2.9.0-CVE-2017-7539.patch X-VCS-Directories: app-emulation/qemu/files/ app-emulation/qemu/ X-VCS-Committer: lluixhi X-VCS-Committer-Name: Aric Belsito X-VCS-Revision: 9212f510625a88c624d5d8d9456842091ee93305 X-VCS-Branch: master Date: Thu, 27 Jul 2017 17:59:40 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org X-Archives-Salt: 2ead0d58-cf6c-44a2-b23e-7523e322b4d6 X-Archives-Hash: 937f2b44fab517d9bf35a7b4c1f5fe5b commit: 9212f510625a88c624d5d8d9456842091ee93305 Author: Aric Belsito gmail com> AuthorDate: Thu Jul 27 17:59:01 2017 +0000 Commit: Aric Belsito gmail com> CommitDate: Thu Jul 27 17:59:01 2017 +0000 URL: https://gitweb.gentoo.org/proj/musl.git/commit/?id=9212f510 app-emulation/qemu: restore patch deleted the wrong one.. app-emulation/qemu/Manifest | 2 +- .../qemu/files/qemu-2.9.0-CVE-2017-7493.patch | 174 ++++++ .../qemu/files/qemu-2.9.0-CVE-2017-7539.patch | 601 --------------------- 3 files changed, 175 insertions(+), 602 deletions(-) diff --git a/app-emulation/qemu/Manifest b/app-emulation/qemu/Manifest index e4a3f79..e3f4bd2 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 0000000..346e771 --- /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 +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 +Signed-off-by: Greg Kurz +Reviewed-by: Eric Blake +--- + 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 3af1697..0000000 --- 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 -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 -Reviewed-by: Eric Blake -Message-Id: <20170602150150.258222-4-vsementsov@virtuozzo.com> -Signed-off-by: Paolo Bonzini ---- - 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;