Blob Blame Raw
From e49b010d5f866b3ee7efbf40398f0a0832ce8801 Mon Sep 17 00:00:00 2001
From: Max Reitz <mreitz@redhat.com>
Date: Tue, 23 Jul 2019 14:45:43 +0100
Subject: [PATCH 05/14] nbd/client: Reject inaccessible tail of inconsistent
 server

RH-Author: Max Reitz <mreitz@redhat.com>
Message-id: <20190723144546.23701-5-mreitz@redhat.com>
Patchwork-id: 89649
O-Subject: [RHEL-8.1.0 qemu-kvm PATCH 4/7] nbd/client: Reject inaccessible tail of inconsistent server
Bugzilla: 1678979
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
RH-Acked-by: Stefano Garzarella <sgarzare@redhat.com>
RH-Acked-by: John Snow <jsnow@redhat.com>

From: Eric Blake <eblake@redhat.com>

The NBD spec suggests that a server should never advertise a size
inconsistent with its minimum block alignment, as that tail is
effectively inaccessible to a compliant client obeying those block
constraints. Since we have a habit of rounding up rather than
truncating, to avoid losing the last few bytes of user input, and we
cannot access the tail when the server advertises bogus block sizing,
abort the connection to alert the server to fix their bug.  And
rejecting such servers matches what we already did for a min_block
that was not a power of 2 or which was larger than max_block.

Does not impact either qemu (which always sends properly aligned
sizes) or nbdkit (which does not send minimum block requirements yet);
so this is mostly aimed at new NBD server implementations, and ensures
that the rest of our code can assume the size is aligned.

Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <20190330155704.24191-1-eblake@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
(cherry picked from commit 3add3ab78247fd347fd6f377a4b951022ac35d35)
Signed-off-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
---
 nbd/client.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/nbd/client.c b/nbd/client.c
index 25603f2..c828faf 100644
--- a/nbd/client.c
+++ b/nbd/client.c
@@ -416,6 +416,14 @@ static int nbd_opt_go(QIOChannel *ioc, const char *wantname,
                 nbd_send_opt_abort(ioc);
                 return -1;
             }
+            if (info->min_block &&
+                !QEMU_IS_ALIGNED(info->size, info->min_block)) {
+                error_setg(errp, "export size %" PRIu64 "is not multiple of "
+                           "minimum block size %" PRIu32, info->size,
+                           info->min_block);
+                nbd_send_opt_abort(ioc);
+                return -1;
+            }
             be16_to_cpus(&info->flags);
             trace_nbd_receive_negotiate_size_flags(info->size, info->flags);
             break;
-- 
1.8.3.1