Bug 108211 - [netinet] potentially a bug for inet_aton in sys/netinet/libalias/alias_proxy.c
Summary: [netinet] potentially a bug for inet_aton in sys/netinet/libalias/alias_proxy.c
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: Unspecified
Hardware: Any Any
: Normal Affects Only Me
Assignee: Maxim Konovalov
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2007-01-22 14:50 UTC by Yong Tang
Modified: 2007-05-14 18:32 UTC (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Yong Tang 2007-01-22 14:50:18 UTC
In sys/netinet/libalias/alias_proxy.c, 
The following code exist.

158 #ifdef  _KERNEL
159 static int
160 inet_aton(cp, addr)
161         const char *cp;
162         struct in_addr *addr;
163 {


180                 l = strtoul(c, &endptr, 0);
181 
182                 if (l == ULONG_MAX || l == 0)
183                         return (0);

However, if the input cp is "0.0.0.0", then it seems this function will return (0) which is considered as an error. 

The reason is because 180:
l = strtoul(c, &endptr, 0);
l will return a 0 when the c is "0".

Not quite sure if this is done purposely in FreeBSD but I have never experience similiar cases in other unix-platforms.

Possible solution:

change 
182 (l == ULONG_MAX || l == 0)

into
182 (l == ULONG_MAX || (l == 0 && (endptr == c))

Fix: 

Possible solution:

change 
182 (l == ULONG_MAX || l == 0)

into
182 (l == ULONG_MAX || (l == 0 && (endptr == c))
How-To-Repeat: review the code 180-182 in sys/netinet/libalias/alias_proxy.c
Comment 1 Bruce Evans 2007-01-23 06:11:27 UTC
On Mon, 22 Jan 2007, Yong Tang wrote:

>> Description:
> In sys/netinet/libalias/alias_proxy.c,
> The following code exist.
>
> 158 #ifdef  _KERNEL
> 159 static int
> 160 inet_aton(cp, addr)
> 161         const char *cp;
> 162         struct in_addr *addr;
> 163 {
>
>
> 180                 l = strtoul(c, &endptr, 0);
> 181
> 182                 if (l == ULONG_MAX || l == 0)
> 183                         return (0);
>
> However, if the input cp is "0.0.0.0", then it seems this function will return (0) which is considered as an error.

Bleah, yet another example of how not to check for errors in the strto*
family.

> The reason is because 180:
> l = strtoul(c, &endptr, 0);
> l will return a 0 when the c is "0".
>
> Not quite sure if this is done purposely in FreeBSD but I have never experience similiar cases in other unix-platforms.
>
> Possible solution:
>
> change
> 182 (l == ULONG_MAX || l == 0)
>
> into
> 182 (l == ULONG_MAX || (l == 0 && (endptr == c))

Why not just use libc's inet_aton()?  Well, there is a problem -- this
is for the kernel, so inet_aton() must be duplicated, but it can't be
duplicated literally since the strto* family is fundamentally broken
in the kernel.  strto*'s API depends on errno for reporting errors
correctly, and errno doesn't exist in the kernel.  This kernel version
is a literal duplicate of the libc version except for massive bitrot.
It is identical to an old libc version (libc/net/inet_addr.c 1.16)
except for small changes to avoid avoid checking errno and thus implement
the bug, and minor bitrot in the libc version (const poisoning has
only been done in the kernel).

The massive bitrot in the current libc version (libc/inet/inet_addr.c
1.3) is mainly to implement a home made broken version of strtoul()
inline.  Perhaps strtoul() is too inflexible, but I doubt it.  The
must obvious bug in the new version is the usual overflow in home made
implementations of atoi/strto*: "val = val * base + 'c' - '0'" may
overflow, but there is no overflow checking.  Thus the garbage input
"4294967297.1.1.1" is now treated as "1.1.1.1" on systems with 32-bit
unsigned longs although it is detected as being garbage on systems
with 64-bit unsigned longs.  Some style bugs are also obvious.

Possibly simpler solution for 1 kernel version and 2 userland versions:
- remove all traces of errno and related bogus checks for (l == ULONG_MAX)
   and (l == 0).  Checking (errno == ERANGE) isn't wrong, but it isn't
   needed since the value will be ULONG_MAX after a range error, and since
   ULONG_MAX is too large for part of a dotted quad address it will be
   detected as an error later.  Checking (l == ULONG_MAX) is wrong in
   general since it might not be a the result of a range error, but here
   the range is smaller so the check isn't wrong.  However, the check is
   unnecessary since all values between 256 and ULONG_MAX inclusive will
   be dected as errors later.  Checking (l == 0) is just a bug since 0
   is within range.
- remove broken home made strtol() in libc version, and otherwise merge
   versions and fix bitrot.  The "new" libc version is actually not newer,
   but just bitrot back to the vendor version.  FreeBSD fixed "old" version
   to use strtoul() in rev.1.8 in 1999, but the changes were lost when the
   vendor-version was reimported in a different directory in 2006.  FreeBSD
   also made a few fixes to the old version between 1.8 and 1.16.  The
   main one is related: 1.8 showed yet another way of how not to check
   for errors in strto* -- it checked (l == ERANGE) instead of
   (errno == ERANGE).  Some of its other changes are not quite right.

Bruce
Comment 2 Mark Linimon freebsd_committer freebsd_triage 2007-04-24 05:25:22 UTC
Responsible Changed
From-To: freebsd-bugs->freebsd-net

Over to maintainer(s).
Comment 3 dfilter service freebsd_committer freebsd_triage 2007-04-30 21:22:18 UTC
maxim       2007-04-30 20:22:11 UTC

  FreeBSD src repository

  Modified files:
    sys/netinet/libalias alias_proxy.c 
  Log:
  o Fix strtoul() error conditions check.
  
  PR:             kern/108211
  Submitted by:   Yong Tang
  MFC after:      2 weeks
  
  Revision  Changes    Path
  1.30      +1 -1      src/sys/netinet/libalias/alias_proxy.c
_______________________________________________
cvs-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/cvs-all
To unsubscribe, send any mail to "cvs-all-unsubscribe@freebsd.org"
Comment 4 Maxim Konovalov freebsd_committer freebsd_triage 2007-04-30 21:22:26 UTC
State Changed
From-To: open->patched

Fixed in HEAD.  Thanks! 


Comment 5 Maxim Konovalov freebsd_committer freebsd_triage 2007-04-30 21:22:26 UTC
Responsible Changed
From-To: freebsd-net->maxim

MFC reminder.
Comment 6 Maxim Konovalov freebsd_committer freebsd_triage 2007-05-14 18:32:00 UTC
State Changed
From-To: patched->closed

Merged to RELENG_6.