From owner-svn-src-all@freebsd.org Mon Jul 9 11:03:30 2018 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 179EC103EE9F; Mon, 9 Jul 2018 11:03:30 +0000 (UTC) (envelope-from ae@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id BD29D91527; Mon, 9 Jul 2018 11:03:29 +0000 (UTC) (envelope-from ae@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 9E0EE142FF; Mon, 9 Jul 2018 11:03:29 +0000 (UTC) (envelope-from ae@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id w69B3T3k048528; Mon, 9 Jul 2018 11:03:29 GMT (envelope-from ae@FreeBSD.org) Received: (from ae@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id w69B3Ste048521; Mon, 9 Jul 2018 11:03:28 GMT (envelope-from ae@FreeBSD.org) Message-Id: <201807091103.w69B3Ste048521@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: ae set sender to ae@FreeBSD.org using -f From: "Andrey V. Elsukov" Date: Mon, 9 Jul 2018 11:03:28 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r336131 - head/sys/net X-SVN-Group: head X-SVN-Commit-Author: ae X-SVN-Commit-Paths: head/sys/net X-SVN-Commit-Revision: 336131 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.27 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 09 Jul 2018 11:03:30 -0000 Author: ae Date: Mon Jul 9 11:03:28 2018 New Revision: 336131 URL: https://svnweb.freebsd.org/changeset/base/336131 Log: Deduplicate the code. Add generic function if_tunnel_check_nesting() that does check for allowed nesting level for tunneling interfaces and also does loop detection. Use it in gif(4), gre(4) and me(4) interfaces. Differential Revision: https://reviews.freebsd.org/D16162 Modified: head/sys/net/if.c head/sys/net/if_gif.c head/sys/net/if_gre.c head/sys/net/if_me.c head/sys/net/if_var.h Modified: head/sys/net/if.c ============================================================================== --- head/sys/net/if.c Mon Jul 9 09:00:16 2018 (r336130) +++ head/sys/net/if.c Mon Jul 9 11:03:28 2018 (r336131) @@ -3903,6 +3903,44 @@ if_requestencap_default(struct ifnet *ifp, struct if_e } /* + * Tunnel interfaces can nest, also they may cause infinite recursion + * calls when misconfigured. We'll prevent this by detecting loops. + * High nesting level may cause stack exhaustion. We'll prevent this + * by introducing upper limit. + * + * Return 0, if tunnel nesting count is equal or less than limit. + */ +int +if_tunnel_check_nesting(struct ifnet *ifp, struct mbuf *m, uint32_t cookie, + int limit) +{ + struct m_tag *mtag; + int count; + + count = 1; + mtag = NULL; + while ((mtag = m_tag_locate(m, cookie, 0, mtag)) != NULL) { + if (*(struct ifnet **)(mtag + 1) == ifp) { + log(LOG_NOTICE, "%s: loop detected\n", if_name(ifp)); + return (EIO); + } + count++; + } + if (count > limit) { + log(LOG_NOTICE, + "%s: if_output recursively called too many times(%d)\n", + if_name(ifp), count); + return (EIO); + } + mtag = m_tag_alloc(cookie, 0, sizeof(struct ifnet *), M_NOWAIT); + if (mtag == NULL) + return (ENOMEM); + *(struct ifnet **)(mtag + 1) = ifp; + m_tag_prepend(m, mtag); + return (0); +} + +/* * Get the link layer address that was read from the hardware at attach. * * This is only set by Ethernet NICs (IFT_ETHER), but laggX interfaces re-type Modified: head/sys/net/if_gif.c ============================================================================== --- head/sys/net/if_gif.c Mon Jul 9 09:00:16 2018 (r336130) +++ head/sys/net/if_gif.c Mon Jul 9 11:03:28 2018 (r336131) @@ -104,7 +104,6 @@ void (*ng_gif_input_orphan_p)(struct ifnet *ifp, struc void (*ng_gif_attach_p)(struct ifnet *ifp); void (*ng_gif_detach_p)(struct ifnet *ifp); -static int gif_check_nesting(struct ifnet *, struct mbuf *); static void gif_delete_tunnel(struct gif_softc *); static int gif_ioctl(struct ifnet *, u_long, caddr_t); static int gif_transmit(struct ifnet *, struct mbuf *); @@ -256,6 +255,7 @@ gif_hashdestroy(struct gif_list *hash) free(hash, M_GIF); } +#define MTAG_GIF 1080679712 static int gif_transmit(struct ifnet *ifp, struct mbuf *m) { @@ -285,7 +285,8 @@ gif_transmit(struct ifnet *ifp, struct mbuf *m) if ((ifp->if_flags & IFF_MONITOR) != 0 || (ifp->if_flags & IFF_UP) == 0 || sc->gif_family == 0 || - (error = gif_check_nesting(ifp, m)) != 0) { + (error = if_tunnel_check_nesting(ifp, m, MTAG_GIF, + V_max_gif_nesting)) != 0) { m_freem(m); goto err; } @@ -378,42 +379,6 @@ gif_qflush(struct ifnet *ifp __unused) } -#define MTAG_GIF 1080679712 -static int -gif_check_nesting(struct ifnet *ifp, struct mbuf *m) -{ - struct m_tag *mtag; - int count; - - /* - * gif may cause infinite recursion calls when misconfigured. - * We'll prevent this by detecting loops. - * - * High nesting level may cause stack exhaustion. - * We'll prevent this by introducing upper limit. - */ - count = 1; - mtag = NULL; - while ((mtag = m_tag_locate(m, MTAG_GIF, 0, mtag)) != NULL) { - if (*(struct ifnet **)(mtag + 1) == ifp) { - log(LOG_NOTICE, "%s: loop detected\n", if_name(ifp)); - return (EIO); - } - count++; - } - if (count > V_max_gif_nesting) { - log(LOG_NOTICE, - "%s: if_output recursively called too many times(%d)\n", - if_name(ifp), count); - return (EIO); - } - mtag = m_tag_alloc(MTAG_GIF, 0, sizeof(struct ifnet *), M_NOWAIT); - if (mtag == NULL) - return (ENOMEM); - *(struct ifnet **)(mtag + 1) = ifp; - m_tag_prepend(m, mtag); - return (0); -} int gif_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, Modified: head/sys/net/if_gre.c ============================================================================== --- head/sys/net/if_gre.c Mon Jul 9 09:00:16 2018 (r336130) +++ head/sys/net/if_gre.c Mon Jul 9 11:03:28 2018 (r336131) @@ -503,37 +503,7 @@ drop: return (IPPROTO_DONE); } -#define MTAG_GRE 1307983903 static int -gre_check_nesting(struct ifnet *ifp, struct mbuf *m) -{ - struct m_tag *mtag; - int count; - - count = 1; - mtag = NULL; - while ((mtag = m_tag_locate(m, MTAG_GRE, 0, mtag)) != NULL) { - if (*(struct ifnet **)(mtag + 1) == ifp) { - log(LOG_NOTICE, "%s: loop detected\n", ifp->if_xname); - return (EIO); - } - count++; - } - if (count > V_max_gre_nesting) { - log(LOG_NOTICE, - "%s: if_output recursively called too many times(%d)\n", - ifp->if_xname, count); - return (EIO); - } - mtag = m_tag_alloc(MTAG_GRE, 0, sizeof(struct ifnet *), M_NOWAIT); - if (mtag == NULL) - return (ENOMEM); - *(struct ifnet **)(mtag + 1) = ifp; - m_tag_prepend(m, mtag); - return (0); -} - -static int gre_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, struct route *ro) { @@ -569,6 +539,7 @@ gre_setseqn(struct grehdr *gh, uint32_t seq) *opts = htonl(seq); } +#define MTAG_GRE 1307983903 static int gre_transmit(struct ifnet *ifp, struct mbuf *m) { @@ -592,7 +563,8 @@ gre_transmit(struct ifnet *ifp, struct mbuf *m) if ((ifp->if_flags & IFF_MONITOR) != 0 || (ifp->if_flags & IFF_UP) == 0 || sc->gre_family == 0 || - (error = gre_check_nesting(ifp, m)) != 0) { + (error = if_tunnel_check_nesting(ifp, m, MTAG_GRE, + V_max_gre_nesting)) != 0) { m_freem(m); goto drop; } Modified: head/sys/net/if_me.c ============================================================================== --- head/sys/net/if_me.c Mon Jul 9 09:00:16 2018 (r336130) +++ head/sys/net/if_me.c Mon Jul 9 11:03:28 2018 (r336131) @@ -455,37 +455,7 @@ drop: return (IPPROTO_DONE); } -#define MTAG_ME 1414491977 static int -me_check_nesting(struct ifnet *ifp, struct mbuf *m) -{ - struct m_tag *mtag; - int count; - - count = 1; - mtag = NULL; - while ((mtag = m_tag_locate(m, MTAG_ME, 0, mtag)) != NULL) { - if (*(struct ifnet **)(mtag + 1) == ifp) { - log(LOG_NOTICE, "%s: loop detected\n", ifp->if_xname); - return (EIO); - } - count++; - } - if (count > V_max_me_nesting) { - log(LOG_NOTICE, - "%s: if_output recursively called too many times(%d)\n", - ifp->if_xname, count); - return (EIO); - } - mtag = m_tag_alloc(MTAG_ME, 0, sizeof(struct ifnet *), M_NOWAIT); - if (mtag == NULL) - return (ENOMEM); - *(struct ifnet **)(mtag + 1) = ifp; - m_tag_prepend(m, mtag); - return (0); -} - -static int me_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, struct route *ro __unused) { @@ -499,6 +469,7 @@ me_output(struct ifnet *ifp, struct mbuf *m, const str return (ifp->if_transmit(ifp, m)); } +#define MTAG_ME 1414491977 static int me_transmit(struct ifnet *ifp, struct mbuf *m) { @@ -519,7 +490,8 @@ me_transmit(struct ifnet *ifp, struct mbuf *m) if (sc == NULL || !ME_READY(sc) || (ifp->if_flags & IFF_MONITOR) != 0 || (ifp->if_flags & IFF_UP) == 0 || - (error = me_check_nesting(ifp, m) != 0)) { + (error = if_tunnel_check_nesting(ifp, m, MTAG_ME, + V_max_me_nesting)) != 0) { m_freem(m); goto drop; } Modified: head/sys/net/if_var.h ============================================================================== --- head/sys/net/if_var.h Mon Jul 9 09:00:16 2018 (r336130) +++ head/sys/net/if_var.h Mon Jul 9 11:03:28 2018 (r336131) @@ -644,6 +644,7 @@ int if_printf(struct ifnet *, const char *, ...) __pri void if_ref(struct ifnet *); void if_rele(struct ifnet *); int if_setlladdr(struct ifnet *, const u_char *, int); +int if_tunnel_check_nesting(struct ifnet *, struct mbuf *, uint32_t, int); void if_up(struct ifnet *); int ifioctl(struct socket *, u_long, caddr_t, struct thread *); int ifpromisc(struct ifnet *, int);