| From 217e6fa24ce28ec87fca8da93c9016cb78028612 Mon Sep 17 00:00:00 2001 |
| From: Willem de Bruijn <willemb@google.com> |
| Date: Tue, 7 Feb 2017 15:57:20 -0500 |
| Subject: [PATCH] net: introduce device min_header_len |
| |
| commit 217e6fa24ce28ec87fca8da93c9016cb78028612 upstream. |
| |
| The stack must not pass packets to device drivers that are shorter |
| than the minimum link layer header length. |
| |
| Previously, packet sockets would drop packets smaller than or equal |
| to dev->hard_header_len, but this has false positives. Zero length |
| payload is used over Ethernet. Other link layer protocols support |
| variable length headers. Support for validation of these protocols |
| removed the min length check for all protocols. |
| |
| Introduce an explicit dev->min_header_len parameter and drop all |
| packets below this value. Initially, set it to non-zero only for |
| Ethernet and loopback. Other protocols can follow in a patch to |
| net-next. |
| |
| Fixes: 9ed988cd5915 ("packet: validate variable length ll headers") |
| Reported-by: Sowmini Varadhan <sowmini.varadhan@oracle.com> |
| Signed-off-by: Willem de Bruijn <willemb@google.com> |
| Acked-by: Eric Dumazet <edumazet@google.com> |
| Acked-by: Sowmini Varadhan <sowmini.varadhan@oracle.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| |
| diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c |
| index 1e05b7c2d157..0844f8496413 100644 |
| --- a/drivers/net/loopback.c |
| +++ b/drivers/net/loopback.c |
| @@ -164,6 +164,7 @@ static void loopback_setup(struct net_device *dev) |
| { |
| dev->mtu = 64 * 1024; |
| dev->hard_header_len = ETH_HLEN; /* 14 */ |
| + dev->min_header_len = ETH_HLEN; /* 14 */ |
| dev->addr_len = ETH_ALEN; /* 6 */ |
| dev->type = ARPHRD_LOOPBACK; /* 0x0001*/ |
| dev->flags = IFF_LOOPBACK; |
| diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h |
| index 70ad0291d517..27914672602d 100644 |
| --- a/include/linux/netdevice.h |
| +++ b/include/linux/netdevice.h |
| @@ -1511,6 +1511,7 @@ enum netdev_priv_flags { |
| * @max_mtu: Interface Maximum MTU value |
| * @type: Interface hardware type |
| * @hard_header_len: Maximum hardware header length. |
| + * @min_header_len: Minimum hardware header length |
| * |
| * @needed_headroom: Extra headroom the hardware may need, but not in all |
| * cases can this be guaranteed |
| @@ -1728,6 +1729,7 @@ struct net_device { |
| unsigned int max_mtu; |
| unsigned short type; |
| unsigned short hard_header_len; |
| + unsigned short min_header_len; |
| |
| unsigned short needed_headroom; |
| unsigned short needed_tailroom; |
| @@ -2694,6 +2696,8 @@ static inline bool dev_validate_header(const struct net_device *dev, |
| { |
| if (likely(len >= dev->hard_header_len)) |
| return true; |
| + if (len < dev->min_header_len) |
| + return false; |
| |
| if (capable(CAP_SYS_RAWIO)) { |
| memset(ll_header + len, 0, dev->hard_header_len - len); |
| diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c |
| index 8c5a479681ca..516c87e75de7 100644 |
| --- a/net/ethernet/eth.c |
| +++ b/net/ethernet/eth.c |
| @@ -356,6 +356,7 @@ void ether_setup(struct net_device *dev) |
| dev->header_ops = ð_header_ops; |
| dev->type = ARPHRD_ETHER; |
| dev->hard_header_len = ETH_HLEN; |
| + dev->min_header_len = ETH_HLEN; |
| dev->mtu = ETH_DATA_LEN; |
| dev->min_mtu = ETH_MIN_MTU; |
| dev->max_mtu = ETH_DATA_LEN; |
| -- |
| 2.12.0 |
| |