Bug 132705 - [libwrap] [patch] libwrap - infinite loop if hosts.allow line > 2k
Summary: [libwrap] [patch] libwrap - infinite loop if hosts.allow line > 2k
Status: Open
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: unspecified
Hardware: Any Any
: Normal Affects Only Me
Assignee: freebsd-bugs mailing list
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2009-03-16 19:00 UTC by Chris St Denis
Modified: 2018-01-03 05:16 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 Chris St Denis 2009-03-16 19:00:05 UTC
When given an input line of more than 2k bytes, libwrap ends up in an
infinite loop in xgets(), calling fgets() with a read length of one.
As fgets() reads the length minus one characters, it will keep
"reading" and returning zero length strings. 

This causes network daemons that use libwrap stop accepting
incoming network connections and use 100% cpu on an incoming connection.

This problem appeared because sshguard placed a large number of IPs (around 1000) in my hosts.allow file triggering this bug. 


Backtrace of an affected sshd process:

  crash# gdb /usr/sbin/sshd 691
  GNU gdb 6.1.1 [FreeBSD]
  Copyright 2004 Free Software Foundation, Inc.
  GDB is free software, covered by the GNU General Public License, and
  you are
  welcome to change it and/or distribute copies of it under certain
  conditions.
  Type "show copying" to see the conditions.
  There is absolutely no warranty for GDB.  Type "show warranty" for
  details.
  This GDB was configured as "i386-marcel-freebsd"...
  Attaching to program: /usr/sbin/sshd, process 691
  Reading symbols from /usr/lib/libssh.so.4...done.
  Loaded symbols for /usr/lib/libssh.so.4
  Reading symbols from /lib/libutil.so.7...done.
  Loaded symbols for /lib/libutil.so.7
  Reading symbols from /lib/libz.so.4...done.
  Loaded symbols for /lib/libz.so.4
  Reading symbols from /usr/lib/libwrap.so.5...done.
  Loaded symbols for /usr/lib/libwrap.so.5
  <snip other symbols for breviry>
  Reading symbols from /libexec/ld-elf.so.1...done.
  Loaded symbols for /libexec/ld-elf.so.1
  0x28373225 in fgets (buf=0xbfbfe67b "", n=1, fp=0x283b8040) at
  /usr/src/lib/libc/stdio/fgets.c:56
  56      {
  (gdb) bt
  #0  0x28373225 in fgets (buf=0xbfbfe67b "", n=1, fp=0x283b8040) at
  /usr/src/lib/libc/stdio/fgets.c:56
  #1  0x281124ee in xgets (ptr=0xbfbfe67b "", len=1, fp=0x283b8040) at
  /usr/src/lib/libwrap/../../contrib/tcp_wrappers/misc.c:38
  #2  0x28111410 in table_match (table=0x28112c5c "/etc/hosts.allow",
  request=0xbfbfeb14)
      at
  /usr/src/lib/libwrap/../../contrib/tcp_wrappers/hosts_access.c:162
  #3  0x28111540 in hosts_access (request=0xbfbfeb14) at
  /usr/src/lib/libwrap/../../contrib/tcp_wrappers/hosts_access.c:132
  #4  0x08052b39 in main (ac=2, av=0xbfbfeecc) at
  /usr/src/secure/usr.sbin/sshd/../../../crypto/openssh/sshd.c:1843
  (gdb) bt
  #0  0x28373225 in fgets (buf=0xbfbfe67b "", n=1, fp=0x283b8040) at
  /usr/src/lib/libc/stdio/fgets.c:56
  #1  0x281124ee in xgets (ptr=0xbfbfe67b "", len=1, fp=0x283b8040) at
  /usr/src/lib/libwrap/../../contrib/tcp_wrappers/misc.c:38
  #2  0x28111410 in table_match (table=0x28112c5c "/etc/hosts.allow",
  request=0xbfbfeb14)
      at
  /usr/src/lib/libwrap/../../contrib/tcp_wrappers/hosts_access.c:162
  #3  0x28111540 in hosts_access (request=0xbfbfeb14) at
  /usr/src/lib/libwrap/../../contrib/tcp_wrappers/hosts_access.c:132
  #4  0x08052b39 in main (ac=2, av=0xbfbfeecc) at
  /usr/src/secure/usr.sbin/sshd/../../../crypto/openssh/sshd.c:1843
  (gdb) q
  The program is running.  Quit anyway (and detach it)? (y or n) y
  Detaching from program: /usr/sbin/sshd, process 691 


See also: thread on FreeBSD Hackers list: http://docs.freebsd.org/cgi/getmsg.cgi?fetch=203036+0+archive/2009/freebsd-hackers/20090315.freebsd-hackers

Fix: Mikko Työläjärvi from the FreeBSD Hackers list provided a possible patch and some recommendations for better patching. His contribution pasted below.

This Q&D patch makes libwrap behave as documented in hosts_access(5):



See also, his full post: http://docs.freebsd.org/cgi/getmsg.cgi?fetch=3542+0+current/freebsd-hackers


Nate Eldredge also commented:

It doesn't seem like it should be too bad.  xgets is only called in three places.  It would be easy enough to replace it with something like glibc's getline(3), that uses realloc to size a buffer appropriately.--YbPUPByMtL2gWHrHPOQvKXvMvtiCQyp5txYVSNZQOjiPOOA5
Content-Type: text/plain; name="file.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="file.diff"

--- misc.c.orig    2009-03-15 14:06:11.000000000 -0700
+++ misc.c    2009-03-15 14:06:49.000000000 -0700
@@ -48,6 +48,8 @@
      ptr += got;
      len -= got;
      ptr[0] = 0;
+        if (len <= 1)
+            return start;
      }
      return (ptr > start ? start : 0);
  }
..
This is only sligtly better, as the code will now try to parse the
remainder of the line as a rule, and either fail or, due to some
syntactic quirk, get a false match.  From a security standpoint, both
are bad. 
..
The real fix involves rewriting chunks of the libwrap code, or finding
a version where someone has already done so. 
How-To-Repeat: Create a hosts.allow file with a long line, such as:

Example hosts.allow file (IPs are randomly generated for purposes of example)

  sshd : 112.110.123.63 113.11.2.126 113.11.8.6 113.19.19.22
  113.197.48.68 <snipped 990+ IPs for space> 116.48.108.244 116.48.11.19 : deny
  ALL : ALL : allow

connect to any network daemon using libwrap (such as sshd).
Comment 1 Mark Linimon freebsd_committer freebsd_triage 2009-03-17 00:34:17 UTC
Responsible Changed
From-To: freebsd-bugs->freebsd-net

Over to maintainer(s).
Comment 2 Eitan Adler freebsd_committer freebsd_triage 2017-12-31 08:01:11 UTC
For bugs matching the following criteria:

Status: In Progress Changed: (is less than) 2014-06-01

Reset to default assignee and clear in-progress tags.

Mail being skipped