Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 10 Nov 2006 08:55:39 +0000
From:      MQ <antinvidia@gmail.com>
To:        "Bruce Evans" <bde@zeta.org.au>
Cc:        freebsd-net@freebsd.org
Subject:   Re: Reentrant problem with inet_ntoa in the kernel
Message-ID:  <be0088ce0611100055i24d4e309k156aa69147488bfc@mail.gmail.com>
In-Reply-To: <20061105214041.F44623@delplex.bde.org>
References:  <be0088ce0611020026y4fe07749pd5a984f8744769b@mail.gmail.com> <20061102142543.GC70915@lor.one-eyed-alien.net> <be0088ce0611030146u5e97e08cmbd36e94d772c8a94@mail.gmail.com> <20061103141732.GA87515@lor.one-eyed-alien.net> <be0088ce0611031846l469b096bl536fec1d243da13f@mail.gmail.com> <20061105011849.GB6669@lor.one-eyed-alien.net> <20061105214041.F44623@delplex.bde.org>

next in thread | previous in thread | raw e-mail | index | archive | help
2006/11/5, Bruce Evans <bde@zeta.org.au>:
>
> On Sat, 4 Nov 2006, Brooks Davis wrote:
>
> > On Sat, Nov 04, 2006 at 02:46:30AM +0000, MQ wrote:
> >> 2006/11/3, Brooks Davis <brooks@one-eyed-alien.net>:
>
> >>> The particular definition used is excedingly ugly.  At a minimum there
> >>> needs to be a define or a constant "16" for the lenght rather than the
> >>> 4*sizeof("123") nonsense.
>
> The `4*sizeof "123"' is not nonsense.  It is better than the userland
> version
> at the time it was committed.  The userland version hard-coded the size as
> 18 (sic).  The current userland version still hard-codes 18, but now
> actually needs it to print an error message of length 17.  The uglyness in
> `4*sizeof "123"' is just that it has 3 formatting style bugs (missing
> spaces
> around binary operator, space after sizeof, and missing parentheses for
> sizeof) and depends on the storage for a '.' being the same as the storage
> for the the '\0' terminator.  I would write it as sizeof("255.255.255.255
> ").
>
> >> Oh, I see. This kind of definition is really annoying, and hard to keep
> all
> >> the
> >> occurrences consistent. Maybe a better way is use a macro to make that
> >> clear?
> >>
> >> #define IPV4_ADDRSZ (4 * sizeof "123")
> >> char buf[IPV4_ADDRSZ];
>
> This is less clear, since it takes twice as much code to obfuscate the
> size in a macro for no benefits since the macro is only used once.
>
> >> This "ugly" definition comes from inet_ntoa() in
> /sys/libkern/inet_ntoa.c,
> >> I just copied the style without too much consideration, it's my fault.
> >
> > I'd just use 16.  The inet_ntoa function is frankly inane.  It attempts
> > to support chars that aren't 8 bits which would break so much stuff it
> > isn't funny.
>
> No, it assumes 8-bit chars.  It's masking with 0xff is apparently copied
> from an old implementation that used plain chars.  The userland
> implementation at the time it was committed does that, but uses a macro
> to do the masking and is missing lots of style bugs.
>
> The userland version now calls inet_ntop().  This is missing the design
> bug of using a static buffer.  It calls inet_ntop4() for the ipv4 case.
> This is closer to being non-ugly:
>
> % static const char *
> % inet_ntop4(const u_char *src, char *dst, socklen_t size)
> % {
> %       static const char fmt[] = "%u.%u.%u.%u";
> %       char tmp[sizeof "255.255.255.255"];
> %       int l;
> %
> %       l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2],
> src[3]);
> %       if (l <= 0 || (socklen_t) l >= size) {
> %               errno = ENOSPC;
> %               return (NULL);
> %       }
> %       strlcpy(dst, tmp, size);
> %       return (dst);
> % }
>
> I would write this as:
>
> %%%
> CTASSERT(CHAR_BIT == 8);        /* else src would be misintepreted */
>
> static const char *
> inet_ntop4(const u_char *src, char *dst, socklen_t size)
> {
>         int n;
>
>         n = snprintf(dst, size, "%u.%u.%u.%u", src[0], src[1], src[2],
> src[3]);
>         assert(n >= 0);         /* CHAR_BIT == 8 imples 0 < n <= 16 */
>         if ((u_int)n >= size) {
>                 errno = ENOSPC;
>                 return (NULL);
>         }
>         return (dst);
> }
> %%%
>
> This is closer to the version in RELENG_6 than the current version.  It
> doesn't use tmp[]] to preserve dst on error, and fixes the bounds checking
> without introducing several style bugs and not actually fixing the bounds
> checking.  The old version was:
>
>         if ((socklen_t)snprintf(dst, size, fmt, src[0], src[1], src[2],
> src[3]
>             >= size) {
>                 ...
>         }
>
> This is good enough since 0 < l <= 16 implies that the preposterou case
> (l <= 0) and the preposterous broken case ((socklen_t)l != l) can't
> happen, but it is easier to use correct bounds checking than to understant
> why bugs in the bounds checking are harmless.
>
> Bruce
>


I don't know why the ret array in the userland version of the inet_ntoa
should be 17. The length of the message itself is 17, and an \0 is needed
for the str* to work.

By the way, 4 * sizeof("123") chars should be always enough to contain an
IPv4 address, no matter how many bits consititute a char.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?be0088ce0611100055i24d4e309k156aa69147488bfc>