When image is part of the file it makes sense to limit the length of the
image in the file. Otherwise it is assumed that the image spans to the
end of the file. This assumption may lead to reads/writes outside of the
image and thus lead to errors or data corruption.

To limit the assumed image size new option is introduced.

Signed-off-by: Tomáš Golembiovský <tgole...@redhat.com>
---
 qemu-nbd.c    | 44 +++++++++++++++++++++++++++++++++++---------
 qemu-nbd.texi |  4 ++++
 2 files changed, 39 insertions(+), 9 deletions(-)

diff --git a/qemu-nbd.c b/qemu-nbd.c
index 629bce1..7ed52f7 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -85,6 +85,7 @@ static void usage(const char *name)
 "\n"
 "Exposing part of the image:\n"
 "  -o, --offset=OFFSET       offset into the image\n"
+"  -S, --device-size=LEN     limit reported device size\n"
 "  -P, --partition=NUM       only expose partition NUM\n"
 "\n"
 "General purpose options:\n"
@@ -471,10 +472,12 @@ int main(int argc, char **argv)
     const char *port = NULL;
     char *sockpath = NULL;
     char *device = NULL;
-    off_t fd_size;
+    off_t real_size = 0;
+    off_t fd_size = 0;
+    bool has_image_size = false;
     QemuOpts *sn_opts = NULL;
     const char *sn_id_or_name = NULL;
-    const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:tl:x:T:";
+    const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:tl:x:T:S:";
     struct option lopt[] = {
         { "help", no_argument, NULL, 'h' },
         { "version", no_argument, NULL, 'V' },
@@ -482,6 +485,7 @@ int main(int argc, char **argv)
         { "port", required_argument, NULL, 'p' },
         { "socket", required_argument, NULL, 'k' },
         { "offset", required_argument, NULL, 'o' },
+        { "image-size", required_argument, NULL, 'S' },
         { "read-only", no_argument, NULL, 'r' },
         { "partition", required_argument, NULL, 'P' },
         { "connect", required_argument, NULL, 'c' },
@@ -714,6 +718,18 @@ int main(int argc, char **argv)
             g_free(trace_file);
             trace_file = trace_opt_parse(optarg);
             break;
+        case 'S':
+            ret = qemu_strtoll(optarg, NULL, 0, &fd_size);
+            if (ret != 0) {
+                error_report("Invalid image size `%s'", optarg);
+                exit(EXIT_FAILURE);
+            }
+            if (fd_size <= 0) {
+                error_report("Image size must be positive `%s'", optarg);
+                exit(EXIT_FAILURE);
+            }
+            has_image_size = true;
+            break;
         }
     }
 
@@ -894,19 +910,29 @@ int main(int argc, char **argv)
     }
 
     bs->detect_zeroes = detect_zeroes;
-    fd_size = blk_getlength(blk);
-    if (fd_size < 0) {
+    real_size = blk_getlength(blk);
+    if (real_size < 0) {
         error_report("Failed to determine the image length: %s",
-                     strerror(-fd_size));
+                     strerror(-real_size));
         exit(EXIT_FAILURE);
     }
 
-    if (dev_offset >= fd_size) {
-        error_report("Offset (%lu) has to be smaller than the image size 
(%lu)",
-                     dev_offset, fd_size);
+    if (!has_image_size) {
+        fd_size = real_size;
+
+        if (dev_offset >= fd_size) {
+            error_report("Offset (%lu) has to be smaller than image size 
(%lu)",
+                        dev_offset, fd_size);
+            exit(EXIT_FAILURE);
+        }
+
+        fd_size -= dev_offset;
+    } else if ((dev_offset + fd_size) > real_size) {
+        error_report("Offset (%lu) plus image size (%lu) has to be smaller "
+                     "than or equal to real image size (%lu)",
+                     dev_offset, fd_size, real_size);
         exit(EXIT_FAILURE);
     }
-    fd_size -= dev_offset;
 
     if (partition != -1) {
         ret = find_partition(blk, partition, &dev_offset, &fd_size);
diff --git a/qemu-nbd.texi b/qemu-nbd.texi
index 91ebf04..c589525 100644
--- a/qemu-nbd.texi
+++ b/qemu-nbd.texi
@@ -30,6 +30,10 @@ credentials for the qemu-nbd server.
 The TCP port to listen on (default @samp{10809})
 @item -o, --offset=@var{offset}
 The offset into the image
+@item -S, --image-size=@var{length}
+The size of the image to present to client. This is useful in combination with
+@var{-o} when the image is embedded in file but does not span to the end of the
+file.
 @item -b, --bind=@var{iface}
 The interface to bind to (default @samp{0.0.0.0})
 @item -k, --socket=@var{path}
-- 
2.9.3


Reply via email to