|
|
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 |
|