Module Name: src Committed By: martin Date: Thu Mar 8 13:41:41 UTC 2018
Modified Files: src/sys/net [netbsd-8]: if_l2tp.c if_l2tp.h src/sys/netinet [netbsd-8]: in_l2tp.c src/sys/netinet6 [netbsd-8]: in6_l2tp.c Log Message: Pull up following revision(s) (requested by knakahara in ticket #614): sys/net/if_l2tp.c: revision 1.20 sys/netinet6/in6_l2tp.c: revision 1.13 sys/netinet6/in6_l2tp.c: revision 1.14 sys/net/if_l2tp.h: revision 1.3 sys/net/if_l2tp.c: revision 1.13 sys/netinet/in_l2tp.c: revision 1.10 sys/net/if_l2tp.c: revision 1.18 sys/netinet/in_l2tp.c: revision 1.11 sys/net/if_l2tp.c: revision 1.19 sys/netinet/in_l2tp.c: revision 1.12 If if_attach() failed in the attach function, return. Add comments about if_initialize(). suggested by ozaki-r@n.o. Fix null deref, m could be NULL if M_PREPEND fails. style Style, reduce the indentation level when possible, and add a missing NULL check after M_PREPEND. Several fixes in L2TP: * l2tp_input(): use m_copydata, and ensure there is enough space in the chain. Otherwise overflow. * l2tp_tcpmss_clamp(): ensure there is enough space in the chain. * in_l2tp_output(): don't check 'sc' against NULL, it can't be NULL. * in_l2tp_input(): no need to call m_pullup since we use m_copydata. Just check the space in the chain. * in_l2tp_input(): if there is a cookie, make sure the chain has enough space. * in6_l2tp_input(): same changes as in_l2tp_input(). Ok knakahara@ Use MH_ALIGN instead, ok knakahara@. To generate a diff of this commit: cvs rdiff -u -r1.11.2.4 -r1.11.2.5 src/sys/net/if_l2tp.c cvs rdiff -u -r1.2 -r1.2.2.1 src/sys/net/if_l2tp.h cvs rdiff -u -r1.2.8.3 -r1.2.8.4 src/sys/netinet/in_l2tp.c cvs rdiff -u -r1.5.8.3 -r1.5.8.4 src/sys/netinet6/in6_l2tp.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/net/if_l2tp.c diff -u src/sys/net/if_l2tp.c:1.11.2.4 src/sys/net/if_l2tp.c:1.11.2.5 --- src/sys/net/if_l2tp.c:1.11.2.4 Sun Feb 11 21:17:34 2018 +++ src/sys/net/if_l2tp.c Thu Mar 8 13:41:40 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: if_l2tp.c,v 1.11.2.4 2018/02/11 21:17:34 snj Exp $ */ +/* $NetBSD: if_l2tp.c,v 1.11.2.5 2018/03/08 13:41:40 martin Exp $ */ /* * Copyright (c) 2017 Internet Initiative Japan Inc. @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_l2tp.c,v 1.11.2.4 2018/02/11 21:17:34 snj Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_l2tp.c,v 1.11.2.5 2018/03/08 13:41:40 martin Exp $"); #ifdef _KERNEL_OPT #include "opt_inet.h" @@ -228,10 +228,17 @@ l2tp_clone_create(struct if_clone *ifc, { struct l2tp_softc *sc; struct l2tp_variant *var; + int rv; sc = kmem_zalloc(sizeof(struct l2tp_softc), KM_SLEEP); - var = kmem_zalloc(sizeof(struct l2tp_variant), KM_SLEEP); + if_initname(&sc->l2tp_ec.ec_if, ifc->ifc_name, unit); + rv = l2tpattach0(sc); + if (rv != 0) { + kmem_free(sc, sizeof(struct l2tp_softc)); + return rv; + } + var = kmem_zalloc(sizeof(struct l2tp_variant), KM_SLEEP); var->lv_softc = sc; var->lv_state = L2TP_STATE_DOWN; var->lv_use_cookie = L2TP_COOKIE_OFF; @@ -241,10 +248,6 @@ l2tp_clone_create(struct if_clone *ifc, mutex_init(&sc->l2tp_lock, MUTEX_DEFAULT, IPL_NONE); PSLIST_ENTRY_INIT(sc, l2tp_hash); - if_initname(&sc->l2tp_ec.ec_if, ifc->ifc_name, unit); - - l2tpattach0(sc); - sc->l2tp_ro_percpu = percpu_alloc(sizeof(struct l2tp_ro)); percpu_foreach(sc->l2tp_ro_percpu, l2tp_ro_init_pc, NULL); @@ -255,9 +258,10 @@ l2tp_clone_create(struct if_clone *ifc, return (0); } -void +int l2tpattach0(struct l2tp_softc *sc) { + int rv; sc->l2tp_ec.ec_if.if_addrlen = 0; sc->l2tp_ec.ec_if.if_mtu = L2TP_MTU; @@ -274,9 +278,19 @@ l2tpattach0(struct l2tp_softc *sc) sc->l2tp_ec.ec_if.if_transmit = l2tp_transmit; sc->l2tp_ec.ec_if._if_input = ether_input; IFQ_SET_READY(&sc->l2tp_ec.ec_if.if_snd); - if_attach(&sc->l2tp_ec.ec_if); + /* XXX + * It may improve performance to use if_initialize()/if_register() + * so that l2tp_input() calls if_input() instead of + * if_percpuq_enqueue(). However, that causes recursive softnet_lock + * when NET_MPSAFE is not set. + */ + rv = if_attach(&sc->l2tp_ec.ec_if); + if (rv != 0) + return rv; if_alloc_sadl(&sc->l2tp_ec.ec_if); bpf_attach(&sc->l2tp_ec.ec_if, DLT_EN10MB, sizeof(struct ether_header)); + + return 0; } void @@ -451,16 +465,23 @@ l2tpintr(struct l2tp_variant *var) void l2tp_input(struct mbuf *m, struct ifnet *ifp) { + u_long val; KASSERT(ifp != NULL); - if (0 == (mtod(m, u_long) & 0x03)) { + if (m->m_pkthdr.len < sizeof(val)) { + m_freem(m); + return; + } + + m_copydata(m, 0, sizeof(val), &val); + + if ((val & 0x03) == 0) { /* copy and align head of payload */ struct mbuf *m_head; int copy_length; #define L2TP_COPY_LENGTH 60 -#define L2TP_LINK_HDR_ROOM (MHLEN - L2TP_COPY_LENGTH - 4/*round4(2)*/) if (m->m_pkthdr.len < L2TP_COPY_LENGTH) { copy_length = m->m_pkthdr.len; @@ -481,19 +502,19 @@ l2tp_input(struct mbuf *m, struct ifnet } M_COPY_PKTHDR(m_head, m); - m_head->m_data += 2 /* align */ + L2TP_LINK_HDR_ROOM; - memcpy(m_head->m_data, m->m_data, copy_length); + MH_ALIGN(m_head, L2TP_COPY_LENGTH); + memcpy(mtod(m_head, void *), mtod(m, void *), copy_length); m_head->m_len = copy_length; m->m_data += copy_length; m->m_len -= copy_length; /* construct chain */ if (m->m_len == 0) { - m_head->m_next = m_free(m); /* not m_freem */ + m_head->m_next = m_free(m); } else { /* - * copyed mtag in previous call M_COPY_PKTHDR - * but don't delete mtag in case cutt of M_PKTHDR flag + * Already copied mtag with M_COPY_PKTHDR. + * but don't delete mtag in case cut off M_PKTHDR flag */ m_tag_delete_chain(m, NULL); m->m_flags &= ~M_PKTHDR; @@ -1352,80 +1373,90 @@ static struct mbuf *l2tp_tcpmss6_clamp(s #endif struct mbuf * -l2tp_tcpmss_clamp(struct ifnet *ifp, struct mbuf *m) +l2tp_tcpmss_clamp(struct ifnet *ifp, struct mbuf *m) { + struct ether_header *eh; + struct ether_vlan_header evh; - if (l2tp_need_tcpmss_clamp(ifp)) { - struct ether_header *eh; - struct ether_vlan_header evh; - - /* save ether header */ - m_copydata(m, 0, sizeof(evh), (void *)&evh); - eh = (struct ether_header *)&evh; - - switch (ntohs(eh->ether_type)) { - case ETHERTYPE_VLAN: /* Ether + VLAN */ - if (m->m_pkthdr.len <= sizeof(struct ether_vlan_header)) - break; - m_adj(m, sizeof(struct ether_vlan_header)); - switch (ntohs(evh.evl_proto)) { -#ifdef INET - case ETHERTYPE_IP: /* Ether + VLAN + IPv4 */ - m = l2tp_tcpmss4_clamp(ifp, m); - if (m == NULL) - return NULL; - break; -#endif /* INET */ -#ifdef INET6 - case ETHERTYPE_IPV6: /* Ether + VLAN + IPv6 */ - m = l2tp_tcpmss6_clamp(ifp, m); - if (m == NULL) - return NULL; - break; -#endif /* INET6 */ - default: - break; - } - /* restore ether header */ - M_PREPEND(m, sizeof(struct ether_vlan_header), - M_DONTWAIT); - if (m == NULL) - return NULL; - *mtod(m, struct ether_vlan_header *) = evh; + if (!l2tp_need_tcpmss_clamp(ifp)) { + return m; + } + + if (m->m_pkthdr.len < sizeof(evh)) { + m_freem(m); + return NULL; + } + + /* save ether header */ + m_copydata(m, 0, sizeof(evh), (void *)&evh); + eh = (struct ether_header *)&evh; + + switch (ntohs(eh->ether_type)) { + case ETHERTYPE_VLAN: /* Ether + VLAN */ + if (m->m_pkthdr.len <= sizeof(struct ether_vlan_header)) break; + m_adj(m, sizeof(struct ether_vlan_header)); + switch (ntohs(evh.evl_proto)) { #ifdef INET - case ETHERTYPE_IP: /* Ether + IPv4 */ - if (m->m_pkthdr.len <= sizeof(struct ether_header)) - break; - m_adj(m, sizeof(struct ether_header)); + case ETHERTYPE_IP: /* Ether + VLAN + IPv4 */ m = l2tp_tcpmss4_clamp(ifp, m); if (m == NULL) return NULL; - /* restore ether header */ - M_PREPEND(m, sizeof(struct ether_header), M_DONTWAIT); - if (m == NULL) - return NULL; - *mtod(m, struct ether_header *) = *eh; break; #endif /* INET */ #ifdef INET6 - case ETHERTYPE_IPV6: /* Ether + IPv6 */ - if (m->m_pkthdr.len <= sizeof(struct ether_header)) - break; - m_adj(m, sizeof(struct ether_header)); + case ETHERTYPE_IPV6: /* Ether + VLAN + IPv6 */ m = l2tp_tcpmss6_clamp(ifp, m); if (m == NULL) return NULL; - /* restore ether header */ - M_PREPEND(m, sizeof(struct ether_header), M_DONTWAIT); - if (m == NULL) - return NULL; - *mtod(m, struct ether_header *) = *eh; break; #endif /* INET6 */ default: break; } + + /* restore ether header */ + M_PREPEND(m, sizeof(struct ether_vlan_header), + M_DONTWAIT); + if (m == NULL) + return NULL; + *mtod(m, struct ether_vlan_header *) = evh; + break; + +#ifdef INET + case ETHERTYPE_IP: /* Ether + IPv4 */ + if (m->m_pkthdr.len <= sizeof(struct ether_header)) + break; + m_adj(m, sizeof(struct ether_header)); + m = l2tp_tcpmss4_clamp(ifp, m); + if (m == NULL) + return NULL; + /* restore ether header */ + M_PREPEND(m, sizeof(struct ether_header), M_DONTWAIT); + if (m == NULL) + return NULL; + *mtod(m, struct ether_header *) = *eh; + break; +#endif /* INET */ + +#ifdef INET6 + case ETHERTYPE_IPV6: /* Ether + IPv6 */ + if (m->m_pkthdr.len <= sizeof(struct ether_header)) + break; + m_adj(m, sizeof(struct ether_header)); + m = l2tp_tcpmss6_clamp(ifp, m); + if (m == NULL) + return NULL; + /* restore ether header */ + M_PREPEND(m, sizeof(struct ether_header), M_DONTWAIT); + if (m == NULL) + return NULL; + *mtod(m, struct ether_header *) = *eh; + break; +#endif /* INET6 */ + + default: + break; } return m; @@ -1439,12 +1470,12 @@ l2tp_need_tcpmss_clamp(struct ifnet *ifp #ifdef INET if (ifp->if_tcpmss != 0) ret = 1; -#endif /* INET */ +#endif #ifdef INET6 if (ifp->if_tcpmss6 != 0) ret = 1; -#endif /* INET6 */ +#endif return ret; } Index: src/sys/net/if_l2tp.h diff -u src/sys/net/if_l2tp.h:1.2 src/sys/net/if_l2tp.h:1.2.2.1 --- src/sys/net/if_l2tp.h:1.2 Wed May 31 08:19:44 2017 +++ src/sys/net/if_l2tp.h Thu Mar 8 13:41:40 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: if_l2tp.h,v 1.2 2017/05/31 08:19:44 knakahara Exp $ */ +/* $NetBSD: if_l2tp.h,v 1.2.2.1 2018/03/08 13:41:40 martin Exp $ */ /* * Copyright (c) 2017 Internet Initiative Japan Inc. @@ -162,7 +162,7 @@ l2tp_heldref_variant(struct l2tp_variant /* Prototypes */ void l2tpattach(int); -void l2tpattach0(struct l2tp_softc *); +int l2tpattach0(struct l2tp_softc *); void l2tp_input(struct mbuf *, struct ifnet *); int l2tp_ioctl(struct ifnet *, u_long, void *); Index: src/sys/netinet/in_l2tp.c diff -u src/sys/netinet/in_l2tp.c:1.2.8.3 src/sys/netinet/in_l2tp.c:1.2.8.4 --- src/sys/netinet/in_l2tp.c:1.2.8.3 Tue Jan 2 10:39:57 2018 +++ src/sys/netinet/in_l2tp.c Thu Mar 8 13:41:41 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: in_l2tp.c,v 1.2.8.3 2018/01/02 10:39:57 snj Exp $ */ +/* $NetBSD: in_l2tp.c,v 1.2.8.4 2018/03/08 13:41:41 martin Exp $ */ /* * Copyright (c) 2017 Internet Initiative Japan Inc. @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.2.8.3 2018/01/02 10:39:57 snj Exp $"); +__KERNEL_RCSID(0, "$NetBSD: in_l2tp.c,v 1.2.8.4 2018/03/08 13:41:41 martin Exp $"); #ifdef _KERNEL_OPT #include "opt_l2tp.h" @@ -103,9 +103,6 @@ in_l2tp_output(struct l2tp_variant *var, && sin_dst->sin_family == AF_INET); sc = var->lv_softc; - if (sc == NULL) - return ENETUNREACH; - ifp = &sc->l2tp_ec.ec_if; error = l2tp_check_nesting(ifp, m); if (error) { @@ -113,7 +110,16 @@ in_l2tp_output(struct l2tp_variant *var, goto looped; } -#ifdef NETYET + /* bidirectional configured tunnel mode */ + if (sin_dst->sin_addr.s_addr == INADDR_ANY) { + m_freem(m); + if ((ifp->if_flags & IFF_DEBUG) != 0) + log(LOG_DEBUG, "%s: ENETUNREACH\n", __func__); + error = ENETUNREACH; + goto out; + } + +#ifdef NOTYET /* TODO: support ALTQ for innner frame */ #ifdef ALTQ ALTQ_SAVE_PAYLOAD(m, AF_ETHER); @@ -122,16 +128,7 @@ in_l2tp_output(struct l2tp_variant *var, memset(&iphdr, 0, sizeof(iphdr)); iphdr.ip_src = sin_src->sin_addr; - /* bidirectional configured tunnel mode */ - if (sin_dst->sin_addr.s_addr != INADDR_ANY) - iphdr.ip_dst = sin_dst->sin_addr; - else { - m_freem(m); - if ((ifp->if_flags & IFF_DEBUG) != 0) - log(LOG_DEBUG, "%s: ENETUNREACH\n", __func__); - error = ENETUNREACH; - goto out; - } + iphdr.ip_dst = sin_dst->sin_addr; iphdr.ip_p = IPPROTO_L2TP; /* version will be set in ip_output() */ iphdr.ip_ttl = ip_l2tp_ttl; @@ -152,11 +149,12 @@ in_l2tp_output(struct l2tp_variant *var, goto out; } #endif + /* - * payload length - * NOTE: Payload length may be changed in ip_tcpmss(). - * Typical case is missing of TCP mss option in original - * TCP header. + * Payload length. + * + * NOTE: payload length may be changed in ip_tcpmss(). Typical case + * is missing of TCP mss option in original TCP header. */ iphdr.ip_len += m->m_pkthdr.len; HTONS(iphdr.ip_len); @@ -174,12 +172,10 @@ in_l2tp_output(struct l2tp_variant *var, } if (var->lv_peer_cookie_len == 4) { cookie_32 = htonl((uint32_t)var->lv_peer_cookie); - memcpy(mtod(m, void *), &cookie_32, - sizeof(uint32_t)); + memcpy(mtod(m, void *), &cookie_32, sizeof(uint32_t)); } else { cookie_64 = htobe64(var->lv_peer_cookie); - memcpy(mtod(m, void *), &cookie_64, - sizeof(uint64_t)); + memcpy(mtod(m, void *), &cookie_64, sizeof(uint64_t)); } } @@ -196,11 +192,14 @@ in_l2tp_output(struct l2tp_variant *var, /* prepend new IP header */ M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); + if (m == NULL) { + error = ENOBUFS; + goto out; + } if (IP_HDR_ALIGNED_P(mtod(m, void *)) == 0) { - if (m) - m = m_copyup(m, sizeof(struct ip), 0); + m = m_copyup(m, sizeof(struct ip), 0); } else { - if (m && m->m_len < sizeof(struct ip)) + if (m->m_len < sizeof(struct ip)) m = m_pullup(m, sizeof(struct ip)); } if (m == NULL) { @@ -260,13 +259,12 @@ in_l2tp_input(struct mbuf *m, int off, i struct psref psref; struct l2tp_variant *var; - if (m->m_len < off + sizeof(uint32_t)) { - m = m_pullup(m, off + sizeof(uint32_t)); - if (!m) { - /* if payload length < 4 octets */ - return; - } - } + KASSERT((m->m_flags & M_PKTHDR) != 0); + + if (m->m_pkthdr.len < off + sizeof(uint32_t)) { + m_freem(m); + return; + } /* get L2TP session ID */ m_copydata(m, off, sizeof(uint32_t), (void *)&sess_id); @@ -288,28 +286,28 @@ in_l2tp_input(struct mbuf *m, int off, i m_freem(m); ip_statinc(IP_STAT_NOL2TP); return; - } else { - sc = var->lv_softc; - l2tpp = &(sc->l2tp_ec.ec_if); + } + + sc = var->lv_softc; + l2tpp = &(sc->l2tp_ec.ec_if); - if (l2tpp == NULL || (l2tpp->if_flags & IFF_UP) == 0) { + if (l2tpp == NULL || (l2tpp->if_flags & IFF_UP) == 0) { #ifdef L2TP_DEBUG - if (l2tpp == NULL) - log(LOG_DEBUG, "%s: l2tpp is NULL\n", __func__); - else - log(LOG_DEBUG, "%s: l2tpp is down\n", __func__); + if (l2tpp == NULL) + log(LOG_DEBUG, "%s: l2tpp is NULL\n", __func__); + else + log(LOG_DEBUG, "%s: l2tpp is down\n", __func__); #endif - m_freem(m); - ip_statinc(IP_STAT_NOL2TP); - goto out; - } + m_freem(m); + ip_statinc(IP_STAT_NOL2TP); + goto out; + } - /* other CPU do l2tp_delete_tunnel */ - if (var->lv_psrc == NULL || var->lv_pdst == NULL) { - m_freem(m); - ip_statinc(IP_STAT_NOL2TP); - goto out; - } + /* other CPU did l2tp_delete_tunnel */ + if (var->lv_psrc == NULL || var->lv_pdst == NULL) { + m_freem(m); + ip_statinc(IP_STAT_NOL2TP); + goto out; } if (var->lv_state != L2TP_STATE_UP) { @@ -320,6 +318,10 @@ in_l2tp_input(struct mbuf *m, int off, i m_adj(m, off + sizeof(uint32_t)); if (var->lv_use_cookie == L2TP_COOKIE_ON) { + if (m->m_pkthdr.len < var->lv_my_cookie_len) { + m_freem(m); + goto out; + } if (var->lv_my_cookie_len == 4) { m_copydata(m, 0, sizeof(uint32_t), (void *)&cookie_32); NTOHL(cookie_32); Index: src/sys/netinet6/in6_l2tp.c diff -u src/sys/netinet6/in6_l2tp.c:1.5.8.3 src/sys/netinet6/in6_l2tp.c:1.5.8.4 --- src/sys/netinet6/in6_l2tp.c:1.5.8.3 Tue Jan 2 10:39:57 2018 +++ src/sys/netinet6/in6_l2tp.c Thu Mar 8 13:41:41 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: in6_l2tp.c,v 1.5.8.3 2018/01/02 10:39:57 snj Exp $ */ +/* $NetBSD: in6_l2tp.c,v 1.5.8.4 2018/03/08 13:41:41 martin Exp $ */ /* * Copyright (c) 2017 Internet Initiative Japan Inc. @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: in6_l2tp.c,v 1.5.8.3 2018/01/02 10:39:57 snj Exp $"); +__KERNEL_RCSID(0, "$NetBSD: in6_l2tp.c,v 1.5.8.4 2018/03/08 13:41:41 martin Exp $"); #ifdef _KERNEL_OPT #include "opt_l2tp.h" @@ -113,6 +113,14 @@ in6_l2tp_output(struct l2tp_variant *var goto looped; } + /* bidirectional configured tunnel mode */ + if (IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr)) { + m_freem(m); + if ((ifp->if_flags & IFF_DEBUG) != 0) + log(LOG_DEBUG, "%s: ENETUNREACH\n", __func__); + return ENETUNREACH; + } + #ifdef NOTYET /* TODO: support ALTQ for innner frame */ #ifdef ALTQ @@ -122,18 +130,10 @@ in6_l2tp_output(struct l2tp_variant *var memset(&ip6hdr, 0, sizeof(ip6hdr)); ip6hdr.ip6_src = sin6_src->sin6_addr; - /* bidirectional configured tunnel mode */ - if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr)) - ip6hdr.ip6_dst = sin6_dst->sin6_addr; - else { - m_freem(m); - if ((ifp->if_flags & IFF_DEBUG) != 0) - log(LOG_DEBUG, "%s: ENETUNREACH\n", __func__); - return ENETUNREACH; - } + ip6hdr.ip6_dst = sin6_dst->sin6_addr; /* unlike IPv4, IP version must be filled by caller of ip6_output() */ - ip6hdr.ip6_vfc = 0x60; - ip6hdr.ip6_nxt = IPPROTO_L2TP; + ip6hdr.ip6_vfc = 0x60; + ip6hdr.ip6_nxt = IPPROTO_L2TP; ip6hdr.ip6_hlim = ip6_l2tp_hlim; /* outer IP payload length */ ip6hdr.ip6_plen = 0; @@ -152,10 +152,10 @@ in6_l2tp_output(struct l2tp_variant *var #endif /* - * payload length - * NOTE: Payload length may be changed in ip_tcpmss(). - * Typical case is missing of TCP mss option in original - * TCP header. + * Payload length. + * + * NOTE: payload length may be changed in ip_tcpmss(). Typical case + * is missing of TCP mss option in original TCP header. */ ip6hdr.ip6_plen += m->m_pkthdr.len; HTONS(ip6hdr.ip6_plen); @@ -171,12 +171,10 @@ in6_l2tp_output(struct l2tp_variant *var return ENOBUFS; if (var->lv_peer_cookie_len == 4) { cookie_32 = htonl((uint32_t)var->lv_peer_cookie); - memcpy(mtod(m, void *), &cookie_32, - sizeof(uint32_t)); + memcpy(mtod(m, void *), &cookie_32, sizeof(uint32_t)); } else { cookie_64 = htobe64(var->lv_peer_cookie); - memcpy(mtod(m, void *), &cookie_64, - sizeof(uint64_t)); + memcpy(mtod(m, void *), &cookie_64, sizeof(uint64_t)); } } @@ -191,11 +189,12 @@ in6_l2tp_output(struct l2tp_variant *var /* prepend new IP header */ M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT); + if (m == NULL) + return ENOBUFS; if (IP_HDR_ALIGNED_P(mtod(m, void *)) == 0) { - if (m) - m = m_copyup(m, sizeof(struct ip), 0); + m = m_copyup(m, sizeof(struct ip), 0); } else { - if (m && m->m_len < sizeof(struct ip6_hdr)) + if (m->m_len < sizeof(struct ip6_hdr)) m = m_pullup(m, sizeof(struct ip6_hdr)); } if (m == NULL) @@ -254,14 +253,12 @@ in6_l2tp_input(struct mbuf **mp, int *of uint64_t cookie_64; struct psref psref; - if (m->m_len < off + sizeof(uint32_t)) { - m = m_pullup(m, off + sizeof(uint32_t)); - if (!m) { - /* if payload length < 4 octets */ - return IPPROTO_DONE; - } - *mp = m; - } + KASSERT((m->m_flags & M_PKTHDR) != 0); + + if (m->m_pkthdr.len < off + sizeof(uint32_t)) { + m_freem(m); + return IPPROTO_DONE; + } /* get L2TP session ID */ m_copydata(m, off, sizeof(uint32_t), (void *)&sess_id); @@ -282,27 +279,28 @@ in6_l2tp_input(struct mbuf **mp, int *of m_freem(m); IP_STATINC(IP_STAT_NOL2TP); return IPPROTO_DONE; - } else { - sc = var->lv_softc; - l2tpp = &(sc->l2tp_ec.ec_if); + } - if (l2tpp == NULL || (l2tpp->if_flags & IFF_UP) == 0) { + sc = var->lv_softc; + l2tpp = &(sc->l2tp_ec.ec_if); + + if (l2tpp == NULL || (l2tpp->if_flags & IFF_UP) == 0) { #ifdef L2TP_DEBUG - if (l2tpp == NULL) - log(LOG_DEBUG, "%s: l2tpp is NULL\n", __func__); - else - log(LOG_DEBUG, "%s: l2tpp is down\n", __func__); + if (l2tpp == NULL) + log(LOG_DEBUG, "%s: l2tpp is NULL\n", __func__); + else + log(LOG_DEBUG, "%s: l2tpp is down\n", __func__); #endif - m_freem(m); - IP_STATINC(IP_STAT_NOL2TP); - goto out; - } - /* other CPU do l2tp_delete_tunnel */ - if (var->lv_psrc == NULL || var->lv_pdst == NULL) { - m_freem(m); - ip_statinc(IP_STAT_NOL2TP); - goto out; - } + m_freem(m); + IP_STATINC(IP_STAT_NOL2TP); + goto out; + } + + /* other CPU did l2tp_delete_tunnel */ + if (var->lv_psrc == NULL || var->lv_pdst == NULL) { + m_freem(m); + ip_statinc(IP_STAT_NOL2TP); + goto out; } if (var->lv_state != L2TP_STATE_UP) { @@ -312,6 +310,10 @@ in6_l2tp_input(struct mbuf **mp, int *of m_adj(m, off + sizeof(uint32_t)); if (var->lv_use_cookie == L2TP_COOKIE_ON) { + if (m->m_pkthdr.len < var->lv_my_cookie_len) { + m_freem(m); + goto out; + } if (var->lv_my_cookie_len == 4) { m_copydata(m, 0, sizeof(uint32_t), (void *)&cookie_32); NTOHL(cookie_32);