From Qing.Li@windriver.com  Tue Apr 30 11:14:18 2002
Return-Path: <Qing.Li@windriver.com>
Received: from mail.wrs.com (unknown-1-11.windriver.com [147.11.1.11])
	by hub.freebsd.org (Postfix) with ESMTP id 9B44337B404
	for <FreeBSD-gnats-submit@freebsd.org>; Tue, 30 Apr 2002 11:14:17 -0700 (PDT)
Received: from heavygear (heavygear [147.11.38.42])
	by mail.wrs.com (8.9.3/8.9.1) with SMTP id LAA00034
	for <FreeBSD-gnats-submit@freebsd.org>; Tue, 30 Apr 2002 11:13:23 -0700 (PDT)
Message-Id: <DMEGKJAJNLKBGDDBEAIPAEFEEOAA.Qing.Li@windriver.com>
Date: Tue, 30 Apr 2002 11:13:40 -0700
From: "Qing Li" <Qing.Li@windriver.com>
To: <FreeBSD-gnats-submit@freebsd.org>
Subject: genmask, rt_fixchange, and kernel panic

>Number:         37606
>Category:       kern
>Synopsis:       genmask, rt_fixchange causes kernel panic
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    ru
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Apr 30 11:20:01 PDT 2002
>Closed-Date:    Fri Jan 17 00:04:51 PST 2003
>Last-Modified:  Fri Jan 17 00:04:51 PST 2003
>Originator:     Qing Li
>Release:        FreeBSD 4.5-STABLE i386
>Organization:
>Environment:
System: FreeBSD a.b.com 4.5-STABLE FreeBSD 4.5-STABLE #0: Tue Mar 5 17:05:43
GMT 2002 root@a.b.com:/usr/obj/usr/src/sys/GENERIC i386


CPU: Pentium II/Pentium II Xeon/Celeron (265.37-MHz 686-class CPU)
  Origin = "GenuineIntel"  Id = 0x634  Stepping = 4

Features=0x80f9ff<FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,SEP,MTRR,PGE,MCA,CMOV,M
MX>
real memory  = 167772160 (163840K bytes)
avail memory = 158347264 (154636K bytes)

>Description:

Creating a route entry with -cloning flag and the -genmask
option causes a kernel panic on 4.5-STABLE.

The cloned entry created is a network route. The problem
appears to be in route.c, in "rtrequest1" function, where

    if (!(rt->rt_flags & RTF_HOST) && (rt_mask(rt) !=0)
      <snip>
               rnh->rnh_walktree_from(..,rt_fixchange,.)

This newly created entry is immediately removed inside
rt_fixchange. This invalid "rt" pointer is returned back
to the caller.

This problem did not show up in the previous version of
the code apparently due to the missing flag check on
RTF_CLONING in the code above,

   if (cmd == RTM_RESOLVE)
      <snip>
      if ((*ret_nrt)->rt_flags & RTF_PRCLONING) (old version)

   new version
      if ((*ret_nrt)->rt_flags & (RTF_CLONING & RTF_PRCLONING)

   The rt_parent is not assigned so rt_fixchange returned
   immediately in the previous version.

   I am also not sure why rt_fixchange is needed if
   cmd is RTM_RESOLVE.

>How-To-Repeat:

  route add -net 10.2.10.5 -netmask 255.255.0.0 -cloning
  -genmask 255.255.255.0 64.81.55.1

  ping 10.2.10.6

>Fix:

*** route.c.org	Tue Apr 30 10:19:47 2002
--- route.c	Tue Apr 30 10:20:49 2002
***************
*** 846,851 ****
--- 846,854 ----
  		printf("rt_fixchange: rt %p, rt0 %p\n", rt, rt0);
  #endif

+         if (rt == rt0)
+           return 0;
+
  	if (!rt->rt_parent || (rt->rt_flags & RTF_PINNED)) {
  #ifdef DEBUG
  		if(rtfcdebug) printf("no parent or pinned\n");










>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->ru 
Responsible-Changed-By: johan 
Responsible-Changed-When: Wed May 1 17:20:59 PDT 2002 
Responsible-Changed-Why:  
Ruslan has done alot of commits to this area and 
he made the last commits to -stable. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=37606 

From: Ruslan Ermilov <ru@FreeBSD.org>
To: Garrett Wollman <wollman@FreeBSD.org>,
	Qing Li <Qing.Li@windriver.com>
Cc: net@FreeBSD.org, bug-followup@FreeBSD.org
Subject: Re: kern/37606: genmask, rt_fixchange causes kernel panic
Date: Wed, 5 Jun 2002 20:02:22 +0300

 On Tue, Apr 30, 2002 at 11:13:40AM -0700, Qing Li wrote:
 > 
 > Creating a route entry with -cloning flag and the -genmask
 > option causes a kernel panic on 4.5-STABLE.
 > 
 > The cloned entry created is a network route. The problem
 > appears to be in route.c, in "rtrequest1" function, where
 > 
 >     if (!(rt->rt_flags & RTF_HOST) && (rt_mask(rt) !=0)
 >       <snip>
 >                rnh->rnh_walktree_from(..,rt_fixchange,.)
 > 
 > This newly created entry is immediately removed inside
 > rt_fixchange. This invalid "rt" pointer is returned back
 > to the caller.
 > 
 > This problem did not show up in the previous version of
 > the code apparently due to the missing flag check on
 > RTF_CLONING in the code above,
 > 
 >    if (cmd == RTM_RESOLVE)
 >       <snip>
 >       if ((*ret_nrt)->rt_flags & RTF_PRCLONING) (old version)
 > 
 >    new version
 >       if ((*ret_nrt)->rt_flags & (RTF_CLONING & RTF_PRCLONING)
 > 
 >    The rt_parent is not assigned so rt_fixchange returned
 >    immediately in the previous version.
 > 
 >    I am also not sure why rt_fixchange is needed if
 >    cmd is RTM_RESOLVE.
 > 
 I am not sure as well, and hereby asking the original author.
 Garrett, what was the intent of adding this code to rtrequest1()
 in rev. 1.22:
 
    /*
     * We repeat the same procedure from rt_setgate() here because
     * it doesn't fire when we call it there because the node
     * hasn't been added to the tree yet.
     */
    if (!(rt->rt_flags & RTF_HOST)) {
            struct rtfc_arg arg;
            arg.rnh = rnh;
            arg.rt0 = rt;
            rnh->rnh_walktree_from(rnh, rt_key(rt), rt_mask(rt),
                                   rt_fixchange, &arg);
    }
 
 We are obviously either adding or cloning heer, why do we need to
 call rt_fixchange() at all?  Moreover, the node is already in the
 tree.
 
 Do we probably need to do this in the RTM_ADD case only, if yes,
 why?
 
 > >How-To-Repeat:
 > 
 >   route add -net 10.2.10.5 -netmask 255.255.0.0 -cloning
 >   -genmask 255.255.255.0 64.81.55.1
 > 
 >   ping 10.2.10.6
 > 
 > >Fix:
 > 
 > *** route.c.org	Tue Apr 30 10:19:47 2002
 > --- route.c	Tue Apr 30 10:20:49 2002
 > ***************
 > *** 846,851 ****
 > --- 846,854 ----
 >   		printf("rt_fixchange: rt %p, rt0 %p\n", rt, rt0);
 >   #endif
 > 
 > +         if (rt == rt0)
 > +           return 0;
 > +
 >   	if (!rt->rt_parent || (rt->rt_flags & RTF_PINNED)) {
 >   #ifdef DEBUG
 >   		if(rtfcdebug) printf("no parent or pinned\n");
 
 -- 
 Ruslan Ermilov		Sysadmin and DBA,
 ru@sunbay.com		Sunbay Software AG,
 ru@FreeBSD.org		FreeBSD committer,
 +380.652.512.251	Simferopol, Ukraine
 
 http://www.FreeBSD.org	The Power To Serve
 http://www.oracle.com	Enabling The Information Age
State-Changed-From-To: open->patched 
State-Changed-By: ru 
State-Changed-When: Mon Dec 23 05:16:34 PST 2002 
State-Changed-Why:  
Fixed this and another similar race by disallowing recursive 
walks in rt_fixchange() and rt_fixdelete(). 

Also optimized the RTM_RESOLVE change by not calling the 
rt_fixchange(). 

Thanks for the report! 

http://www.freebsd.org/cgi/query-pr.cgi?pr=37606 
State-Changed-From-To: patched->closed 
State-Changed-By: ru 
State-Changed-When: Fri Jan 17 00:03:57 PST 2003 
State-Changed-Why:  
Fixed in 4.7-STABLE, in src/sys/net/route.c,v 1.59.2.10. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=37606 
>Unformatted:
