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

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