import CS libnbd-1.20.2-2.el9

This commit is contained in:
eabdullin 2024-09-30 15:53:09 +00:00
parent 11bb9b4ab6
commit 2b6d9962e9
14 changed files with 551 additions and 387 deletions

2
.gitignore vendored
View File

@ -1,2 +1,2 @@
SOURCES/libguestfs.keyring SOURCES/libguestfs.keyring
SOURCES/libnbd-1.18.1.tar.gz SOURCES/libnbd-1.20.2.tar.gz

View File

@ -1,2 +1,2 @@
cc1b37b9cfafa515aab3eefd345ecc59aac2ce7b SOURCES/libguestfs.keyring cc1b37b9cfafa515aab3eefd345ecc59aac2ce7b SOURCES/libguestfs.keyring
4f99e6f21edffe62b394aa9c7fb68149e6d4d5e4 SOURCES/libnbd-1.18.1.tar.gz d3abc6e794dd4b99640328bfd395a8913288e859 SOURCES/libnbd-1.20.2.tar.gz

View File

@ -1,88 +0,0 @@
From 4451e5b61ca07771ceef3e012223779e7a0c7701 Mon Sep 17 00:00:00 2001
From: Eric Blake <eblake@redhat.com>
Date: Mon, 30 Oct 2023 12:50:53 -0500
Subject: [PATCH] generator: Fix assertion in ext-mode BLOCK_STATUS,
CVE-2023-5871
Another round of fuzz testing revealed that when a server negotiates
extended headers and replies with a 64-bit flag value where the client
used the 32-bit API command, we were correctly flagging the server's
response as being an EOVERFLOW condition, but then immediately failing
in an assertion failure instead of reporting it to the application.
The following one-byte change to qemu.git at commit fd9a38fd43 allows
the creation of an intentionally malicious server:
| diff --git i/nbd/server.c w/nbd/server.c
| index 859c163d19f..32e1e771a95 100644
| --- i/nbd/server.c
| +++ w/nbd/server.c
| @@ -2178,7 +2178,7 @@ static void nbd_extent_array_convert_to_be(NBDExtentArray *ea)
|
| for (i = 0; i < ea->count; i++) {
| ea->extents[i].length = cpu_to_be64(ea->extents[i].length);
| - ea->extents[i].flags = cpu_to_be64(ea->extents[i].flags);
| + ea->extents[i].flags = ~cpu_to_be64(ea->extents[i].flags);
| }
| }
and can then be detected with the following command line:
$ nbdsh -c - <<\EOF
> def f(a,b,c,d):
> pass
>
> h.connect_systemd_socket_activation(["/path/to/bad/qemu-nbd",
> "-r", "-f", "raw", "TODO"])
> h.block_staus(h.get_size(), 0, f)
> EOF
nbdsh: generator/states-reply-chunk.c:626: enter_STATE_REPLY_CHUNK_REPLY_RECV_BS_ENTRIES: Assertion `(len | flags) <= UINT32_MAX' failed.
Aborted (core dumped)
whereas a fixed libnbd will give:
nbdsh: command line script failed: nbd_block_status: block-status: command failed: Value too large for defined data type
We can either relax the assertion (by changing to 'assert ((len |
flags) <= UINT32_MAX || cmd->error)'), or intentionally truncate flags
to make the existing assertion reliable. This patch goes with the
latter approach.
Sadly, this crash is possible in all existing 1.18.x stable releases,
if they were built with assertions enabled (most distros do this by
default), meaning a malicious server has an easy way to cause a Denial
of Service attack by triggering the assertion failure in vulnerable
clients, so we have assigned this CVE-2023-5871. Mitigating factors:
the crash only happens for a server that sends a 64-bit status block
reply (no known production servers do so; qemu 8.2 will be the first
known server to support extended headers, but it is not yet released);
and as usual, a client can use TLS to guarantee it is connecting only
to a known-safe server. If libnbd is compiled without assertions,
there is no crash or other mistaken behavior; and when assertions are
enabled, the attacker cannot accomplish anything more than a denial of
service.
Reported-by: Richard W.M. Jones <rjones@redhat.com>
Fixes: 20dadb0e10 ("generator: Prepare for extent64 callback", v1.17.4)
Signed-off-by: Eric Blake <eblake@redhat.com>
(cherry picked from commit 177308adb17e81fce7c0f2b2fcf655c5c0b6a4d6)
Signed-off-by: Eric Blake <eblake@redhat.com>
---
generator/states-reply-chunk.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/generator/states-reply-chunk.c b/generator/states-reply-chunk.c
index 5a31c19..8ab7e8b 100644
--- a/generator/states-reply-chunk.c
+++ b/generator/states-reply-chunk.c
@@ -600,6 +600,7 @@ STATE_MACHINE {
break; /* Skip this and later extents; we already made progress */
/* Expose this extent as an error; we made no progress */
cmd->error = cmd->error ? : EOVERFLOW;
+ flags = (uint32_t)flags;
}
}
--
2.39.3

View File

@ -0,0 +1,191 @@
From 89f0e33f355681b7c5b1835a09c5fac93c08e71e Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Tue, 23 Jul 2024 17:22:12 +0100
Subject: [PATCH] generator: Print full error in handle_reply_error
Print the full error from the server during handshaking. This
modifies the contract of handle_reply_error so it calls set_error,
which can be overridden by callers or ignored completely.
(cherry picked from commit cf49a49adc8abc8c917437db7461ed9956583877)
---
generator/states-newstyle-opt-go.c | 32 +--------
generator/states-newstyle-opt-list.c | 5 +-
generator/states-newstyle-opt-meta-context.c | 8 +--
generator/states-newstyle.c | 68 ++++++++++++++++++--
4 files changed, 69 insertions(+), 44 deletions(-)
diff --git a/generator/states-newstyle-opt-go.c b/generator/states-newstyle-opt-go.c
index 5bc9a9ae..f6eb8afc 100644
--- a/generator/states-newstyle-opt-go.c
+++ b/generator/states-newstyle-opt-go.c
@@ -247,37 +247,9 @@ STATE_MACHINE {
SET_NEXT_STATE (%.DEAD);
return 0;
}
- /* Decode expected known errors into a nicer string */
- switch (reply) {
- case NBD_REP_ERR_UNSUP:
+ if (reply == NBD_REP_ERR_UNSUP)
assert (h->opt_current == NBD_OPT_INFO);
- set_error (ENOTSUP, "handshake: server lacks NBD_OPT_INFO support");
- break;
- case NBD_REP_ERR_POLICY:
- case NBD_REP_ERR_PLATFORM:
- set_error (0, "handshake: server policy prevents NBD_OPT_GO");
- break;
- case NBD_REP_ERR_INVALID:
- case NBD_REP_ERR_TOO_BIG:
- set_error (EINVAL, "handshake: server rejected NBD_OPT_GO as invalid");
- break;
- case NBD_REP_ERR_TLS_REQD:
- set_error (ENOTSUP, "handshake: server requires TLS encryption first");
- break;
- case NBD_REP_ERR_UNKNOWN:
- set_error (ENOENT, "handshake: server has no export named '%s'",
- h->export_name);
- break;
- case NBD_REP_ERR_SHUTDOWN:
- set_error (ESHUTDOWN, "handshake: server is shutting down");
- break;
- case NBD_REP_ERR_BLOCK_SIZE_REQD:
- set_error (EINVAL, "handshake: server requires specific block sizes");
- break;
- default:
- set_error (0, "handshake: unknown reply from NBD_OPT_GO: 0x%" PRIx32,
- reply);
- }
+
nbd_internal_reset_size_and_flags (h);
h->meta_valid = false;
err = nbd_get_errno () ? : ENOTSUP;
diff --git a/generator/states-newstyle-opt-list.c b/generator/states-newstyle-opt-list.c
index cdd4676e..6605ee0a 100644
--- a/generator/states-newstyle-opt-list.c
+++ b/generator/states-newstyle-opt-list.c
@@ -127,9 +127,8 @@ STATE_MACHINE {
SET_NEXT_STATE (%.DEAD);
return 0;
}
- err = ENOTSUP;
- set_error (err, "unexpected response, possibly the server does not "
- "support listing exports");
+ debug (h, "unexpected response, possibly the server does not "
+ "support listing exports");
break;
}
diff --git a/generator/states-newstyle-opt-meta-context.c b/generator/states-newstyle-opt-meta-context.c
index 6f016e66..3945411e 100644
--- a/generator/states-newstyle-opt-meta-context.c
+++ b/generator/states-newstyle-opt-meta-context.c
@@ -270,12 +270,8 @@ STATE_MACHINE {
}
if (opt == h->opt_current) {
- /* XXX Should we decode specific expected errors, like
- * REP_ERR_UNKNOWN to ENOENT or REP_ERR_TOO_BIG to ERANGE?
- */
- err = ENOTSUP;
- set_error (err, "unexpected response, possibly the server does not "
- "support meta contexts");
+ debug (h, "unexpected response, possibly the server does not "
+ "support meta contexts");
CALL_CALLBACK (h->opt_cb.completion, &err);
nbd_internal_free_option (h);
SET_NEXT_STATE (%.NEGOTIATING);
diff --git a/generator/states-newstyle.c b/generator/states-newstyle.c
index 45893a8b..6c7cc45c 100644
--- a/generator/states-newstyle.c
+++ b/generator/states-newstyle.c
@@ -79,14 +79,18 @@ prepare_for_reply_payload (struct nbd_handle *h, uint32_t opt)
return 0;
}
-/* Check an unexpected server reply. If it is an error, log any
- * message from the server and return 0; otherwise, return -1.
+/* Check an unexpected server reply error.
+ *
+ * This calls set_error with a descriptive error message and returns
+ * 0. Unless there is a further unexpected error while processing
+ * this error, in which case it calls set_error and returns -1.
*/
static int
handle_reply_error (struct nbd_handle *h)
{
uint32_t len;
uint32_t reply;
+ char *msg = NULL;
len = be32toh (h->sbuf.or.option_reply.replylen);
reply = be32toh (h->sbuf.or.option_reply.reply);
@@ -101,9 +105,63 @@ handle_reply_error (struct nbd_handle *h)
return -1;
}
- if (len > 0)
- debug (h, "handshake: server error message: %.*s", (int)len,
- h->sbuf.or.payload.err_msg);
+ /* Decode expected errors into a nicer string.
+ *
+ * XXX Note this string comes directly from the server, and most
+ * libnbd users simply print the error using 'fprintf'. We really
+ * ought to quote this string somehow, but we don't have a useful
+ * function for that.
+ */
+ if (len > 0) {
+ if (asprintf (&msg, ": %.*s",
+ (int)len, h->sbuf.or.payload.err_msg) == -1) {
+ set_error (errno, "asprintf");
+ return -1;
+ }
+ }
+
+ switch (reply) {
+ case NBD_REP_ERR_UNSUP:
+ set_error (ENOTSUP, "the operation is not supported by the server%s",
+ msg ? : "");
+ break;
+ case NBD_REP_ERR_POLICY:
+ set_error (0, "server policy prevents the operation%s",
+ msg ? : "");
+ break;
+ case NBD_REP_ERR_PLATFORM:
+ set_error (0, "the operation is not supported by the server platform%s",
+ msg ? : "");
+ break;
+ case NBD_REP_ERR_INVALID:
+ set_error (EINVAL, "the server rejected this operation as invalid%s",
+ msg ? : "");
+ break;
+ case NBD_REP_ERR_TOO_BIG:
+ set_error (EINVAL, "the operation is too large to process%s",
+ msg ? : "");
+ break;
+ case NBD_REP_ERR_TLS_REQD:
+ set_error (ENOTSUP, "the server requires TLS encryption first%s",
+ msg ? : "");
+ break;
+ case NBD_REP_ERR_UNKNOWN:
+ set_error (ENOENT, "the server has no export named '%s'%s",
+ h->export_name, msg ? : "");
+ break;
+ case NBD_REP_ERR_SHUTDOWN:
+ set_error (ESHUTDOWN, "the server is shutting down%s",
+ msg ? : "");
+ break;
+ case NBD_REP_ERR_BLOCK_SIZE_REQD:
+ set_error (EINVAL, "the server requires specific block sizes%s",
+ msg ? : "");
+ break;
+ default:
+ set_error (0, "handshake: unknown reply from the server: 0x%" PRIx32 "%s",
+ reply, msg ? : "");
+ }
+ free (msg);
return 0;
}
--
2.43.0

View File

@ -1,34 +0,0 @@
From c39e31b7a20c7dc8aa12c5fa3f1742824e1e0c76 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Thu, 9 Nov 2023 09:40:30 +0000
Subject: [libnbd PATCH] docs: Fix incorrect xref in libnbd-release-notes for
1.18
Content-type: text/plain
LIBNBD_STRICT_AUTO_FLAG was added to nbd_set_strict_mode(3).
Reported-by: Vera Wu
(cherry picked from commit 4fef3dbc07e631fce58487d25d991e83bbb424b1)
Signed-off-by: Eric Blake <eblake@redhat.com>
---
docs/libnbd-release-notes-1.18.pod | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/libnbd-release-notes-1.18.pod b/docs/libnbd-release-notes-1.18.pod
index 935fab11..836ebe19 100644
--- a/docs/libnbd-release-notes-1.18.pod
+++ b/docs/libnbd-release-notes-1.18.pod
@@ -84,8 +84,8 @@ Golang, OCaml and Python language bindings (Eric Blake).
L<nbd_shutdown(3)> now works correctly when in opt mode (Eric Blake).
-L<nbd_set_string(3)> adds C<LIBNBD_STRICT_AUTO_FLAG> which allows the
-client to test how servers behave when the payload length flag is
+L<nbd_set_strict_mode(3)> adds C<LIBNBD_STRICT_AUTO_FLAG> which allows
+the client to test how servers behave when the payload length flag is
adjusted (Eric Blake).
=head2 Protocol
--
2.41.0

View File

@ -0,0 +1,38 @@
From f31e31b32e662d0aadb77bc639308c8a65968886 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Tue, 23 Jul 2024 17:26:39 +0100
Subject: [PATCH] lib: Don't overwrite error in nbd_opt_{go,info}
We already set the error in handle_reply_error, so don't overwrite
that here.
(cherry picked from commit 474a4ae6c8d11212a4a8c06ea3e8b3fd97a7e97d)
---
lib/opt.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/opt.c b/lib/opt.c
index 600265a0..5872dd54 100644
--- a/lib/opt.c
+++ b/lib/opt.c
@@ -99,7 +99,7 @@ nbd_unlocked_opt_go (struct nbd_handle *h)
if (r == 0 && err) {
assert (nbd_internal_is_state_negotiating (get_next_state (h)) ||
nbd_internal_is_state_dead (get_next_state (h)));
- set_error (err, "server replied with error to opt_go request");
+ /* handle_reply_error already called set_error */
return -1;
}
if (r == 0)
@@ -122,7 +122,7 @@ nbd_unlocked_opt_info (struct nbd_handle *h)
if (r == 0 && err) {
assert (nbd_internal_is_state_negotiating (get_next_state (h)) ||
nbd_internal_is_state_dead (get_next_state (h)));
- set_error (err, "server replied with error to opt_info request");
+ /* handle_reply_error already called set_error */
return -1;
}
return r;
--
2.43.0

View File

@ -0,0 +1,43 @@
From ff5ee9308e66fe9fd19ea578623c4540f44942d6 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Thu, 25 Jul 2024 13:39:28 +0100
Subject: [PATCH] generator: Restore assignment to local 'err'
I accidentally removed the assignment of local variable 'err' along
these paths in commit cf49a49adc ("generator: Print full error in
handle_reply_error").
Fixes: commit cf49a49adc8abc8c917437db7461ed9956583877
(cherry picked from commit e75d20b9e19143b1bd0d232fc49cb2e0287f824a)
---
generator/states-newstyle-opt-list.c | 1 +
generator/states-newstyle-opt-meta-context.c | 1 +
2 files changed, 2 insertions(+)
diff --git a/generator/states-newstyle-opt-list.c b/generator/states-newstyle-opt-list.c
index 6605ee0a..48559574 100644
--- a/generator/states-newstyle-opt-list.c
+++ b/generator/states-newstyle-opt-list.c
@@ -129,6 +129,7 @@ STATE_MACHINE {
}
debug (h, "unexpected response, possibly the server does not "
"support listing exports");
+ err = ENOTSUP;
break;
}
diff --git a/generator/states-newstyle-opt-meta-context.c b/generator/states-newstyle-opt-meta-context.c
index 3945411e..699e24aa 100644
--- a/generator/states-newstyle-opt-meta-context.c
+++ b/generator/states-newstyle-opt-meta-context.c
@@ -272,6 +272,7 @@ STATE_MACHINE {
if (opt == h->opt_current) {
debug (h, "unexpected response, possibly the server does not "
"support meta contexts");
+ err = ENOTSUP;
CALL_CALLBACK (h->opt_cb.completion, &err);
nbd_internal_free_option (h);
SET_NEXT_STATE (%.NEGOTIATING);
--
2.43.0

View File

@ -1,206 +0,0 @@
From 32cb9ab9f1701b1a1a826b48f2083cb75adf1e87 Mon Sep 17 00:00:00 2001
From: Eric Blake <eblake@redhat.com>
Date: Thu, 9 Nov 2023 20:11:08 -0600
Subject: [libnbd PATCH] tests: Check behavior of
nbd_set_strict_mode(STRICT_AUTO_FLAG)
Content-type: text/plain
While developing extended header support for qemu 8.2, I needed a way
to make libnbd quickly behave as a non-compliant client to test corner
cases in qemu's server code; so I wrote commit 5c1dae9236 ("api: Add
LIBNBD_STRICT_AUTO_FLAG to nbd_set_strict", v1.18.0) to meet my needs.
However, I failed to codify my manual tests of that bit into a unit
test for libnbd, until now. Most sane clients will never call
nbd_set_strict_mode() in the first place (after all, it is explicitly
documented as an integration tool, which is how I used it with my qemu
code development), but it never hurts to make sure we don't break it
even for the relatively small set of users that would ever use it.
The test added here runs in two parts; if you get a SKIP despite
having qemu-nbd, then the first part ran successfully before the
second half gave up due to lack of extended headers in qemu
(presumably qemu 8.1 or older); if you get a PASS, then both parts
were run. However, both parts are inherently fragile, depending on
behavior known to be in qemu 8.2 - while it is unlikely to change in
future qemu releases (at least as long as I continue to maintain NBD
code there), the fact that we are intentionally violating the NBD
protocol means a different server is within its rights to behave
differently than qemu 8.2 did. Hence this test lives in interop/
rather than tests/ because of its strong ties to a particular qemu.
Signed-off-by: Eric Blake <eblake@redhat.com>
(cherry picked from commit 54d4426394c372413f55f648d4ad1d21b3395e07)
Signed-off-by: Eric Blake <eblake@redhat.com>
---
interop/Makefile.am | 2 +
interop/strict-mode-auto-flag.sh | 138 +++++++++++++++++++++++++++++++
2 files changed, 140 insertions(+)
create mode 100755 interop/strict-mode-auto-flag.sh
diff --git a/interop/Makefile.am b/interop/Makefile.am
index d6485adf..ac12d84a 100644
--- a/interop/Makefile.am
+++ b/interop/Makefile.am
@@ -28,6 +28,7 @@ EXTRA_DIST = \
structured-read.sh \
opt-extended-headers.sh \
block-status-payload.sh \
+ strict-mode-auto-flag.sh \
$(NULL)
TESTS_ENVIRONMENT = \
@@ -153,6 +154,7 @@ TESTS += \
interop-qemu-block-size.sh \
opt-extended-headers.sh \
block-status-payload.sh \
+ strict-mode-auto-flag.sh \
$(NULL)
interop_qemu_nbd_SOURCES = \
diff --git a/interop/strict-mode-auto-flag.sh b/interop/strict-mode-auto-flag.sh
new file mode 100755
index 00000000..8f73ea73
--- /dev/null
+++ b/interop/strict-mode-auto-flag.sh
@@ -0,0 +1,138 @@
+#!/usr/bin/env bash
+# nbd client library in userspace
+# Copyright Red Hat
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test effect of AUTO_FLAG bit in set_strict_mode()
+
+source ../tests/functions.sh
+set -e
+set -x
+
+requires truncate --version
+requires qemu-nbd --version
+requires nbdsh --version
+
+file="strict-mode-auto-flag.file"
+rm -f $file
+cleanup_fn rm -f $file
+
+truncate -s 1M $file
+
+# Unconditional part of test: behavior when extended headers are not in use
+$VG nbdsh -c '
+import errno
+
+h.set_request_extended_headers(False)
+args = ["qemu-nbd", "-f", "raw", "'"$file"'"]
+h.connect_systemd_socket_activation(args)
+assert h.get_extended_headers_negotiated() is False
+
+# STRICT_AUTO_FLAG and STRICT_COMMANDS are on by default
+flags = h.get_strict_mode()
+assert flags & nbd.STRICT_AUTO_FLAG
+assert flags & nbd.STRICT_COMMANDS
+
+# Under STRICT_AUTO_FLAG, using or omitting flag does not matter; client
+# side auto-corrects the flag before passing to server
+h.pwrite(b"1"*512, 0, 0)
+h.pwrite(b"2"*512, 0, nbd.CMD_FLAG_PAYLOAD_LEN)
+
+# Without STRICT_AUTO_FLAG but still STRICT_COMMANDS, client side now sees
+# attempts to use the flag as invalid
+flags = flags & ~nbd.STRICT_AUTO_FLAG
+h.set_strict_mode(flags)
+h.pwrite(b"3"*512, 0, 0)
+stats = h.stats_bytes_sent()
+try:
+ h.pwrite(b"4"*512, 0, nbd.CMD_FLAG_PAYLOAD_LEN)
+ assert False
+except nbd.Error as e:
+ assert e.errnum == errno.EINVAL
+assert stats == h.stats_bytes_sent()
+
+# Warning: fragile test ahead. Without STRICT_COMMANDS, we send unexpected
+# flag to qemu, and expect failure. For qemu <= 8.1, this is safe (those
+# versions did not know the flag, and correctly reject unknown flags with
+# NBD_EINVAL). For qemu 8.2, this also works (qemu knows the flag, but warns
+# that we were not supposed to send it without extended headers). But if
+# future qemu versions change to start silently ignoring the flag (after all,
+# a write command obviously has a payload even without extended headers, so
+# the flag is redundant for NBD_CMD_WRITE), then we may need to tweak this.
+flags = flags & ~nbd.STRICT_COMMANDS
+h.set_strict_mode(flags)
+h.pwrite(b"5"*512, 0, 0)
+stats = h.stats_bytes_sent()
+try:
+ h.pwrite(b"6"*512, 0, nbd.CMD_FLAG_PAYLOAD_LEN)
+ print("Did newer qemu change behavior?")
+ assert False
+except nbd.Error as e:
+ assert e.errnum == errno.EINVAL
+assert stats < h.stats_bytes_sent()
+
+h.shutdown()
+'
+
+# Conditional part of test: only run if qemu supports extended headers
+requires nbdinfo --has extended-headers -- [ qemu-nbd -r -f raw "$file" ]
+$VG nbdsh -c '
+import errno
+
+args = ["qemu-nbd", "-f", "raw", "'"$file"'"]
+h.connect_systemd_socket_activation(args)
+assert h.get_extended_headers_negotiated() is True
+
+# STRICT_AUTO_FLAG and STRICT_COMMANDS are on by default
+flags = h.get_strict_mode()
+assert flags & nbd.STRICT_AUTO_FLAG
+assert flags & nbd.STRICT_COMMANDS
+
+# Under STRICT_AUTO_FLAG, using or omitting flag does not matter; client
+# side auto-corrects the flag before passing to server
+h.pwrite(b"1"*512, 0, 0)
+h.pwrite(b"2"*512, 0, nbd.CMD_FLAG_PAYLOAD_LEN)
+
+# Without STRICT_AUTO_FLAG but still STRICT_COMMANDS, client side now sees
+# attempts to omit the flag as invalid
+flags = flags & ~nbd.STRICT_AUTO_FLAG
+h.set_strict_mode(flags)
+h.pwrite(b"3"*512, 0, nbd.CMD_FLAG_PAYLOAD_LEN)
+stats = h.stats_bytes_sent()
+try:
+ h.pwrite(b"4"*512, 0, 0)
+ assert False
+except nbd.Error as e:
+ assert e.errnum == errno.EINVAL
+assert stats == h.stats_bytes_sent()
+
+# Warning: fragile test ahead. Without STRICT_COMMANDS, omitting the flag
+# is a protocol violation. qemu 8.2 silently ignores the violation; but a
+# future qemu might start failing the command, at which point we would need
+# to tweak this part of the test.
+flags = flags & ~nbd.STRICT_COMMANDS
+h.set_strict_mode(flags)
+h.pwrite(b"5"*512, 0, nbd.CMD_FLAG_PAYLOAD_LEN)
+stats = h.stats_bytes_sent()
+try:
+ h.pwrite(b"6"*512, 0, 0)
+except nbd.Error:
+ print("Did newer qemu change behavior?")
+ assert False
+assert stats < h.stats_bytes_sent()
+
+h.shutdown()
+'
--
2.41.0

View File

@ -0,0 +1,175 @@
From 923357f49704d55cd74dc5334a12a7089825ff57 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Thu, 25 Jul 2024 13:25:34 +0100
Subject: [PATCH] generator/states-newstyle.c: Quote untrusted string from the
server
Updates: commit cf49a49adc8abc8c917437db7461ed9956583877
(cherry picked from commit 5dbfc418cb6176102634acea2256b2335520159c)
---
generator/states-newstyle.c | 124 ++++++++++++++++++++----------------
1 file changed, 68 insertions(+), 56 deletions(-)
diff --git a/generator/states-newstyle.c b/generator/states-newstyle.c
index 6c7cc45c..8c483bd2 100644
--- a/generator/states-newstyle.c
+++ b/generator/states-newstyle.c
@@ -18,6 +18,7 @@
#include <assert.h>
+#include "ascii-ctype.h"
#include "internal.h"
/* Common code for parsing a reply to NBD_OPT_*. */
@@ -88,80 +89,91 @@ prepare_for_reply_payload (struct nbd_handle *h, uint32_t opt)
static int
handle_reply_error (struct nbd_handle *h)
{
- uint32_t len;
uint32_t reply;
- char *msg = NULL;
+ uint32_t replylen;
+ FILE *fp;
+ char *s = NULL;
+ size_t len = 0;
+ int err = 0;
- len = be32toh (h->sbuf.or.option_reply.replylen);
reply = be32toh (h->sbuf.or.option_reply.reply);
if (!NBD_REP_IS_ERR (reply)) {
set_error (0, "handshake: unexpected option reply type %d", reply);
return -1;
}
+ replylen = be32toh (h->sbuf.or.option_reply.replylen);
assert (NBD_MAX_STRING < sizeof h->sbuf.or.payload);
- if (len > NBD_MAX_STRING) {
+ if (replylen > NBD_MAX_STRING) {
set_error (0, "handshake: option error string too long");
return -1;
}
- /* Decode expected errors into a nicer string.
- *
- * XXX Note this string comes directly from the server, and most
- * libnbd users simply print the error using 'fprintf'. We really
- * ought to quote this string somehow, but we don't have a useful
- * function for that.
- */
- if (len > 0) {
- if (asprintf (&msg, ": %.*s",
- (int)len, h->sbuf.or.payload.err_msg) == -1) {
- set_error (errno, "asprintf");
- return -1;
- }
+ /* Decode expected errors into a nicer string. */
+ fp = open_memstream (&s, &len);
+ if (fp == NULL) {
+ set_error (errno, "open_memstream");
+ return -1;
}
switch (reply) {
case NBD_REP_ERR_UNSUP:
- set_error (ENOTSUP, "the operation is not supported by the server%s",
- msg ? : "");
- break;
- case NBD_REP_ERR_POLICY:
- set_error (0, "server policy prevents the operation%s",
- msg ? : "");
- break;
- case NBD_REP_ERR_PLATFORM:
- set_error (0, "the operation is not supported by the server platform%s",
- msg ? : "");
- break;
- case NBD_REP_ERR_INVALID:
- set_error (EINVAL, "the server rejected this operation as invalid%s",
- msg ? : "");
- break;
- case NBD_REP_ERR_TOO_BIG:
- set_error (EINVAL, "the operation is too large to process%s",
- msg ? : "");
- break;
- case NBD_REP_ERR_TLS_REQD:
- set_error (ENOTSUP, "the server requires TLS encryption first%s",
- msg ? : "");
- break;
- case NBD_REP_ERR_UNKNOWN:
- set_error (ENOENT, "the server has no export named '%s'%s",
- h->export_name, msg ? : "");
- break;
- case NBD_REP_ERR_SHUTDOWN:
- set_error (ESHUTDOWN, "the server is shutting down%s",
- msg ? : "");
- break;
- case NBD_REP_ERR_BLOCK_SIZE_REQD:
- set_error (EINVAL, "the server requires specific block sizes%s",
- msg ? : "");
- break;
- default:
- set_error (0, "handshake: unknown reply from the server: 0x%" PRIx32 "%s",
- reply, msg ? : "");
+ err = ENOTSUP;
+ fprintf (fp, "the operation is not supported by the server");
+ break;
+ case NBD_REP_ERR_POLICY:
+ fprintf (fp, "server policy prevents the operation");
+ break;
+ case NBD_REP_ERR_PLATFORM:
+ fprintf (fp, "the operation is not supported by the server platform");
+ break;
+ case NBD_REP_ERR_INVALID:
+ err = EINVAL;
+ fprintf (fp, "the server rejected this operation as invalid");
+ break;
+ case NBD_REP_ERR_TOO_BIG:
+ err = EINVAL;
+ fprintf (fp, "the operation is too large to process");
+ break;
+ case NBD_REP_ERR_TLS_REQD:
+ err = ENOTSUP;
+ fprintf (fp, "the server requires TLS encryption first");
+ break;
+ case NBD_REP_ERR_UNKNOWN:
+ err = ENOENT;
+ fprintf (fp, "the server has no export named '%s'", h->export_name);
+ break;
+ case NBD_REP_ERR_SHUTDOWN:
+ err = ESHUTDOWN;
+ fprintf (fp, "the server is shutting down");
+ break;
+ case NBD_REP_ERR_BLOCK_SIZE_REQD:
+ err = EINVAL;
+ fprintf (fp, "the server requires specific block sizes");
+ break;
+ default:
+ fprintf (fp, "handshake: unknown reply from the server: 0x%" PRIx32,
+ reply);
+ }
+
+ if (replylen > 0) {
+ /* Since this message comes from the server, take steps to quote it. */
+ uint32_t i;
+ const char *msg = h->sbuf.or.payload.err_msg;
+
+ fprintf (fp, ": ");
+ for (i = 0; i < replylen; ++i) {
+ if (ascii_isprint (msg[i]))
+ fputc (msg[i], fp);
+ else
+ fprintf (fp, "\\x%02x", msg[i]);
}
- free (msg);
+ }
+
+ fclose (fp);
+
+ set_error (err, "%s", s);
+ free (s);
return 0;
}
--
2.43.0

View File

@ -0,0 +1,27 @@
From a8e554e53ce8150286e06f4afd578ab52e2f03d9 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Thu, 25 Jul 2024 15:48:46 +0100
Subject: [PATCH] generator/states-newstyle.c: Don't sign extend escaped chars
Fixes: commit 5dbfc418cb6176102634acea2256b2335520159c
(cherry picked from commit 0d6c6bbb3386de3b60ab6c4831045f2b1896051b)
---
generator/states-newstyle.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/generator/states-newstyle.c b/generator/states-newstyle.c
index 8c483bd2..1e026a8a 100644
--- a/generator/states-newstyle.c
+++ b/generator/states-newstyle.c
@@ -159,7 +159,7 @@ handle_reply_error (struct nbd_handle *h)
if (replylen > 0) {
/* Since this message comes from the server, take steps to quote it. */
uint32_t i;
- const char *msg = h->sbuf.or.payload.err_msg;
+ const unsigned char *msg = (unsigned char *) h->sbuf.or.payload.err_msg;
fprintf (fp, ": ");
for (i = 0; i < replylen; ++i) {
--
2.43.0

View File

@ -6,7 +6,7 @@ set -e
# directory. Use it like this: # directory. Use it like this:
# ./copy-patches.sh # ./copy-patches.sh
rhel_version=9.4 rhel_version=9.5
# Check we're in the right directory. # Check we're in the right directory.
if [ ! -f libnbd.spec ]; then if [ ! -f libnbd.spec ]; then

View File

@ -1,17 +0,0 @@
-----BEGIN PGP SIGNATURE-----
iQJFBAABCAAvFiEE93dPsa0HSn6Mh2fqkXOPc+G3aKAFAmU2izoRHHJpY2hAYW5u
ZXhpYS5vcmcACgkQkXOPc+G3aKA+txAAkLeWdvH2ryibEyqMeyejvh9vMgQO5I46
LaygI8jDi+XG+rGy7imiwIxxWvyCZI3y2U5MFudLZoFi+gCyVAC+LeBxjF41NBGz
fbgwFaQHrCbxyLlsj9OcR6M0+EPU8NXXPPGgXZNcnf7tHNZkTO0OGS9chml0wXHA
Zx9WheHl6wbLTVIAtLWOJqzRQj80RlcPC+De1wZL+WFMPMkfF8L8K5FRNsfeTIXn
l31d1R0g5QOMTTqBiKE2iopPmVmA5uC/adWCuqF3mzzjzCkHp+Ux/Ys99tkCETrU
jUuHgJ+1pYjn4Lmt/HUwXQZD3L+RkNAWWQziY/3ejK31tGxZqR/XTwq5RPrc6Qs1
/zuoWvSWJZZo9yvX1Iq2RQAaZF5724V/svm+HgaCakaK8EJEj6sntM0OhAl2pRC4
G45Kb2o7k016WgL8plNOlrbHNxaruBcPrkFYDMoyy3KLnWaw3OYMARTD5w/Pd4dC
CJa3tIXIKedhXw9xDtEWfxiKIHfO+LBHBMjpW9KzP/oxE2akmcJZJT+JNpsrpdzV
O6mbVDPedWd5LQQ1bNmwzxkCsMEC9HFhVbCaTuYuSXe/By04Norns4xyEJyDXlG/
QqFgEUS8R+V9xwYHoAPg5RUmycXubSmm64iTAQNqc46QsxeP0Va7gpbrPLe5qVk/
irUsxdBhGIM=
=pgmp
-----END PGP SIGNATURE-----

View File

@ -0,0 +1,17 @@
-----BEGIN PGP SIGNATURE-----
iQJFBAABCAAvFiEE93dPsa0HSn6Mh2fqkXOPc+G3aKAFAmZ7KY8RHHJpY2hAYW5u
ZXhpYS5vcmcACgkQkXOPc+G3aKAP7A/9EzaUWFPP1GDCrpfvVods7F+8DN87O/aZ
mTzw59HNZVz42Yw0cM8MAEckgnpMdT7d64m6E1lx8fxIYGaO+c4r+VeZfYlsZIam
HFzTe4UYwdjZT1HcR9njSkdL/6th5ZMM6NK+RI3MBmQAc5TfFxPUsXbHSAfLgclb
v3yh2F0x6gnSBMxdVVYGha/eGegLZONGhZIxVYlVr0VlFrpy3Lo6+4mxIw5Sbery
cY+LxKwpyx1Gj01qZS+muub7kCXefwZggf15F1NqaQNz6tzriwXpW1yrZGayERmT
s11htXEvqSI3ViO3Rf/paq5vKwo5v7AMLHI7cv2dzrmNglLrEsY4GywlHdgbDYLh
7qY6/35WzQwCcCWlvXP3K4SIkauH5lVR0KMsdU+idxpodqtHSTQN8f0z1vSSf5We
wilBzw1LPiD55Dz7/9AIbjU/w/iUREsZceplbis1DFsVxf+cVZTtwx0LJn2enKTc
O61LVcV9FDB7EJIdTQfFr9WJTR+6gfSF5R7H4kMX8gZHucoUruoXA+M4fqV8aRHc
5lrzgnsVN/GatF5R63yt6dSByQGqnyhpLynoYWCht64PRglb7XekGuT9AR3m85VP
hTu1fZsLfmVl9iJjc47/c5CKq9mAhoicDiCVCgTidCq5O9SmI2HgmCPUH/nd2+Fc
uB2geCRdnZ0=
=dUDc
-----END PGP SIGNATURE-----

View File

@ -1,15 +1,27 @@
# i686 no longer has any kind of OCaml compiler, not even ocamlc.
%ifnarch %{ix86}
%global have_ocaml 1
%endif
# No ublk in RHEL 9.
%if !0%{?rhel}
%global have_ublk 1
%endif
# No nbd.ko in RHEL 9.
%if !0%{?rhel}
%global have_nbd_ko 1
%endif
# If we should verify tarball signature with GPGv2. # If we should verify tarball signature with GPGv2.
%global verify_tarball_signature 1 %global verify_tarball_signature 1
# If there are patches which touch autotools files, set this to 1.
%global patches_touch_autotools 1
# The source directory. # The source directory.
%global source_directory 1.18-stable %global source_directory 1.20-stable
Name: libnbd Name: libnbd
Version: 1.18.1 Version: 1.20.2
Release: 3%{?dist} Release: 2%{?dist}
Summary: NBD client library in userspace Summary: NBD client library in userspace
License: LGPL-2.0-or-later AND BSD-3-Clause License: LGPL-2.0-or-later AND BSD-3-Clause
@ -26,21 +38,21 @@ Source2: libguestfs.keyring
Source3: copy-patches.sh Source3: copy-patches.sh
# Patches are stored in the upstream repository: # Patches are stored in the upstream repository:
# https://gitlab.com/nbdkit/libnbd/-/commits/rhel-9.4/ # https://gitlab.com/nbdkit/libnbd/-/commits/rhel-9.5/
# Patches. Patch0001: 0001-generator-Print-full-error-in-handle_reply_error.patch
Patch0001: 0001-generator-Fix-assertion-in-ext-mode-BLOCK_STATUS-CVE.patch Patch0002: 0002-lib-Don-t-overwrite-error-in-nbd_opt_-go-info.patch
Patch0002: 0002-docs-Fix-incorrect-xref-in-libnbd-release-notes-for-.patch Patch0003: 0003-generator-Restore-assignment-to-local-err.patch
Patch0003: 0003-tests-Check-behavior-of-nbd_set_strict_mode-STRICT_A.patch Patch0004: 0004-generator-states-newstyle.c-Quote-untrusted-string-f.patch
Patch0005: 0005-generator-states-newstyle.c-Don-t-sign-extend-escape.patch
%if 0%{patches_touch_autotools}
BuildRequires: autoconf, automake, libtool
%endif
%if 0%{verify_tarball_signature} %if 0%{verify_tarball_signature}
BuildRequires: gnupg2 BuildRequires: gnupg2
%endif %endif
# For rebuilding autoconf cruft.
BuildRequires: autoconf, automake, libtool
# For the core library. # For the core library.
BuildRequires: gcc BuildRequires: gcc
BuildRequires: make BuildRequires: make
@ -51,7 +63,7 @@ BuildRequires: libxml2-devel
# For nbdfuse. # For nbdfuse.
BuildRequires: fuse3, fuse3-devel BuildRequires: fuse3, fuse3-devel
%if !0%{?rhel} %if 0%{?have_ublk}
# For nbdublk # For nbdublk
BuildRequires: liburing-devel >= 2.2 BuildRequires: liburing-devel >= 2.2
BuildRequires: ubdsrv-devel >= 1.0-3.rc6 BuildRequires: ubdsrv-devel >= 1.0-3.rc6
@ -60,7 +72,7 @@ BuildRequires: ubdsrv-devel >= 1.0-3.rc6
# For the Python 3 bindings. # For the Python 3 bindings.
BuildRequires: python3-devel BuildRequires: python3-devel
%ifnarch %{ix86} %if 0%{?have_ocaml}
# For the OCaml bindings. # For the OCaml bindings.
BuildRequires: ocaml BuildRequires: ocaml
BuildRequires: ocaml-findlib-devel BuildRequires: ocaml-findlib-devel
@ -79,7 +91,7 @@ BuildRequires: gcc-c++
BuildRequires: gnutls-utils BuildRequires: gnutls-utils
BuildRequires: iproute BuildRequires: iproute
BuildRequires: jq BuildRequires: jq
%if !0%{?rhel} %if 0%{?have_nbd_ko}
BuildRequires: nbd BuildRequires: nbd
%endif %endif
BuildRequires: util-linux BuildRequires: util-linux
@ -100,7 +112,7 @@ BuildRequires: nbdkit-sh-plugin
BuildRequires: nbdkit-sparse-random-plugin BuildRequires: nbdkit-sparse-random-plugin
%endif %endif
%ifnarch %{ix86} %if 0%{?have_ocaml}
# The OCaml runtime system does not provide this symbol # The OCaml runtime system does not provide this symbol
%global __ocaml_requires_opts -x Stdlib__Callback %global __ocaml_requires_opts -x Stdlib__Callback
%endif %endif
@ -136,7 +148,7 @@ Requires: %{name}%{?_isa} = %{version}-%{release}
This package contains development headers for %{name}. This package contains development headers for %{name}.
%ifnarch %{ix86} %if 0%{?have_ocaml}
%package -n ocaml-%{name} %package -n ocaml-%{name}
Summary: OCaml language bindings for %{name} Summary: OCaml language bindings for %{name}
Requires: %{name}%{?_isa} = %{version}-%{release} Requires: %{name}%{?_isa} = %{version}-%{release}
@ -182,7 +194,7 @@ Recommends: fuse3
This package contains FUSE support for %{name}. This package contains FUSE support for %{name}.
%if !0%{?rhel} %if 0%{?have_ublk}
%package -n nbdublk %package -n nbdublk
Summary: Userspace NBD block device Summary: Userspace NBD block device
Requires: %{name}%{?_isa} = %{version}-%{release} Requires: %{name}%{?_isa} = %{version}-%{release}
@ -215,25 +227,30 @@ for %{name}.
%{gpgverify} --keyring='%{SOURCE2}' --signature='%{SOURCE1}' --data='%{SOURCE0}' %{gpgverify} --keyring='%{SOURCE2}' --signature='%{SOURCE1}' --data='%{SOURCE0}'
%endif %endif
%autosetup -p1 %autosetup -p1
%if 0%{patches_touch_autotools}
autoreconf -i autoreconf -i
%endif
%build %build
%configure \ %configure \
--disable-static \ --disable-static \
--with-tls-priority=@LIBNBD,SYSTEM \ --with-tls-priority=@LIBNBD,SYSTEM \
--with-bash-completions \
PYTHON=%{__python3} \ PYTHON=%{__python3} \
--enable-python \ --enable-python \
%ifnarch %{ix86} %if 0%{?have_ocaml}
--enable-ocaml \ --enable-ocaml \
%else %else
--disable-ocaml \ --disable-ocaml \
%endif %endif
--enable-fuse \ --enable-fuse \
--disable-golang \ --disable-golang \
--disable-rust --disable-rust \
%if 0%{?have_ublk}
--enable-ublk \
%else
--disable-ublk \
%endif
%{nil}
make %{?_smp_mflags} make %{?_smp_mflags}
@ -247,16 +264,11 @@ find $RPM_BUILD_ROOT -name '*.la' -delete
# Delete the golang man page since we're not distributing the bindings. # Delete the golang man page since we're not distributing the bindings.
rm $RPM_BUILD_ROOT%{_mandir}/man3/libnbd-golang.3* rm $RPM_BUILD_ROOT%{_mandir}/man3/libnbd-golang.3*
%ifarch %{ix86} %if !0%{?have_ocaml}
# Delete the OCaml man page on i686. # Delete the OCaml man page on i686.
rm $RPM_BUILD_ROOT%{_mandir}/man3/libnbd-ocaml.3* rm $RPM_BUILD_ROOT%{_mandir}/man3/libnbd-ocaml.3*
%endif %endif
%if 0%{?rhel}
# Delete nbdublk on RHEL.
rm $RPM_BUILD_ROOT%{_datadir}/bash-completion/completions/nbdublk
%endif
%check %check
function skip_test () function skip_test ()
@ -268,12 +280,6 @@ function skip_test ()
done done
} }
# interop/structured-read.sh fails with the old qemu-nbd in Fedora 29,
# so disable it there.
%if 0%{?fedora} <= 29
skip_test interop/structured-read.sh
%endif
# interop/interop-qemu-storage-daemon.sh fails in RHEL 9 because of # interop/interop-qemu-storage-daemon.sh fails in RHEL 9 because of
# this bug in qemu: # this bug in qemu:
# https://lists.nongnu.org/archive/html/qemu-devel/2021-03/threads.html#03544 # https://lists.nongnu.org/archive/html/qemu-devel/2021-03/threads.html#03544
@ -324,7 +330,7 @@ make %{?_smp_mflags} check || {
%{_mandir}/man3/nbd_*.3* %{_mandir}/man3/nbd_*.3*
%ifnarch %{ix86} %if 0%{?have_ocaml}
%files -n ocaml-%{name} %files -n ocaml-%{name}
%dir %{_libdir}/ocaml/nbd %dir %{_libdir}/ocaml/nbd
%{_libdir}/ocaml/nbd/META %{_libdir}/ocaml/nbd/META
@ -363,7 +369,7 @@ make %{?_smp_mflags} check || {
%{_mandir}/man1/nbdfuse.1* %{_mandir}/man1/nbdfuse.1*
%if !0%{?rhel} %if 0%{?have_ublk}
%files -n nbdublk %files -n nbdublk
%{_bindir}/nbdublk %{_bindir}/nbdublk
%{_mandir}/man1/nbdublk.1* %{_mandir}/man1/nbdublk.1*
@ -383,6 +389,18 @@ make %{?_smp_mflags} check || {
%changelog %changelog
* Fri Jul 26 2024 Richard W.M. Jones <rjones@redhat.com> - 1.20.2-2
- Rebase to libnbd 1.20.2
resolves: RHEL-31883
- Fix multiple flaws in TLS server certificate checking
resolves: RHEL-49801
- Print full NBD error from server
resolves: RHEL-50665
* Tue Apr 09 2024 Miroslav Rezanina <mrezanin@redhat.com> - 1.20.0-1
- Rebase to 1.20.0
resolves: RHEL-31883
* Mon Nov 13 2023 Eric Blake <eblake@redhat.com> - 1.18.1-3 * Mon Nov 13 2023 Eric Blake <eblake@redhat.com> - 1.18.1-3
- Backport unit test of recent libnbd API addition - Backport unit test of recent libnbd API addition
resolves: RHEL-16292 resolves: RHEL-16292