All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH] inet_listen_opts: add error checking
@ 2014-05-21 10:53 Gerd Hoffmann
  2014-05-21 11:57 ` Markus Armbruster
  2014-05-22  3:27 ` Gonglei (Arei)
  0 siblings, 2 replies; 12+ messages in thread
From: Gerd Hoffmann @ 2014-05-21 10:53 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Don't use atoi() function which doesn't detect errors, switch to
strtol and error out on failures.  Also add a range check while
being at it.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 util/qemu-sockets.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
index 8818d7c..22971e2 100644
--- a/util/qemu-sockets.c
+++ b/util/qemu-sockets.c
@@ -133,8 +133,19 @@ int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp)
         ai.ai_family = PF_INET6;
 
     /* lookup */
-    if (port_offset)
-        snprintf(port, sizeof(port), "%d", atoi(port) + port_offset);
+    if (port_offset) {
+        unsigned long long baseport;
+        if (parse_uint_full(port, &baseport, 10) < 0) {
+            error_setg(errp, "can't convert to a number: %s", port);
+            return -1;
+        }
+        if (base_port > 65535 ||
+            baseport + port_offset > 65535) {
+            error_setg(errp, "port %s out of range", port);
+            return -1;
+        }
+        snprintf(port, sizeof(port), "%d", (int)baseport + port_offset);
+    }
     rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res);
     if (rc != 0) {
         error_setg(errp, "address resolution failed for %s:%s: %s", addr, port,
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [Qemu-devel] [PATCH] inet_listen_opts: add error checking
  2014-05-21 10:53 [Qemu-devel] [PATCH] inet_listen_opts: add error checking Gerd Hoffmann
@ 2014-05-21 11:57 ` Markus Armbruster
  2014-05-22  3:27 ` Gonglei (Arei)
  1 sibling, 0 replies; 12+ messages in thread
From: Markus Armbruster @ 2014-05-21 11:57 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel

Gerd Hoffmann <kraxel@redhat.com> writes:

> Don't use atoi() function which doesn't detect errors, switch to
> strtol and error out on failures.  Also add a range check while
> being at it.
>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>

Reviewed-by: Markus Armbruster <armbru@redhat.com>

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Qemu-devel] [PATCH] inet_listen_opts: add error checking
  2014-05-21 10:53 [Qemu-devel] [PATCH] inet_listen_opts: add error checking Gerd Hoffmann
  2014-05-21 11:57 ` Markus Armbruster
@ 2014-05-22  3:27 ` Gonglei (Arei)
  2014-05-22  5:43   ` Gerd Hoffmann
  1 sibling, 1 reply; 12+ messages in thread
From: Gonglei (Arei) @ 2014-05-22  3:27 UTC (permalink / raw)
  To: Gerd Hoffmann, qemu-devel

> -----Original Message-----
> From: qemu-devel-bounces+arei.gonglei=huawei.com@nongnu.org
> [mailto:qemu-devel-bounces+arei.gonglei=huawei.com@nongnu.org] On
> Behalf Of Gerd Hoffmann
> Sent: Wednesday, May 21, 2014 6:53 PM
> To: qemu-devel@nongnu.org
> Cc: Gerd Hoffmann
> Subject: [Qemu-devel] [PATCH] inet_listen_opts: add error checking
> 
> Don't use atoi() function which doesn't detect errors, switch to
> strtol and error out on failures.  Also add a range check while
> being at it.
> 
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  util/qemu-sockets.c | 15 +++++++++++++--
>  1 file changed, 13 insertions(+), 2 deletions(-)
> 
> diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
> index 8818d7c..22971e2 100644
> --- a/util/qemu-sockets.c
> +++ b/util/qemu-sockets.c
> @@ -133,8 +133,19 @@ int inet_listen_opts(QemuOpts *opts, int port_offset,
> Error **errp)
>          ai.ai_family = PF_INET6;
> 
>      /* lookup */
> -    if (port_offset)
> -        snprintf(port, sizeof(port), "%d", atoi(port) + port_offset);
> +    if (port_offset) {
> +        unsigned long long baseport;

unsigned long long is not necessary, unsigned long is enough.

> +        if (parse_uint_full(port, &baseport, 10) < 0) {
> +            error_setg(errp, "can't convert to a number: %s", port);
> +            return -1;
> +        }
> +        if (base_port > 65535 ||

base_port is undeclared.

> +            baseport + port_offset > 65535) {
> +            error_setg(errp, "port %s out of range", port);
> +            return -1;
> +        }
> +        snprintf(port, sizeof(port), "%d", (int)baseport + port_offset);
> +    }
>      rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res);
>      if (rc != 0) {
>          error_setg(errp, "address resolution failed for %s:%s: %s", addr,
> port,
> --
> 1.8.3.1
> 


Best regards,
-Gonglei

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Qemu-devel] [PATCH] inet_listen_opts: add error checking
  2014-05-22  3:27 ` Gonglei (Arei)
@ 2014-05-22  5:43   ` Gerd Hoffmann
  2014-05-22  6:10     ` Gonglei (Arei)
  0 siblings, 1 reply; 12+ messages in thread
From: Gerd Hoffmann @ 2014-05-22  5:43 UTC (permalink / raw)
  To: Gonglei (Arei); +Cc: qemu-devel

> >      /* lookup */
> > -    if (port_offset)
> > -        snprintf(port, sizeof(port), "%d", atoi(port) + port_offset);
> > +    if (port_offset) {
> > +        unsigned long long baseport;
> 
> unsigned long long is not necessary, unsigned long is enough.
> 
> > +        if (parse_uint_full(port, &baseport, 10) < 0) {

parse_uint_full prototype uses "unsigned long long".  And on 32bit
machines it actually is a difference (long long is 64bit integer whereas
long is 32bit only).

> > +            error_setg(errp, "can't convert to a number: %s", port);
> > +            return -1;
> > +        }
> > +        if (base_port > 65535 ||
> 
> base_port is undeclared.

Oops, I'll fix.

cheers,
  Gerd

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Qemu-devel] [PATCH] inet_listen_opts: add error checking
  2014-05-22  5:43   ` Gerd Hoffmann
@ 2014-05-22  6:10     ` Gonglei (Arei)
  0 siblings, 0 replies; 12+ messages in thread
From: Gonglei (Arei) @ 2014-05-22  6:10 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel

> -----Original Message-----
> From: Gerd Hoffmann [mailto:kraxel@redhat.com]
> Sent: Thursday, May 22, 2014 1:44 PM
> To: Gonglei (Arei)
> Cc: qemu-devel@nongnu.org
> Subject: Re: [Qemu-devel] [PATCH] inet_listen_opts: add error checking
> 
> > >      /* lookup */
> > > -    if (port_offset)
> > > -        snprintf(port, sizeof(port), "%d", atoi(port) + port_offset);
> > > +    if (port_offset) {
> > > +        unsigned long long baseport;
> >
> > unsigned long long is not necessary, unsigned long is enough.
> >
> > > +        if (parse_uint_full(port, &baseport, 10) < 0) {
> 
> parse_uint_full prototype uses "unsigned long long".  And on 32bit
> machines it actually is a difference (long long is 64bit integer whereas
> long is 32bit only).
> 
Okay, Thanks.


Best regards,
-Gonglei

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [Qemu-devel] [PATCH] inet_listen_opts: add error checking
@ 2014-05-22  5:44 Gerd Hoffmann
  0 siblings, 0 replies; 12+ messages in thread
From: Gerd Hoffmann @ 2014-05-22  5:44 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Don't use atoi() function which doesn't detect errors, switch to
strtol and error out on failures.  Also add a range check while
being at it.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
---
 util/qemu-sockets.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
index 8818d7c..6861feb 100644
--- a/util/qemu-sockets.c
+++ b/util/qemu-sockets.c
@@ -133,8 +133,19 @@ int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp)
         ai.ai_family = PF_INET6;
 
     /* lookup */
-    if (port_offset)
-        snprintf(port, sizeof(port), "%d", atoi(port) + port_offset);
+    if (port_offset) {
+        unsigned long long baseport;
+        if (parse_uint_full(port, &baseport, 10) < 0) {
+            error_setg(errp, "can't convert to a number: %s", port);
+            return -1;
+        }
+        if (baseport > 65535 ||
+            baseport + port_offset > 65535) {
+            error_setg(errp, "port %s out of range", port);
+            return -1;
+        }
+        snprintf(port, sizeof(port), "%d", (int)baseport + port_offset);
+    }
     rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res);
     if (rc != 0) {
         error_setg(errp, "address resolution failed for %s:%s: %s", addr, port,
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [Qemu-devel] [PATCH] inet_listen_opts: add error checking
@ 2013-12-13  9:57 Gerd Hoffmann
  0 siblings, 0 replies; 12+ messages in thread
From: Gerd Hoffmann @ 2013-12-13  9:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Don't use atoi() function which doesn't detect errors, switch to
strtol and error out on failures.  Also add a range check while
being at it.

[ v2: use parse_uint_full instead of strtol ]

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 util/qemu-sockets.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
index 6b97dc1..5636510 100644
--- a/util/qemu-sockets.c
+++ b/util/qemu-sockets.c
@@ -133,8 +133,20 @@ int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp)
         ai.ai_family = PF_INET6;
 
     /* lookup */
-    if (port_offset)
-        snprintf(port, sizeof(port), "%d", atoi(port) + port_offset);
+    if (port_offset) {
+        int baseport;
+        errno = 0;
+        baseport = strtol(port, NULL, 10);
+        if (errno != 0) {
+            error_setg(errp, "can't convert to a number: %s", port);
+            return -1;
+        }
+        if (baseport < 0 || baseport + port_offset > 65535) {
+            error_setg(errp, "port %s out of range", port);
+            return -1;
+        }
+        snprintf(port, sizeof(port), "%d", baseport + port_offset);
+    }
     rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res);
     if (rc != 0) {
         error_setg(errp, "address resolution failed for %s:%s: %s", addr, port,
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [Qemu-devel] [PATCH] inet_listen_opts: add error checking
  2013-12-11 23:03 ` Eric Blake
  2013-12-12 12:27   ` Gerd Hoffmann
@ 2013-12-13  9:57   ` Gerd Hoffmann
  1 sibling, 0 replies; 12+ messages in thread
From: Gerd Hoffmann @ 2013-12-13  9:57 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel

  Hi,

> <rant>
> WHY is strtol() such a PAINFUL interface to use correctly?  And WHY
> can't qemu copy libvirt's lead of writing a SANE wrapper function, and
> then mandating that the rest of the code base use the sane wrapper
> instead of strtol()?
> </rant>

Turns out there already is one, just /me didn't know.
So, for the record and the mailing list archives:

util/cutil.c provides parse_uint() and parse_uint_full().

The first returns a pointer to the remaining bits to parse, so you can
inspect the suffix (if any).  The second errors out in case there is
trailing garbage, simliar to the libvirt wrapper in case you pass in
NULL as end_ptr.

cheers,
  Gerd

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Qemu-devel] [PATCH] inet_listen_opts: add error checking
  2013-12-12 12:27   ` Gerd Hoffmann
@ 2013-12-12 15:50     ` Eric Blake
  0 siblings, 0 replies; 12+ messages in thread
From: Eric Blake @ 2013-12-12 15:50 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 2111 bytes --]



On 12/12/2013 05:27 AM, Gerd Hoffmann wrote:
>   Hi,
> 
>>> +    if (port_offset) {
>>> +        int baseport;
>>> +        errno = 0;
>>> +        baseport = strtol(port, NULL, 10);
> 
>> <rant>
>> WHY is strtol() such a PAINFUL interface to use correctly?
> 
> Crossed my mind too after reading the manpage, which sayed you should
> clear errno to reliable detect errors as checking the return value
> doesn't cut it.
> 
> Your points obviously underline that.
> 
>>   And WHY
>> can't qemu copy libvirt's lead of writing a SANE wrapper function, and
>> then mandating that the rest of the code base use the sane wrapper
>> instead of strtol()?
>> </rant>
> 
> Care to share a pointer to the code?

/* Like strtol, but produce an "int" result, and check more carefully.
   Return 0 upon success;  return -1 to indicate failure.
   When END_PTR is NULL, the byte after the final valid digit must be NUL.
   Otherwise, it's like strtol and lets the caller check any suffix for
   validity.  This function is careful to return -1 when the string S
   represents a number that is not representable as an "int". */
int
virStrToLong_i(char const *s, char **end_ptr, int base, int *result)
{
    long int val;
    char *p;
    int err;

    errno = 0;
    val = strtol(s, &p, base); /* exempt from syntax-check */
    err = (errno || (!end_ptr && *p) || p == s || (int) val != val);
    if (end_ptr)
        *end_ptr = p;
    if (err)
        return -1;
    *result = val;
    return 0;
}

and other variants of virStrToLong_* for parsing into unsigned int,
long, etc.

Libvirt then couples that with a syntax check that gets run during 'make
syntax-check' (or we could even migrate it into 'make check') that
forbids all use of strtol() not on a line with the magic exemption
comment.  Therefore, the number of actual uses of strtol() in the source
code base is limited to just these wrapper functions, and everyone else
gets sane semantics.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 621 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Qemu-devel] [PATCH] inet_listen_opts: add error checking
  2013-12-11 23:03 ` Eric Blake
@ 2013-12-12 12:27   ` Gerd Hoffmann
  2013-12-12 15:50     ` Eric Blake
  2013-12-13  9:57   ` Gerd Hoffmann
  1 sibling, 1 reply; 12+ messages in thread
From: Gerd Hoffmann @ 2013-12-12 12:27 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel

  Hi,

> > +    if (port_offset) {
> > +        int baseport;
> > +        errno = 0;
> > +        baseport = strtol(port, NULL, 10);

> <rant>
> WHY is strtol() such a PAINFUL interface to use correctly?

Crossed my mind too after reading the manpage, which sayed you should
clear errno to reliable detect errors as checking the return value
doesn't cut it.

Your points obviously underline that.

>   And WHY
> can't qemu copy libvirt's lead of writing a SANE wrapper function, and
> then mandating that the rest of the code base use the sane wrapper
> instead of strtol()?
> </rant>

Care to share a pointer to the code?

thanks,
  Gerd

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Qemu-devel] [PATCH] inet_listen_opts: add error checking
  2013-12-11 12:00 Gerd Hoffmann
@ 2013-12-11 23:03 ` Eric Blake
  2013-12-12 12:27   ` Gerd Hoffmann
  2013-12-13  9:57   ` Gerd Hoffmann
  0 siblings, 2 replies; 12+ messages in thread
From: Eric Blake @ 2013-12-11 23:03 UTC (permalink / raw)
  To: Gerd Hoffmann, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 2182 bytes --]

On 12/11/2013 05:00 AM, Gerd Hoffmann wrote:
> Don't use atoi() function which doesn't detect errors, switch to
> strtol and error out on failures.  Also add a range check while
> being at it.
> 
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---

>      /* lookup */
> -    if (port_offset)
> -        snprintf(port, sizeof(port), "%d", atoi(port) + port_offset);
> +    if (port_offset) {
> +        int baseport;
> +        errno = 0;
> +        baseport = strtol(port, NULL, 10);

Fail #1: Silent truncation on 64-bit platforms.  If the user passed
0x100000000 you will see baseport==0 with no error indication (and
doesn't make it any nicer that a 32-bit platform will do what you wanted
- platform-dependent bugs are nasty).  :(

You need to assign the results of strtol() into a long, then do range
checking before truncating to int.

> +        if (errno != 0) {
> +            error_setg(errp, "can't convert to a number: %s", port);
> +            return -1;
> +        }

Fail #2: You forgot to do validation that a number was actually parsed.
 We hate atoi because atoi("a") is happily 0, but your use of strtol()
still has that bug.  POSIX states that implementations are allowed to
fail with EINVAL when parsing "a", but this failure mode is not required
to give an errno diagnostic.  Your code would reject "a" on glibc, but
accept it on other platforms (system-dependent bugs are nasty).  The
only portable way to ensure that a number was actually parsed and that
there is no garbage in the suffix is to pass in the address of a char*
in the second argument, then validate it against your string to ensure
that enough information was parsed and any suffix is expected.

The rest of this email is generic, and not specifically directed at you
or your patch:

<rant>
WHY is strtol() such a PAINFUL interface to use correctly?  And WHY
can't qemu copy libvirt's lead of writing a SANE wrapper function, and
then mandating that the rest of the code base use the sane wrapper
instead of strtol()?
</rant>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 621 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [Qemu-devel] [PATCH] inet_listen_opts: add error checking
@ 2013-12-11 12:00 Gerd Hoffmann
  2013-12-11 23:03 ` Eric Blake
  0 siblings, 1 reply; 12+ messages in thread
From: Gerd Hoffmann @ 2013-12-11 12:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Don't use atoi() function which doesn't detect errors, switch to
strtol and error out on failures.  Also add a range check while
being at it.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 util/qemu-sockets.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
index 6b97dc1..5636510 100644
--- a/util/qemu-sockets.c
+++ b/util/qemu-sockets.c
@@ -133,8 +133,20 @@ int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp)
         ai.ai_family = PF_INET6;
 
     /* lookup */
-    if (port_offset)
-        snprintf(port, sizeof(port), "%d", atoi(port) + port_offset);
+    if (port_offset) {
+        int baseport;
+        errno = 0;
+        baseport = strtol(port, NULL, 10);
+        if (errno != 0) {
+            error_setg(errp, "can't convert to a number: %s", port);
+            return -1;
+        }
+        if (baseport < 0 || baseport + port_offset > 65535) {
+            error_setg(errp, "port %s out of range", port);
+            return -1;
+        }
+        snprintf(port, sizeof(port), "%d", baseport + port_offset);
+    }
     rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res);
     if (rc != 0) {
         error_setg(errp, "address resolution failed for %s:%s: %s", addr, port,
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2014-05-22  6:11 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-05-21 10:53 [Qemu-devel] [PATCH] inet_listen_opts: add error checking Gerd Hoffmann
2014-05-21 11:57 ` Markus Armbruster
2014-05-22  3:27 ` Gonglei (Arei)
2014-05-22  5:43   ` Gerd Hoffmann
2014-05-22  6:10     ` Gonglei (Arei)
  -- strict thread matches above, loose matches on Subject: below --
2014-05-22  5:44 Gerd Hoffmann
2013-12-13  9:57 Gerd Hoffmann
2013-12-11 12:00 Gerd Hoffmann
2013-12-11 23:03 ` Eric Blake
2013-12-12 12:27   ` Gerd Hoffmann
2013-12-12 15:50     ` Eric Blake
2013-12-13  9:57   ` Gerd Hoffmann

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.