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