$ nbdkit sparse-random 4G --filter=cow --run 'nbdinfo --map $uri'
nbdkit: cow.c:591: cow_extents: Assertion `count > 0' failed.
This is caused because nbdinfo calls us with count = 0xfffffe00 which
is rounded up to the next boundary and overflows (so count = 0).
Use a 64 bit variable for count to allow rounding up.
---
tests/Makefile.am | 2 ++
filters/cow/cow.c | 16 +++++++++---
tests/test-cow-extents-large.sh | 46 +++++++++++++++++++++++++++++++++
3 files changed, 61 insertions(+), 3 deletions(-)
diff --git a/tests/Makefile.am b/tests/Makefile.am
index ba42f112..8e0304d4 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1404,6 +1404,7 @@ TESTS += \
test-cow.sh \
test-cow-extents1.sh \
test-cow-extents2.sh \
+ test-cow-extents-large.sh \
test-cow-unaligned.sh \
$(NULL)
endif
@@ -1412,6 +1413,7 @@ EXTRA_DIST += \
test-cow.sh \
test-cow-extents1.sh \
test-cow-extents2.sh \
+ test-cow-extents-large.sh \
test-cow-null.sh \
test-cow-unaligned.sh \
$(NULL)
diff --git a/filters/cow/cow.c b/filters/cow/cow.c
index 83844845..3bd09399 100644
--- a/filters/cow/cow.c
+++ b/filters/cow/cow.c
@@ -571,19 +571,23 @@ cow_cache (nbdkit_next *next,
/* Extents. */
static int
cow_extents (nbdkit_next *next,
- void *handle, uint32_t count, uint64_t offset, uint32_t flags,
+ void *handle, uint32_t count32, uint64_t offset, uint32_t flags,
struct nbdkit_extents *extents, int *err)
{
const bool can_extents = next->can_extents (next);
const bool req_one = flags & NBDKIT_FLAG_REQ_ONE;
+ uint64_t count = count32;
uint64_t end;
uint64_t blknum;
- /* To make this easier, align the requested extents to whole blocks. */
+ /* To make this easier, align the requested extents to whole blocks.
+ * Note that count is a 64 bit variable containing at most a 32 bit
+ * value so rounding up is safe here.
+ */
end = offset + count;
offset = ROUND_DOWN (offset, BLKSIZE);
end = ROUND_UP (end, BLKSIZE);
- count = end - offset;
+ count = end - offset;
blknum = offset / BLKSIZE;
assert (IS_ALIGNED (offset, BLKSIZE));
@@ -628,6 +632,12 @@ cow_extents (nbdkit_next *next,
* as we can.
*/
for (;;) {
+ /* nbdkit_extents_full cannot read more than a 32 bit range
+ * (range_count), but count is a 64 bit quantity, so don't
+ * overflow range_count here.
+ */
+ if (range_count >= UINT32_MAX - BLKSIZE + 1) break;
+
blknum++;
offset += BLKSIZE;
count -= BLKSIZE;
diff --git a/tests/test-cow-extents-large.sh b/tests/test-cow-extents-large.sh
new file mode 100755
index 00000000..ea981dcb
--- /dev/null
+++ b/tests/test-cow-extents-large.sh
@@ -0,0 +1,46 @@
+#!/usr/bin/env bash
+# nbdkit
+# Copyright (C) 2018-2021 Red Hat Inc.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Red Hat nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+
+# Regression test of an earlier overflow in cow_extents.
+#
https://listman.redhat.com/archives/libguestfs/2021-July/msg00037.html
+
+source ./functions.sh
+set -e
+set -x
+
+requires_filter cow
+requires_plugin sparse-random
+requires nbdinfo --version
+
+for size in 0 3G 4G 5G 8G; do
+ nbdkit -U - sparse-random $size --filter=cow --run 'nbdinfo --map $uri'
+done
--
2.32.0