This can be used to ensure that the tar filter does not read
indefinite amounts of input when opening the tar file.
See:
https://github.com/kubevirt/containerized-data-importer/pull/2748#issueco...
---
filters/tar/nbdkit-tar-filter.pod | 19 +++++++++
tests/Makefile.am | 2 +
filters/tar/tar.c | 10 +++++
tests/test-tar-limit.sh | 65 +++++++++++++++++++++++++++++++
4 files changed, 96 insertions(+)
diff --git a/filters/tar/nbdkit-tar-filter.pod b/filters/tar/nbdkit-tar-filter.pod
index 96aba16d9..f032d7cc3 100644
--- a/filters/tar/nbdkit-tar-filter.pod
+++ b/filters/tar/nbdkit-tar-filter.pod
@@ -5,6 +5,7 @@ nbdkit-tar-filter - read and write files inside tar files without
unpacking
=head1 SYNOPSIS
nbdkit file FILENAME.tar --filter=tar tar-entry=PATH_INSIDE_TAR
+ [tar-limit=SIZE]
=head1 EXAMPLES
@@ -82,6 +83,24 @@ The path of the file inside the tarball to serve. This parameter is
required. It must exactly match the name stored in the tarball, so
use S<C<tar tf filename.tar>>
+=item [B<tar-limit=>]SIZE
+
+When opening the tar file we have to locate the file (C<tar-entry>)
+inside the tarball. Because tar files do not have a central index we
+must iterate over the tar file to find the entry, and that may be
+costly (especially with untrusted tar files). In the worst case where
+C<tar-entry> starts near the end of the file we may have to iterate
+over the whole tar file. If this is a problem you may set
+C<tar-limit> to some smaller value, eg:
+
+ nbdkit -r curl
https://example.com/file.tar \
+ --filter=tar tar-entry=disk.img tar-limit=10M
+
+which ensures no more than 10 megabytes are read before we give up and
+reject the tar file (sending an error back to the NBD client).
+
+The default is 0 meaning no limit.
+
=item B<tar=gtar>
=item B<tar=>/PATH/TO/GTAR
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 6694e409e..f2912aa93 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1957,11 +1957,13 @@ TESTS += \
test-tar.sh \
test-tar-info.sh \
test-tar-info-xz.sh \
+ test-tar-limit.sh \
$(NULL)
EXTRA_DIST += \
test-tar.sh \
test-tar-info.sh \
test-tar-info-xz.sh \
+ test-tar-limit.sh \
$(NULL)
# truncate filter tests.
diff --git a/filters/tar/tar.c b/filters/tar/tar.c
index f3adb2c46..efe47684d 100644
--- a/filters/tar/tar.c
+++ b/filters/tar/tar.c
@@ -53,6 +53,7 @@
#include "utils.h"
static const char *entry; /* File within tar (tar-entry=...) */
+static int64_t tar_limit = 0;
static const char *tar_program = "tar";
/* Offset and size within tarball.
@@ -76,6 +77,12 @@ tar_config (nbdkit_next_config *next, nbdkit_backend *nxdata,
entry = value;
return 0;
}
+ else if (strcmp (key, "tar-limit") == 0) {
+ tar_limit = nbdkit_parse_size (value);
+ if (tar_limit == -1)
+ return -1;
+ return 0;
+ }
else if (strcmp (key, "tar") == 0) {
tar_program = value;
return 0;
@@ -98,6 +105,7 @@ tar_config_complete (nbdkit_next_config_complete *next,
#define tar_config_help \
"tar-entry=<FILENAME> (required) The path inside the tar file to
serve.\n" \
+ "tar-limit=SIZE Limit on reading to find entry.\n" \
"tar=<PATH> Path of the tar binary."
static int
@@ -197,6 +205,8 @@ calculate_offset_of_entry (nbdkit_next *next)
copysize = next->get_size (next);
if (copysize == -1)
return -1;
+ if (tar_limit > 0 && copysize > tar_limit)
+ copysize = tar_limit;
/* Run the tar command. */
nbdkit_debug ("%s", cmd);
diff --git a/tests/test-tar-limit.sh b/tests/test-tar-limit.sh
new file mode 100755
index 000000000..2eba69324
--- /dev/null
+++ b/tests/test-tar-limit.sh
@@ -0,0 +1,65 @@
+#!/usr/bin/env bash
+# nbdkit
+# Copyright Red Hat
+#
+# 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.
+
+# Test the tar filter and tar-limit filter.
+
+source ./functions.sh
+set -e
+set -x
+
+requires test -f disk
+requires tar --version
+requires test -f disk
+requires_nbdinfo
+
+tar_bad=tar-limit-bad.tar
+tar_good=tar-limit-good.tar
+tar_filler=tar-filler.img
+files="$tar_bad $tar_good $tar_filler"
+rm -f $files
+cleanup_fn rm -f $files
+
+# Create two tar files, one where the disk is located before an
+# arbitrary boundary and one after.
+truncate -s 1M $tar_filler
+tar cf $tar_good disk
+tar cf $tar_bad $tar_filler disk
+
+# Check we can read the good disk and reject the bad disk.
+cmd="nbdkit -U - file --filter=tar tar-entry=disk tar-limit=131072"
+
+$cmd $tar_good --run 'nbdinfo "$uri"'
+
+if $cmd $tar_bad --run 'nbdinfo "$uri"' ; then
+ echo "ERROR: $0: expected $tar_bad to fail"
+ exit 1
+fi
--
2.40.1