[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#588144: libc6: As shipped /etc/bindresvport.blacklist lines are ignored due to tabs



>From lenny's glibc-2.7/debian/patches/any/local-bindresvport_blacklist.diff
the code to read and parse a single line is:

+      unsigned long port;
+      char *tmp, *cp;
+      ssize_t n = __getline (&buf, &buflen, fp);
+      if (n < 1)
+        break;
+
+      cp = buf;
+      tmp = strchr (cp, '#');  /* remove comments */
+      if (tmp)
+        *tmp = '\0';
+      while (isspace ((int)*cp))    /* remove spaces and tabs */
+        ++cp;
+      if (*cp == '\0')        /* ignore empty lines */
+        continue;
+      if (cp[strlen (cp) - 1] == '\n')
+        cp[strlen (cp) - 1] = '\0';
+
+      port = strtoul (cp, &tmp, 0);
+      if (*tmp != '\0' || (port == ULONG_MAX && errno == ERANGE))
+       continue;

This has a couple of issues.

The one that causes a problem is that it skips leading but not trailing
spaces.  If the last digit of the number is followed by anything other
than '\0', '#', or '\n', the line will be skipped.

Code should be added after strtoul() to skip the spaces:
      while (isspace ((int)*tmp))    /* remove spaces and tabs */
        ++tmp;

Also, a comment purports to "ignore empty lines" by checking for a null
character, but it does this *before* replacing a newline at the end with
a null character.  As it happens, lines consisting solely of a newline
will be ignored, but only because of this code:

+      /* Don't bother with out-of-range ports */
+      if (port < LOWPORT || port > ENDPORT)
+        continue;

Therefore, the "ignore empty lines" comment is misleading.

In an Ubuntu bug report, I gave good directions for testing this.
https://bugs.launchpad.net/ubuntu/+source/glibc/+bug/306007

I have confirmed the directions work on lenny (I have an Ubuntu desktop
and a lenny server).  (Of course, I got different port numbers, but still
in the 600-999 range I reserved.)

0. Backup the file:
$ sudo mv /etc/bindresvport.blacklist /etc/bindresvport.blacklist.bak

1. Reserve all ports 600-999, with the format used for shipped
bindresvport.blacklist (e.g., "631\t# cups")
$ perl -e 'for ($i=600; $i<1000; $i++) {print "$i\t# foo\n";}' | sudo
dd of=/etc/bindresvport.blacklist
7+1 records in
7+1 records out
4011 bytes (4.0 kB) copied, 6.5962e-05 s, 60.8 MB/s

2. Restart nis (or a different service as available).
$ sudo /etc/init.d/nis restart
 * Starting NIS service

3. Check what port it got:
$ sudo netstat --inet -nap | grep ypbind
tcp 0 0 0.0.0.0:724 0.0.0.0:* LISTEN 29803/ypbind
udp 0 0 0.0.0.0:723 0.0.0.0:* 29803/ypbind
udp 0 0 0.0.0.0:724 0.0.0.0:* 29803/ypbind

4. Note that it falls in the range 600-999 (there is a small 24 out of
424 chance it will not -- try again).

This also fails with spaces, substituting the perl command in step 1:
$ perl -e 'for ($i=600; $i<1000; $i++) {print "$i # foo\n";}' | sudo
dd of=/etc/bindresvport.blacklist

It works with the '#' character directly following the port number:
$ perl -e 'for ($i=600; $i<1000; $i++) {print "$i# foo\n";}' | sudo dd
of=/etc/bindresvport.blacklist
or with the port number on the line by itself:
$ perl -e 'for ($i=600; $i<1000; $i++) {print "$i\n";}' | sudo dd
of=/etc/bindresvport.blacklist

In the last two cases I get:
tcp 0 0 0.0.0.0:1001 0.0.0.0:* LISTEN 29923/ypbind
udp 0 0 0.0.0.0:1000 0.0.0.0:* 29923/ypbind
udp 0 0 0.0.0.0:1001 0.0.0.0:* 29923/ypbind



Reply to: