Blame SOURCES/kvm-qemu-nbd-Sanity-check-partition-bounds.patch

383d26
From 58096dddd1682a83fb782a49d80199da9a117ef9 Mon Sep 17 00:00:00 2001
383d26
From: John Snow <jsnow@redhat.com>
383d26
Date: Wed, 27 Mar 2019 17:22:38 +0100
383d26
Subject: [PATCH 100/163] qemu-nbd: Sanity check partition bounds
383d26
383d26
RH-Author: John Snow <jsnow@redhat.com>
383d26
Message-id: <20190327172308.31077-26-jsnow@redhat.com>
383d26
Patchwork-id: 85207
383d26
O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 25/55] qemu-nbd: Sanity check partition bounds
383d26
Bugzilla: 1691009
383d26
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
383d26
RH-Acked-by: Max Reitz <mreitz@redhat.com>
383d26
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
383d26
383d26
From: Eric Blake <eblake@redhat.com>
383d26
383d26
When the user requests a partition, we were using data read
383d26
from the disk as disk offsets without a bounds check. We got
383d26
lucky that even when computed offsets are out-of-bounds,
383d26
blk_pread() will gracefully catch the error later (so I don't
383d26
think a malicious image can crash or exploit qemu-nbd, and am
383d26
not treating this as a security flaw), but it's better to
383d26
flag the problem up front than to risk permanent EIO death of
383d26
the block device down the road.  The new bounds check adds
383d26
an assertion that will never fail, but rather exists to help
383d26
the compiler see that adding two positive 41-bit values
383d26
(given MBR constraints) can't overflow 64-bit off_t.
383d26
383d26
Using off_t to represent a partition length is a bit of a
383d26
misnomer; a later patch will update to saner types, but it
383d26
is left separate in case the bounds check needs to be
383d26
backported in isolation.
383d26
383d26
Also, note that the partition code blindly overwrites any
383d26
non-zero offset passed in by the user; so for now, make the
383d26
-o/-P combo an error for less confusion.  In the future, we
383d26
may let -o and -P work together (selecting a subset of a
383d26
partition); so it is okay that an explicit '-o 0' behaves
383d26
no differently from omitting -o.
383d26
383d26
This can be tested with nbdkit:
383d26
$ echo hi > file
383d26
$ nbdkit -fv --filter=truncate partitioning file truncate=64k
383d26
383d26
Pre-patch:
383d26
$ qemu-nbd -p 10810 -P 1 -f raw nbd://localhost:10809 &
383d26
$ qemu-io -f raw nbd://localhost:10810
383d26
qemu-io> r -v 0 1
383d26
Disconnect client, due to: Failed to send reply: reading from file failed: Input/output error
383d26
Connection closed
383d26
read failed: Input/output error
383d26
qemu-io> q
383d26
[1]+  Done                    qemu-nbd -p 10810 -P 1 -f raw nbd://localhost:10809
383d26
383d26
Post-patch:
383d26
$ qemu-nbd -p 10810 -P 1 -f raw nbd://localhost:10809
383d26
qemu-nbd: Discovered partition 1 at offset 1048576 size 512, but size exceeds file length 65536
383d26
383d26
Signed-off-by: Eric Blake <eblake@redhat.com>
383d26
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
383d26
Reviewed-by: Richard W.M. Jones <rjones@redhat.com>
383d26
Message-Id: <20190117193658.16413-5-eblake@redhat.com>
383d26
(cherry picked from commit 4485936b6de20afa38138e9d1e8ffed88cf0be73)
383d26
Signed-off-by: John Snow <jsnow@redhat.com>
383d26
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
383d26
---
383d26
 qemu-nbd.c | 22 +++++++++++++++++++++-
383d26
 1 file changed, 21 insertions(+), 1 deletion(-)
383d26
383d26
diff --git a/qemu-nbd.c b/qemu-nbd.c
383d26
index 51b55f2..5c90c5e 100644
383d26
--- a/qemu-nbd.c
383d26
+++ b/qemu-nbd.c
383d26
@@ -1013,12 +1013,32 @@ int main(int argc, char **argv)
383d26
     fd_size -= dev_offset;
383d26
 
383d26
     if (partition != -1) {
383d26
-        ret = find_partition(blk, partition, &dev_offset, &fd_size);
383d26
+        off_t limit;
383d26
+
383d26
+        if (dev_offset) {
383d26
+            error_report("Cannot request partition and offset together");
383d26
+            exit(EXIT_FAILURE);
383d26
+        }
383d26
+        ret = find_partition(blk, partition, &dev_offset, &limit);
383d26
         if (ret < 0) {
383d26
             error_report("Could not find partition %d: %s", partition,
383d26
                          strerror(-ret));
383d26
             exit(EXIT_FAILURE);
383d26
         }
383d26
+        /*
383d26
+         * MBR partition limits are (32-bit << 9); this assert lets
383d26
+         * the compiler know that we have two positive values that
383d26
+         * can't overflow 64 bits.
383d26
+         */
383d26
+        assert(dev_offset >= 0 && dev_offset + limit >= dev_offset);
383d26
+        if (dev_offset + limit > fd_size) {
383d26
+            error_report("Discovered partition %d at offset %lld size %lld, "
383d26
+                         "but size exceeds file length %lld", partition,
383d26
+                         (long long int) dev_offset, (long long int) limit,
383d26
+                         (long long int) fd_size);
383d26
+            exit(EXIT_FAILURE);
383d26
+        }
383d26
+        fd_size = limit;
383d26
     }
383d26
 
383d26
     export = nbd_export_new(bs, dev_offset, fd_size, export_name,
383d26
-- 
383d26
1.8.3.1
383d26