From nobody@FreeBSD.org  Thu Aug  7 20:25:06 2008
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id 13A80106566B
	for <freebsd-gnats-submit@FreeBSD.org>; Thu,  7 Aug 2008 20:25:06 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (www.freebsd.org [IPv6:2001:4f8:fff6::21])
	by mx1.freebsd.org (Postfix) with ESMTP id 0049F8FC14
	for <freebsd-gnats-submit@FreeBSD.org>; Thu,  7 Aug 2008 20:25:05 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.14.2/8.14.2) with ESMTP id m77KP5QP045750
	for <freebsd-gnats-submit@FreeBSD.org>; Thu, 7 Aug 2008 20:25:05 GMT
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.14.2/8.14.1/Submit) id m77KP5Jo045735;
	Thu, 7 Aug 2008 20:25:05 GMT
	(envelope-from nobody)
Message-Id: <200808072025.m77KP5Jo045735@www.freebsd.org>
Date: Thu, 7 Aug 2008 20:25:05 GMT
From: Petr Lampa <lampa@fit.vutbr.cz>
To: freebsd-gnats-submit@FreeBSD.org
Subject: MFC r179289 1.98 ip6_input.c breaks IPv6 control options return
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         126349
>Category:       kern
>Synopsis:       MFC r179289 1.98 ip6_input.c breaks IPv6 control options return
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    bz
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Aug 07 20:30:03 UTC 2008
>Closed-Date:    Mon Aug 18 23:10:22 UTC 2008
>Last-Modified:  Mon Aug 18 23:20:01 UTC 2008
>Originator:     Petr Lampa
>Release:        RELENG_7
>Organization:
FIT BUT
>Environment:
FreeBSD radka.fit.vutbr.cz 7.0-STABLE FreeBSD 7.0-STABLE #5: Thu Aug  7 11:28:35 CEST 2008 root@radka.fit.vutbr.cz:/usr/src/sys/i386/compile/RADKA  i386

>Description:
ip6_savecontrol() split into two functions ip6_savecontrol_v4() and ip6_savecontrol() has breaked options handling. If any option is stored in ip6_savecontrol_v4(), for instance IN6P_PKTINFO, mp is locally moved to the tail, but as this variable is local, this is not passed to ip6_savecontrol() and mp has original value here (it still points to opts). If any option is stored in ip6_savecontrol(), then all previous options stored in ip6_savecontrol_v4() are lost. This manifests clearly in xorp (it uses PKTINFO and TCLASS) with invalid destination errors:

ERROR xorp_fea:12158 FEA +1691 io_ip_socket.cc proto_socket_read ] proto_socket_read() failed: invalid destination address: ::
>How-To-Repeat:
Run xorp with IPv6 routing on RELENG_7 or HEAD, probably some other programs with recvmsg() ipv6 options processing stopped working.
>Fix:
I have added another parameter to return resulting value of mp (pointing to the tail of the control list). This parameter is returned only when provided, it's not needed for udp_append(). Here is the patch (tested, xorp running now):

diff -c netinet/udp_usrreq.c.old netinet/udp_usrreq.c
*** netinet/udp_usrreq.c.old    Thu Aug  7 22:02:02 2008
--- netinet/udp_usrreq.c        Thu Aug  7 22:02:54 2008
***************
*** 215,221 ****
            inp->inp_socket->so_options & (SO_TIMESTAMP | SO_BINTIME)) {
  #ifdef INET6
                if (inp->inp_vflag & INP_IPV6)
!                       ip6_savecontrol_v4(inp, n, &opts);
                else
  #endif
                        ip_savecontrol(inp, &opts, ip, n);
--- 215,221 ----
            inp->inp_socket->so_options & (SO_TIMESTAMP | SO_BINTIME)) {
  #ifdef INET6
                if (inp->inp_vflag & INP_IPV6)
!                       ip6_savecontrol_v4(inp, n, &opts, NULL);
                else
  #endif
                        ip_savecontrol(inp, &opts, ip, n);
diff -c netinet6/ip6_input.c.old netinet6/ip6_input.c
*** netinet6/ip6_input.c.old    Thu Aug  7 19:55:28 2008
--- netinet6/ip6_input.c        Thu Aug  7 22:02:40 2008
***************
*** 1043,1049 ****
   * options and handle the v6-only ones itself.
   */
  int
! ip6_savecontrol_v4(struct inpcb *inp, struct mbuf *m, struct mbuf **mp)
  {
        struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);

--- 1043,1049 ----
   * options and handle the v6-only ones itself.
   */
  int
! ip6_savecontrol_v4(struct inpcb *inp, struct mbuf *m, struct mbuf **mp, struct mbuf ***last_mp)
  {
        struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);

***************
*** 1056,1061 ****
--- 1056,1062 ----
                    SCM_TIMESTAMP, SOL_SOCKET);
                if (*mp)
                        mp = &(*mp)->m_next;
+               if (last_mp) *last_mp = mp;
        }
  #endif

***************
*** 1088,1093 ****
--- 1089,1095 ----
                if (*mp)
                        mp = &(*mp)->m_next;
        }
+       if (last_mp) *last_mp = mp;

        return (0);
  }
***************
*** 1096,1104 ****
  ip6_savecontrol(struct inpcb *in6p, struct mbuf *m, struct mbuf **mp)
  {
        struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);

!       if (ip6_savecontrol_v4(in6p, m, mp) != 0)
                return;

        if ((in6p->in6p_flags & IN6P_TCLASS) != 0) {
                u_int32_t flowinfo;
--- 1098,1108 ----
  ip6_savecontrol(struct inpcb *in6p, struct mbuf *m, struct mbuf **mp)
  {
        struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
+       struct mbuf **last_mp = NULL;

!       if (ip6_savecontrol_v4(in6p, m, mp, &last_mp) != 0)
                return;
+       if (last_mp) mp = last_mp;

        if ((in6p->in6p_flags & IN6P_TCLASS) != 0) {
                u_int32_t flowinfo;

diff -c netinet6/ip6_var.h.old netinet6/ip6_var.h
*** netinet6/ip6_var.h.old      Thu Aug  7 22:02:17 2008
--- netinet6/ip6_var.h  Thu Aug  7 22:02:30 2008
***************
*** 350,356 ****

  int   ip6_process_hopopts __P((struct mbuf *, u_int8_t *, int, u_int32_t *,
                                 u_int32_t *));
! int   ip6_savecontrol_v4(struct inpcb *, struct mbuf *, struct mbuf **);
  void  ip6_savecontrol __P((struct inpcb *, struct mbuf *, struct mbuf **));
  void  ip6_notify_pmtu __P((struct inpcb *, struct sockaddr_in6 *,
                             u_int32_t *));
--- 350,356 ----

  int   ip6_process_hopopts __P((struct mbuf *, u_int8_t *, int, u_int32_t *,
                                 u_int32_t *));
! int   ip6_savecontrol_v4(struct inpcb *, struct mbuf *, struct mbuf **, struct mbuf ***);
  void  ip6_savecontrol __P((struct inpcb *, struct mbuf *, struct mbuf **));
  void  ip6_notify_pmtu __P((struct inpcb *, struct sockaddr_in6 *,
                             u_int32_t *));



>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->bz 
Responsible-Changed-By: bz 
Responsible-Changed-When: Fri Aug 8 06:02:24 UTC 2008 
Responsible-Changed-Why:  
Mine. 

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

From: "Bjoern A. Zeeb" <bz@FreeBSD.org>
To: Petr Lampa <lampa@fit.vutbr.cz>
Cc: bug-followup@FreeBSD.org
Subject: Re: kern/126349: MFC r179289 1.98 ip6_input.c breaks IPv6 control
 options return
Date: Sun, 10 Aug 2008 20:31:05 +0000 (UTC)

 Hi,
 
 does the following patch work for you as well? You can also temporary
 fetch it from
 http://people.freebsd.org/~bz/20080810-01-ip6_savecontrol_v4-fixup.diff
 
 ------------------------------------------------------------------------
 Index: sys/netinet/udp_usrreq.c
 ===================================================================
 --- sys/netinet/udp_usrreq.c	(revision 181529)
 +++ sys/netinet/udp_usrreq.c	(working copy)
 @@ -216,7 +216,7 @@
   	    inp->inp_socket->so_options & (SO_TIMESTAMP | SO_BINTIME)) {
   #ifdef INET6
   		if (inp->inp_vflag & INP_IPV6)
 -			ip6_savecontrol_v4(inp, n, &opts);
 +			(void)ip6_savecontrol_v4(inp, n, &opts, NULL);
   		else
   #endif
   			ip_savecontrol(inp, &opts, ip, n);
 Index: sys/netinet6/ip6_var.h
 ===================================================================
 --- sys/netinet6/ip6_var.h	(revision 181529)
 +++ sys/netinet6/ip6_var.h	(working copy)
 @@ -350,7 +350,8 @@
 
   int	ip6_process_hopopts __P((struct mbuf *, u_int8_t *, int, u_int32_t *,
   				 u_int32_t *));
 -int	ip6_savecontrol_v4(struct inpcb *, struct mbuf *, struct mbuf **);
 +struct mbuf	**ip6_savecontrol_v4(struct inpcb *, struct mbuf *,
 +	    struct mbuf **, int *);
   void	ip6_savecontrol __P((struct inpcb *, struct mbuf *, struct mbuf **));
   void	ip6_notify_pmtu __P((struct inpcb *, struct sockaddr_in6 *,
   			     u_int32_t *));
 Index: sys/netinet6/ip6_input.c
 ===================================================================
 --- sys/netinet6/ip6_input.c	(revision 181529)
 +++ sys/netinet6/ip6_input.c	(working copy)
 @@ -1042,8 +1042,9 @@
    * ip6_savecontrol will directly call ip6_savecontrol_v4 to handle those
    * options and handle the v6-only ones itself.
    */
 -int
 -ip6_savecontrol_v4(struct inpcb *inp, struct mbuf *m, struct mbuf **mp)
 +struct mbuf **
 +ip6_savecontrol_v4(struct inpcb *inp, struct mbuf *m, struct mbuf **mp,
 +    int *v4only)
   {
   	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
 
 @@ -1059,8 +1060,11 @@
   	}
   #endif
 
 -	if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION)
 -		return (1);
 +	if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
 +		if (v4only != NULL)
 +			*v4only = 1;
 +		return (mp);
 +	}
 
   #define IS2292(inp, x, y)	(((inp)->inp_flags & IN6P_RFC2292) ? (x) : (y))
   	/* RFC 2292 sec. 5 */
 @@ -1089,15 +1093,19 @@
   			mp = &(*mp)->m_next;
   	}
 
 -	return (0);
 +	if (v4only != NULL)
 +		*v4only = 0;
 +	return (mp);
   }
 
   void
   ip6_savecontrol(struct inpcb *in6p, struct mbuf *m, struct mbuf **mp)
   {
   	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
 +	int v4only = 0;
 
 -	if (ip6_savecontrol_v4(in6p, m, mp) != 0)
 +	mp = ip6_savecontrol_v4(in6p, m, mp, &v4only);
 +	if (v4only)
   		return;
 
   	if ((in6p->in6p_flags & IN6P_TCLASS) != 0) {
 ------------------------------------------------------------------------
 
 
 -- 
 Bjoern A. Zeeb              Stop bit received. Insert coin for new game.
State-Changed-From-To: open->patched 
State-Changed-By: bz 
State-Changed-When: Sat Aug 16 06:40:50 UTC 2008 
State-Changed-Why:  
Patched in HEAD, MFC in a few days. 

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

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/126349: commit references a PR
Date: Sat, 16 Aug 2008 06:40:34 +0000 (UTC)

 bz          2008-08-16 06:39:18 UTC
 
   FreeBSD src repository
 
   Modified files:
     sys/netinet          udp_usrreq.c 
     sys/netinet6         ip6_input.c ip6_var.h 
   Log:
   SVN rev 181782 on 2008-08-16 06:39:18Z by bz
   
   Fix a regression introduced in r179289 splitting up ip6_savecontrol()
   into v4-only vs. v6-only inp_flags processing.
   When ip6_savecontrol_v4() is called from ip6_savecontrol() we
   were not passing back the **mp thus the information will be missing
   in userland.
   Istead of going with a *** as suggested in the PR we are returning
   **mp now and passing in the v4only flag as a pointer argument.
   
   PR:             kern/126349
   Reviewed by:    rwatson, dwmalone
   
   Revision  Changes    Path
   1.235     +1 -1      src/sys/netinet/udp_usrreq.c
   1.102     +14 -6     src/sys/netinet6/ip6_input.c
   1.44      +2 -1      src/sys/netinet6/ip6_var.h
 _______________________________________________
 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"
 
State-Changed-From-To: patched->closed 
State-Changed-By: bz 
State-Changed-When: Mon Aug 18 23:09:04 UTC 2008 
State-Changed-Why:  
The patch was MFCed. Thanks for reporting the bug and feedback on the patch. 

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

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/126349: commit references a PR
Date: Mon, 18 Aug 2008 23:01:37 +0000 (UTC)

 bz          2008-08-18 23:00:41 UTC
 
   FreeBSD src repository
 
   Modified files:        (Branch: RELENG_7)
     sys/netinet          udp_usrreq.c 
     sys/netinet6         ip6_input.c ip6_var.h 
   Log:
   SVN rev 181856 on 2008-08-18 23:00:41Z by bz
   
   MFC: r181782, cvs 1.235 udp_usrreq.c, 1.102 ip6_input.c, 1.44 ip6_var.h
   
     Fix a regression introduced in r179289 splitting up ip6_savecontrol()
     into v4-only vs. v6-only inp_flags processing.
     When ip6_savecontrol_v4() is called from ip6_savecontrol() we
     were not passing back the **mp thus the information will be missing
     in userland.
     Istead of going with a *** as suggested in the PR we are returning
     **mp now and passing in the v4only flag as a pointer argument.
   
   PR:     kern/126349
   
   Revision   Changes    Path
   1.218.2.3  +1 -1      src/sys/netinet/udp_usrreq.c
   1.95.2.2   +14 -6     src/sys/netinet6/ip6_input.c
   1.39.2.4   +2 -1      src/sys/netinet6/ip6_var.h
 _______________________________________________
 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"
 
>Unformatted:
