Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 19 Jun 2000 23:00:17 +0300 (EEST)
From:      Adrian Penisoara <ady@freebsd.ady.ro>
To:        FreeBSD-gnats-submit@freebsd.org
Cc:        Brian Somers <brian@Awfulhak.org>
Subject:   bin/19384: PPP route deletion bug/possible DoS
Message-ID:  <200006192000.XAA83914@ady.warpnet.ro>

next in thread | raw e-mail | index | archive | help

>Number:         19384
>Category:       bin
>Synopsis:       PPP route deletion bug/possible DoS
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Jun 19 13:00:00 PDT 2000
>Closed-Date:
>Last-Modified:
>Originator:     Adrian Penisoara
>Release:        FreeBSD 3.4-STABLE i386
>Organization:
Warp Net Technologies
>Environment:

  This has been "tested" on 3.4-STABLE, but, as I checked in the CVS
repository, it affects _all_ FreeBSD branches. OpenBSD might be affected
too ?!?

>Description:

  After more than half an year that I've been stressed by a weird route
deletion problem I finally discoverd the bug that affected me.

  First, let me say that my situation is a bit special in that I use
almost 30 PPP processes at the same time on our dial-up / leased line
server.
  The problem I was bitten by was that every now and then, and especially
whenever some dial-up user was hanging up, I was loosing routing
information on the first tunnel interfaces (including the IP on the
interface, I use proxy ARP).

  The problem: in function iface_Create in ppp/iface.c the index number of
the interface is taken from the routing table by comparing the interface
names with a strncmp call like this:

   dl = (struct sockaddr_dl *)(ifm + 1);		/* Single _dl at end */
   if (!strncmp(name, dl->sdl_data, dl->sdl_nlen)) {
     iface = (struct iface *)malloc(sizeof *iface);
        ...

  This code works as expected when using no more than 9 tunnel interfaces;
but when we are using an interface numbered over 9 (eg. tun28) then we
will be comparing strings like "tun28" and "tun2" on the length of the
second, so we'll have a match when we shouldn't had...
  This way the PPP process was computing a wrong index number in the
routing table. Later, when the process is about to die, in ppp/route.c, it
will remove the routes from the shorter named interface tunnel instead of
the right one (e.g. it will remove all routing information tied to tun2
instead of tun28). From this moment the link is effectively dead (at
least in the proxy ARP case): whatever traffic is sent from one end is
discarded on the other end, but the link remains up; the only solution is
to force a  link renegotiation in order to restore the routing 
information.

>How-To-Repeat:

  This may be exploited by users allowed to use PPP (e.g. users in group
network and with proper allow lines in /etc/ppp.conf), provided that
support for over 9 tunnel devices was compiled in the kernel: say an
user wants to block tun1, he will initiate a PPP session forcing the use of
a tunnel in the 10-19 range, like this:

  $ ppp -unit 12 link-label

  then he hangs up and upon termination all tun1's routing information
will be removed from the routing tables (this can be checked using "route
monitor" or even logging PPP at debug level).

>Fix:

 Suggested patch (tested with success for more than 2 hours):

--- usr.sbin/ppp/iface.c.orig	Mon Jan 10 20:29:04 2000
+++ usr.sbin/ppp/iface.c	Mon Jun 19 21:12:04 2000
@@ -91,6 +91,8 @@
   return bits;
 }
 
+static inline size_t max(size_t a, size_t b) { return (a>b ? a : b); }
+
 struct iface *
 iface_Create(const char *name)
 {
@@ -146,7 +148,7 @@
     if (ifm->ifm_type != RTM_IFINFO)
       break;
     dl = (struct sockaddr_dl *)(ifm + 1);		/* Single _dl at end */
-    if (!strncmp(name, dl->sdl_data, dl->sdl_nlen)) {
+    if (!strncmp(name, dl->sdl_data, max(strlen(name),dl->sdl_nlen))) {
       iface = (struct iface *)malloc(sizeof *iface);
       if (iface == NULL) {
         fprintf(stderr, "iface_Create: malloc: %s\n", strerror(errno));



  You may contact me for further details if you need.

 Thank you,
 Adrian Penisoara
 Ady (@freebsd.ady.ro)
 Warp Net Technologies

>Release-Note:
>Audit-Trail:
>Unformatted:


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




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