kern/126349: MFC r179289 1.98 ip6_input.c breaks IPv6 control options return

Petr Lampa lampa at fit.vutbr.cz
Thu Aug 7 20:30:04 UTC 2008


>Number:         126349
>Category:       kern
>Synopsis:       MFC r179289 1.98 ip6_input.c breaks IPv6 control options return
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Aug 07 20:30:03 UTC 2008
>Closed-Date:
>Last-Modified:
>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 at 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:
>Unformatted:


More information about the freebsd-bugs mailing list