Commit 3d406a18 authored by Eric Dumazet's avatar Eric Dumazet Committed by Greg Kroah-Hartman

ipv4: igmp: guard against silly MTU values


[ Upstream commit b5476022 ]

IPv4 stack reacts to changes to small MTU, by disabling itself under
RTNL.

But there is a window where threads not using RTNL can see a wrong
device mtu. This can lead to surprises, in igmp code where it is
assumed the mtu is suitable.

Fix this by reading device mtu once and checking IPv4 minimal MTU.

This patch adds missing IPV4_MIN_MTU define, to not abuse
ETH_MIN_MTU anymore.
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 1cd09d4b
...@@ -33,6 +33,8 @@ ...@@ -33,6 +33,8 @@
#include <net/flow.h> #include <net/flow.h>
#include <net/flow_dissector.h> #include <net/flow_dissector.h>
#define IPV4_MIN_MTU 68 /* RFC 791 */
struct sock; struct sock;
struct inet_skb_parm { struct inet_skb_parm {
......
...@@ -1358,7 +1358,7 @@ static void inetdev_changename(struct net_device *dev, struct in_device *in_dev) ...@@ -1358,7 +1358,7 @@ static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
static bool inetdev_valid_mtu(unsigned int mtu) static bool inetdev_valid_mtu(unsigned int mtu)
{ {
return mtu >= 68; return mtu >= IPV4_MIN_MTU;
} }
static void inetdev_send_gratuitous_arp(struct net_device *dev, static void inetdev_send_gratuitous_arp(struct net_device *dev,
......
...@@ -410,16 +410,17 @@ static int grec_size(struct ip_mc_list *pmc, int type, int gdel, int sdel) ...@@ -410,16 +410,17 @@ static int grec_size(struct ip_mc_list *pmc, int type, int gdel, int sdel)
} }
static struct sk_buff *add_grhead(struct sk_buff *skb, struct ip_mc_list *pmc, static struct sk_buff *add_grhead(struct sk_buff *skb, struct ip_mc_list *pmc,
int type, struct igmpv3_grec **ppgr) int type, struct igmpv3_grec **ppgr, unsigned int mtu)
{ {
struct net_device *dev = pmc->interface->dev; struct net_device *dev = pmc->interface->dev;
struct igmpv3_report *pih; struct igmpv3_report *pih;
struct igmpv3_grec *pgr; struct igmpv3_grec *pgr;
if (!skb) if (!skb) {
skb = igmpv3_newpack(dev, dev->mtu); skb = igmpv3_newpack(dev, mtu);
if (!skb) if (!skb)
return NULL; return NULL;
}
pgr = (struct igmpv3_grec *)skb_put(skb, sizeof(struct igmpv3_grec)); pgr = (struct igmpv3_grec *)skb_put(skb, sizeof(struct igmpv3_grec));
pgr->grec_type = type; pgr->grec_type = type;
pgr->grec_auxwords = 0; pgr->grec_auxwords = 0;
...@@ -441,12 +442,17 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc, ...@@ -441,12 +442,17 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc,
struct igmpv3_grec *pgr = NULL; struct igmpv3_grec *pgr = NULL;
struct ip_sf_list *psf, *psf_next, *psf_prev, **psf_list; struct ip_sf_list *psf, *psf_next, *psf_prev, **psf_list;
int scount, stotal, first, isquery, truncate; int scount, stotal, first, isquery, truncate;
unsigned int mtu;
if (pmc->multiaddr == IGMP_ALL_HOSTS) if (pmc->multiaddr == IGMP_ALL_HOSTS)
return skb; return skb;
if (ipv4_is_local_multicast(pmc->multiaddr) && !sysctl_igmp_llm_reports) if (ipv4_is_local_multicast(pmc->multiaddr) && !sysctl_igmp_llm_reports)
return skb; return skb;
mtu = READ_ONCE(dev->mtu);
if (mtu < IPV4_MIN_MTU)
return skb;
isquery = type == IGMPV3_MODE_IS_INCLUDE || isquery = type == IGMPV3_MODE_IS_INCLUDE ||
type == IGMPV3_MODE_IS_EXCLUDE; type == IGMPV3_MODE_IS_EXCLUDE;
truncate = type == IGMPV3_MODE_IS_EXCLUDE || truncate = type == IGMPV3_MODE_IS_EXCLUDE ||
...@@ -467,7 +473,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc, ...@@ -467,7 +473,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc,
AVAILABLE(skb) < grec_size(pmc, type, gdeleted, sdeleted)) { AVAILABLE(skb) < grec_size(pmc, type, gdeleted, sdeleted)) {
if (skb) if (skb)
igmpv3_sendpack(skb); igmpv3_sendpack(skb);
skb = igmpv3_newpack(dev, dev->mtu); skb = igmpv3_newpack(dev, mtu);
} }
} }
first = 1; first = 1;
...@@ -494,12 +500,12 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc, ...@@ -494,12 +500,12 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc,
pgr->grec_nsrcs = htons(scount); pgr->grec_nsrcs = htons(scount);
if (skb) if (skb)
igmpv3_sendpack(skb); igmpv3_sendpack(skb);
skb = igmpv3_newpack(dev, dev->mtu); skb = igmpv3_newpack(dev, mtu);
first = 1; first = 1;
scount = 0; scount = 0;
} }
if (first) { if (first) {
skb = add_grhead(skb, pmc, type, &pgr); skb = add_grhead(skb, pmc, type, &pgr, mtu);
first = 0; first = 0;
} }
if (!skb) if (!skb)
...@@ -533,7 +539,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc, ...@@ -533,7 +539,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc,
igmpv3_sendpack(skb); igmpv3_sendpack(skb);
skb = NULL; /* add_grhead will get a new one */ skb = NULL; /* add_grhead will get a new one */
} }
skb = add_grhead(skb, pmc, type, &pgr); skb = add_grhead(skb, pmc, type, &pgr, mtu);
} }
} }
if (pgr) if (pgr)
......
...@@ -400,8 +400,8 @@ static int ip_tunnel_bind_dev(struct net_device *dev) ...@@ -400,8 +400,8 @@ static int ip_tunnel_bind_dev(struct net_device *dev)
dev->needed_headroom = t_hlen + hlen; dev->needed_headroom = t_hlen + hlen;
mtu -= (dev->hard_header_len + t_hlen); mtu -= (dev->hard_header_len + t_hlen);
if (mtu < 68) if (mtu < IPV4_MIN_MTU)
mtu = 68; mtu = IPV4_MIN_MTU;
return mtu; return mtu;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment