Our open-coding of strtol handling forgot to handle overflow
conditions. What's more, since we insiste on a user-supplied
partition to be non-zero, we can use 0 rather than -1 for our
initial value to distinguish when a partition is not being
served, for slightly more optimal code.
Signed-off-by: Eric Blake <eblake@redhat.com>
---
qemu-nbd.c | 14 +++++---------
1 file changed, 5 insertions(+), 9 deletions(-)
diff --git a/qemu-nbd.c b/qemu-nbd.c
index 55e29bd9a7e..866e64779f1 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -546,7 +546,7 @@ int main(int argc, char **argv)
int opt_ind = 0;
char *end;
int flags = BDRV_O_RDWR;
- int partition = -1;
+ int partition = 0;
int ret = 0;
bool seen_cache = false;
bool seen_discard = false;
@@ -685,13 +685,9 @@ int main(int argc, char **argv)
flags &= ~BDRV_O_RDWR;
break;
case 'P':
- partition = strtol(optarg, &end, 0);
- if (*end) {
- error_report("Invalid partition `%s'", optarg);
- exit(EXIT_FAILURE);
- }
- if (partition < 1 || partition > 8) {
- error_report("Invalid partition %d", partition);
+ if (qemu_strtoi(optarg, NULL, 0, &partition) < 0 ||
+ partition < 1 || partition > 8) {
+ error_report("Invalid partition %s", optarg);
exit(EXIT_FAILURE);
}
break;
@@ -1004,7 +1000,7 @@ int main(int argc, char **argv)
}
fd_size -= dev_offset;
- if (partition != -1) {
+ if (partition) {
ret = find_partition(blk, partition, &dev_offset, &fd_size);
if (ret < 0) {
error_report("Could not find partition %d: %s", partition,
--
2.17.2
On Fri, Nov 30, 2018 at 04:03:33PM -0600, Eric Blake wrote:
> Our open-coding of strtol handling forgot to handle overflow
> conditions. What's more, since we insiste on a user-supplied
"insist"
> partition to be non-zero, we can use 0 rather than -1 for our
> initial value to distinguish when a partition is not being
> served, for slightly more optimal code.
>
> Signed-off-by: Eric Blake <eblake@redhat.com>
> ---
> qemu-nbd.c | 14 +++++---------
> 1 file changed, 5 insertions(+), 9 deletions(-)
>
> diff --git a/qemu-nbd.c b/qemu-nbd.c
> index 55e29bd9a7e..866e64779f1 100644
> --- a/qemu-nbd.c
> +++ b/qemu-nbd.c
> @@ -546,7 +546,7 @@ int main(int argc, char **argv)
> int opt_ind = 0;
> char *end;
> int flags = BDRV_O_RDWR;
> - int partition = -1;
> + int partition = 0;
> int ret = 0;
> bool seen_cache = false;
> bool seen_discard = false;
> @@ -685,13 +685,9 @@ int main(int argc, char **argv)
> flags &= ~BDRV_O_RDWR;
> break;
> case 'P':
> - partition = strtol(optarg, &end, 0);
> - if (*end) {
> - error_report("Invalid partition `%s'", optarg);
> - exit(EXIT_FAILURE);
> - }
> - if (partition < 1 || partition > 8) {
> - error_report("Invalid partition %d", partition);
> + if (qemu_strtoi(optarg, NULL, 0, &partition) < 0 ||
> + partition < 1 || partition > 8) {
> + error_report("Invalid partition %s", optarg);
Pffft only supporting a mere 8 partitions :-? I raised the limits in
nbdkit recently so it can handle an infinite number of partitions :-)
Anyway, it's a problem with the existing code, so doesn't affect the
review.
> exit(EXIT_FAILURE);
> }
> break;
> @@ -1004,7 +1000,7 @@ int main(int argc, char **argv)
> }
> fd_size -= dev_offset;
>
> - if (partition != -1) {
> + if (partition) {
> ret = find_partition(blk, partition, &dev_offset, &fd_size);
> if (ret < 0) {
> error_report("Could not find partition %d: %s", partition,
> --
> 2.17.2
Reviewed-by: Richard W.M. Jones <rjones@redhat.com>
Rich.
--
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming and virtualization blog: http://rwmj.wordpress.com
virt-builder quickly builds VMs from scratch
http://libguestfs.org/virt-builder.1.html
On 11/30/18 4:26 PM, Richard W.M. Jones wrote:
> On Fri, Nov 30, 2018 at 04:03:33PM -0600, Eric Blake wrote:
>> Our open-coding of strtol handling forgot to handle overflow
>> conditions. What's more, since we insiste on a user-supplied
>
> "insist"
(Ever wonder if I stick in a typo on purpose, just to see who reviews
closely?)
>
>> partition to be non-zero, we can use 0 rather than -1 for our
>> initial value to distinguish when a partition is not being
>> served, for slightly more optimal code.
>>
>> Signed-off-by: Eric Blake <eblake@redhat.com>
>> ---
>> qemu-nbd.c | 14 +++++---------
>> 1 file changed, 5 insertions(+), 9 deletions(-)
>>
>> + if (qemu_strtoi(optarg, NULL, 0, &partition) < 0 ||
>> + partition < 1 || partition > 8) {
>> + error_report("Invalid partition %s", optarg);
>
> Pffft only supporting a mere 8 partitions :-? I raised the limits in
> nbdkit recently so it can handle an infinite number of partitions :-)
nbdkit also handles GPT partitions. qemu-nbd is still stuck on MBR:
static int find_partition(BlockBackend *blk, int partition,
off_t *offset, off_t *size)
{
struct partition_record mbr[4];
uint8_t data[MBR_SIZE];
and if I read git blame correctly, the partition code in qemu-nbd is
mostly untouched since Fabrice committed Anthony's initial
implementation in 2008.
Also, reading the code, I see that qemu-nbd allows partitions 5-8
because it reads through the extended partition descriptor in 4 to
expose the logical partitions within; which nbdkit can't do yet :)
>
> Anyway, it's a problem with the existing code, so doesn't affect the
> review.
Indeed, and with nbdkit around, I'm wondering if I should deprecate
'qemu-nbd --partition' and just point people to nbdkit instead
(provided, of course, that nbdkit learns logical partitions).
Even if you have a qcow2 image with MBR partitions, and where we don't
want to write a qcow2 plugin in nbdkit, you can still always rewrite:
client -> qemu-nbd --partition=1
into
client -> nbdkit --filter=partition nbd partition=1 -> qemu-nbd
(although I don't know what the performance penalty would be)
--
Eric Blake, Principal Software Engineer
Red Hat, Inc. +1-919-301-3266
Virtualization: qemu.org | libvirt.org
01.12.2018 1:03, Eric Blake wrote:
> Our open-coding of strtol handling forgot to handle overflow
> conditions. What's more, since we insiste on a user-supplied
> partition to be non-zero, we can use 0 rather than -1 for our
> initial value to distinguish when a partition is not being
> served, for slightly more optimal code.
>
> Signed-off-by: Eric Blake <eblake@redhat.com>
> ---
> qemu-nbd.c | 14 +++++---------
> 1 file changed, 5 insertions(+), 9 deletions(-)
>
> diff --git a/qemu-nbd.c b/qemu-nbd.c
> index 55e29bd9a7e..866e64779f1 100644
> --- a/qemu-nbd.c
> +++ b/qemu-nbd.c
> @@ -546,7 +546,7 @@ int main(int argc, char **argv)
> int opt_ind = 0;
> char *end;
> int flags = BDRV_O_RDWR;
> - int partition = -1;
> + int partition = 0;
> int ret = 0;
> bool seen_cache = false;
> bool seen_discard = false;
> @@ -685,13 +685,9 @@ int main(int argc, char **argv)
> flags &= ~BDRV_O_RDWR;
> break;
> case 'P':
> - partition = strtol(optarg, &end, 0);
> - if (*end) {
> - error_report("Invalid partition `%s'", optarg);
> - exit(EXIT_FAILURE);
> - }
> - if (partition < 1 || partition > 8) {
> - error_report("Invalid partition %d", partition);
> + if (qemu_strtoi(optarg, NULL, 0, &partition) < 0 ||
I decided to look into qemu_strtoi, hmm.
is it possible, that "char *ep" remains uninitialized, and than we access
it in check_strtox_error? I don's see in strtol spec a guarantee of setting
endptr on failure path.
> + partition < 1 || partition > 8) {
don't you like brace on separate line after multi-line conditions?
> + error_report("Invalid partition %s", optarg);
> exit(EXIT_FAILURE);
> }
> break;
> @@ -1004,7 +1000,7 @@ int main(int argc, char **argv)
> }
> fd_size -= dev_offset;
>
> - if (partition != -1) {
> + if (partition) {
> ret = find_partition(blk, partition, &dev_offset, &fd_size);
> if (ret < 0) {
> error_report("Could not find partition %d: %s", partition,
>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
--
Best regards,
Vladimir
On 12/5/18 9:40 AM, Vladimir Sementsov-Ogievskiy wrote:
> 01.12.2018 1:03, Eric Blake wrote:
>> Our open-coding of strtol handling forgot to handle overflow
>> conditions. What's more, since we insiste on a user-supplied
>> partition to be non-zero, we can use 0 rather than -1 for our
>> initial value to distinguish when a partition is not being
>> served, for slightly more optimal code.
>>
>> - if (partition < 1 || partition > 8) {
>> - error_report("Invalid partition %d", partition);
>> + if (qemu_strtoi(optarg, NULL, 0, &partition) < 0 ||
>
> I decided to look into qemu_strtoi, hmm.
>
> is it possible, that "char *ep" remains uninitialized, and than we access
> it in check_strtox_error? I don's see in strtol spec a guarantee of setting
> endptr on failure path.
C99 7.10.1.4 P5-7 requires strtoll() and friends to assign through
'endptr' if it is non-NULL, for both success and ERANGE failure cases.
POSIX then further requires 'endptr' to be set for EINVAL failures due
to out-of-range 'base' (not that we have any such callers), and permits
(but does not require) the empty string to cause an EINVAL failure (but
whether or not EINVAL happened, 'endptr' is still set). There are no
other possible failures, so no, we are not dereferencing an
uninitialized variable in check_strtox_error.
>
>
>> + partition < 1 || partition > 8) {
>
> don't you like brace on separate line after multi-line conditions?
CODING_STYLE is silent on the matter; checkpatch.pl allows either style
for multi-line, while requesting the same line as the condition for
one-line (see commit a97ceca57). But since I'm already in the habit of
putting { right after the condition because of checkpatch, I don't go
out of my way to put it on its own line after multi-line conditionals.
I don't think it matters too much.
--
Eric Blake, Principal Software Engineer
Red Hat, Inc. +1-919-301-3266
Virtualization: qemu.org | libvirt.org
On 12/5/18 10:26 AM, Eric Blake wrote:
>> is it possible, that "char *ep" remains uninitialized, and than we access
>> it in check_strtox_error? I don's see in strtol spec a guarantee of
>> setting
>> endptr on failure path.
>
> C99 7.10.1.4 P5-7 requires strtoll() and friends to assign through
> 'endptr' if it is non-NULL, for both success and ERANGE failure cases.
> POSIX then further requires 'endptr' to be set for EINVAL failures due
> to out-of-range 'base' (not that we have any such callers), and permits
> (but does not require) the empty string to cause an EINVAL failure (but
> whether or not EINVAL happened, 'endptr' is still set). There are no
> other possible failures, so no, we are not dereferencing an
> uninitialized variable in check_strtox_error.
Correction, quoting POSIX:
http://pubs.opengroup.org/onlinepubs/9699919799/functions/strtol.html
APPLICATION USAGE
Since the value of *endptr is unspecified if the value of base is
not supported, applications should either ensure that base has a
supported value (0 or between 2 and 36) before the call, or check for an
[EINVAL] error before examining *endptr.
So yes, we CAN end up transferring an uninitialized variable into the
caller's non-NULL endpointer if the caller passes an out-of-range base
(this particular caller passes NULL for an endpointer, and an in-range
base, so it's not an issue). Might be worth a separate patch to assert
that base is in range for all of the qemu_strto* helpers, if we are
worried (I'm not).
--
Eric Blake, Principal Software Engineer
Red Hat, Inc. +1-919-301-3266
Virtualization: qemu.org | libvirt.org
On 11/30/18 4:03 PM, Eric Blake wrote:
> Our open-coding of strtol handling forgot to handle overflow
> conditions. What's more, since we insiste on a user-supplied
> partition to be non-zero, we can use 0 rather than -1 for our
> initial value to distinguish when a partition is not being
> served, for slightly more optimal code.
>
> Signed-off-by: Eric Blake <eblake@redhat.com>
> ---
> qemu-nbd.c | 14 +++++---------
> 1 file changed, 5 insertions(+), 9 deletions(-)
>
> diff --git a/qemu-nbd.c b/qemu-nbd.c
> index 55e29bd9a7e..866e64779f1 100644
> --- a/qemu-nbd.c
> +++ b/qemu-nbd.c
> @@ -546,7 +546,7 @@ int main(int argc, char **argv)
> int opt_ind = 0;
> char *end;
> int flags = BDRV_O_RDWR;
> - int partition = -1;
> + int partition = 0;
> int ret = 0;
> bool seen_cache = false;
> bool seen_discard = false;
> @@ -685,13 +685,9 @@ int main(int argc, char **argv)
> flags &= ~BDRV_O_RDWR;
> break;
> case 'P':
> - partition = strtol(optarg, &end, 0);
> - if (*end) {
> - error_report("Invalid partition `%s'", optarg);
> - exit(EXIT_FAILURE);
> - }
> - if (partition < 1 || partition > 8) {
> - error_report("Invalid partition %d", partition);
> + if (qemu_strtoi(optarg, NULL, 0, &partition) < 0 ||
Hmm - the fact that 'char *end' is not a dead variable means there are
more uses of strtoll() that need fixing. I'll get those in v2.
--
Eric Blake, Principal Software Engineer
Red Hat, Inc. +1-919-301-3266
Virtualization: qemu.org | libvirt.org
© 2016 - 2026 Red Hat, Inc.