mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-14 14:55:41 +00:00
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
This commit is contained in:
parent
d50fbe3fe2
commit
98a8fdf6da
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=336131
38
sys/net/if.c
38
sys/net/if.c
@ -3902,6 +3902,44 @@ if_requestencap_default(struct ifnet *ifp, struct if_encap_req *req)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
* Get the link layer address that was read from the hardware at attach.
|
||||||
*
|
*
|
||||||
|
@ -104,7 +104,6 @@ void (*ng_gif_input_orphan_p)(struct ifnet *ifp, struct mbuf *m, int af);
|
|||||||
void (*ng_gif_attach_p)(struct ifnet *ifp);
|
void (*ng_gif_attach_p)(struct ifnet *ifp);
|
||||||
void (*ng_gif_detach_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 void gif_delete_tunnel(struct gif_softc *);
|
||||||
static int gif_ioctl(struct ifnet *, u_long, caddr_t);
|
static int gif_ioctl(struct ifnet *, u_long, caddr_t);
|
||||||
static int gif_transmit(struct ifnet *, struct mbuf *);
|
static int gif_transmit(struct ifnet *, struct mbuf *);
|
||||||
@ -256,6 +255,7 @@ gif_hashdestroy(struct gif_list *hash)
|
|||||||
free(hash, M_GIF);
|
free(hash, M_GIF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MTAG_GIF 1080679712
|
||||||
static int
|
static int
|
||||||
gif_transmit(struct ifnet *ifp, struct mbuf *m)
|
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 ||
|
if ((ifp->if_flags & IFF_MONITOR) != 0 ||
|
||||||
(ifp->if_flags & IFF_UP) == 0 ||
|
(ifp->if_flags & IFF_UP) == 0 ||
|
||||||
sc->gif_family == 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);
|
m_freem(m);
|
||||||
goto err;
|
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
|
int
|
||||||
gif_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
|
gif_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
|
||||||
|
@ -503,36 +503,6 @@ gre_input(struct mbuf *m, int off, int proto, void *arg)
|
|||||||
return (IPPROTO_DONE);
|
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
|
static int
|
||||||
gre_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
|
gre_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
|
||||||
struct route *ro)
|
struct route *ro)
|
||||||
@ -569,6 +539,7 @@ gre_setseqn(struct grehdr *gh, uint32_t seq)
|
|||||||
*opts = htonl(seq);
|
*opts = htonl(seq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MTAG_GRE 1307983903
|
||||||
static int
|
static int
|
||||||
gre_transmit(struct ifnet *ifp, struct mbuf *m)
|
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 ||
|
if ((ifp->if_flags & IFF_MONITOR) != 0 ||
|
||||||
(ifp->if_flags & IFF_UP) == 0 ||
|
(ifp->if_flags & IFF_UP) == 0 ||
|
||||||
sc->gre_family == 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);
|
m_freem(m);
|
||||||
goto drop;
|
goto drop;
|
||||||
}
|
}
|
||||||
|
@ -455,36 +455,6 @@ me_input(struct mbuf *m, int off, int proto, void *arg)
|
|||||||
return (IPPROTO_DONE);
|
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
|
static int
|
||||||
me_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
|
me_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
|
||||||
struct route *ro __unused)
|
struct route *ro __unused)
|
||||||
@ -499,6 +469,7 @@ me_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
|
|||||||
return (ifp->if_transmit(ifp, m));
|
return (ifp->if_transmit(ifp, m));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MTAG_ME 1414491977
|
||||||
static int
|
static int
|
||||||
me_transmit(struct ifnet *ifp, struct mbuf *m)
|
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) ||
|
if (sc == NULL || !ME_READY(sc) ||
|
||||||
(ifp->if_flags & IFF_MONITOR) != 0 ||
|
(ifp->if_flags & IFF_MONITOR) != 0 ||
|
||||||
(ifp->if_flags & IFF_UP) == 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);
|
m_freem(m);
|
||||||
goto drop;
|
goto drop;
|
||||||
}
|
}
|
||||||
|
@ -644,6 +644,7 @@ int if_printf(struct ifnet *, const char *, ...) __printflike(2, 3);
|
|||||||
void if_ref(struct ifnet *);
|
void if_ref(struct ifnet *);
|
||||||
void if_rele(struct ifnet *);
|
void if_rele(struct ifnet *);
|
||||||
int if_setlladdr(struct ifnet *, const u_char *, int);
|
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 *);
|
void if_up(struct ifnet *);
|
||||||
int ifioctl(struct socket *, u_long, caddr_t, struct thread *);
|
int ifioctl(struct socket *, u_long, caddr_t, struct thread *);
|
||||||
int ifpromisc(struct ifnet *, int);
|
int ifpromisc(struct ifnet *, int);
|
||||||
|
Loading…
Reference in New Issue
Block a user