All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next 0/3] validate variable length ll headers
@ 2016-03-10  2:58 Willem de Bruijn
  2016-03-10  2:58 ` [PATCH net-next 1/3] net: " Willem de Bruijn
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: Willem de Bruijn @ 2016-03-10  2:58 UTC (permalink / raw)
  To: netdev; +Cc: davem, Willem de Bruijn

From: Willem de Bruijn <willemb@google.com>

Allow device-specific validation of link layer headers. Existing
checks drop all packets shorter than hard_header_len. For variable
length protocols, such packets can be valid.

patch 1 adds header_ops.validate and dev_validate_header
patch 2 implements the protocol specific callback for AX25
patch 3 replaces ll_header_truncated with dev_validate_header

Willem de Bruijn (3):
  net: validate variable length ll headers
  ax25: add link layer header validation function
  packet: validate variable length ll headers

 include/linux/netdevice.h | 22 ++++++++++++++++++++--
 net/ax25/ax25_ip.c        | 15 +++++++++++++++
 net/packet/af_packet.c    | 43 ++++++++++++++++++-------------------------
 3 files changed, 53 insertions(+), 27 deletions(-)

-- 
2.7.0.rc3.207.g0ac5344

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH net-next 1/3] net: validate variable length ll headers
  2016-03-10  2:58 [PATCH net-next 0/3] validate variable length ll headers Willem de Bruijn
@ 2016-03-10  2:58 ` Willem de Bruijn
  2016-03-10  2:58 ` [PATCH net-next 2/3] ax25: add link layer header validation function Willem de Bruijn
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 7+ messages in thread
From: Willem de Bruijn @ 2016-03-10  2:58 UTC (permalink / raw)
  To: netdev; +Cc: davem, Willem de Bruijn

From: Willem de Bruijn <willemb@google.com>

Netdevice parameter hard_header_len is variously interpreted both as
an upper and lower bound on link layer header length. The field is
used as upper bound when reserving room at allocation, as lower bound
when validating user input in PF_PACKET.

Clarify the definition to be maximum header length. For validation
of untrusted headers, add an optional validate member to header_ops.

Allow bypassing of validation by passing CAP_SYS_RAWIO, for instance
for deliberate testing of corrupt input. In this case, pad trailing
bytes, as some device drivers expect completely initialized headers.

See also http://comments.gmane.org/gmane.linux.network/401064

Signed-off-by: Willem de Bruijn <willemb@google.com>
---
 include/linux/netdevice.h | 22 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index efe7cec..fd30cb5 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -268,6 +268,7 @@ struct header_ops {
 	void	(*cache_update)(struct hh_cache *hh,
 				const struct net_device *dev,
 				const unsigned char *haddr);
+	bool	(*validate)(const char *ll_header, unsigned int len);
 };
 
 /* These flag bits are private to the generic network queueing
@@ -1459,8 +1460,7 @@ enum netdev_priv_flags {
  *	@dma:		DMA channel
  *	@mtu:		Interface MTU value
  *	@type:		Interface hardware type
- *	@hard_header_len: Hardware header length, which means that this is the
- *			  minimum size of a packet.
+ *	@hard_header_len: Maximum hardware header length.
  *
  *	@needed_headroom: Extra headroom the hardware may need, but not in all
  *			  cases can this be guaranteed
@@ -2687,6 +2687,24 @@ static inline int dev_parse_header(const struct sk_buff *skb,
 	return dev->header_ops->parse(skb, haddr);
 }
 
+/* ll_header must have at least hard_header_len allocated */
+static inline bool dev_validate_header(const struct net_device *dev,
+				       char *ll_header, int len)
+{
+	if (likely(len >= dev->hard_header_len))
+		return true;
+
+	if (capable(CAP_SYS_RAWIO)) {
+		memset(ll_header + len, 0, dev->hard_header_len - len);
+		return true;
+	}
+
+	if (dev->header_ops && dev->header_ops->validate)
+		return dev->header_ops->validate(ll_header, len);
+
+	return false;
+}
+
 typedef int gifconf_func_t(struct net_device * dev, char __user * bufptr, int len);
 int register_gifconf(unsigned int family, gifconf_func_t *gifconf);
 static inline int unregister_gifconf(unsigned int family)
-- 
2.7.0.rc3.207.g0ac5344

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH net-next 2/3] ax25: add link layer header validation function
  2016-03-10  2:58 [PATCH net-next 0/3] validate variable length ll headers Willem de Bruijn
  2016-03-10  2:58 ` [PATCH net-next 1/3] net: " Willem de Bruijn
@ 2016-03-10  2:58 ` Willem de Bruijn
  2016-03-10  2:58 ` [PATCH net-next 3/3] packet: validate variable length ll headers Willem de Bruijn
  2016-03-10  3:13 ` [PATCH net-next 0/3] " David Miller
  3 siblings, 0 replies; 7+ messages in thread
From: Willem de Bruijn @ 2016-03-10  2:58 UTC (permalink / raw)
  To: netdev; +Cc: davem, Willem de Bruijn

From: Willem de Bruijn <willemb@google.com>

As variable length protocol, AX25 fails link layer header validation
tests based on a minimum length. header_ops.validate allows protocols
to validate headers that are shorter than hard_header_len. Implement
this callback for AX25.

See also http://comments.gmane.org/gmane.linux.network/401064

Signed-off-by: Willem de Bruijn <willemb@google.com>
---
 net/ax25/ax25_ip.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/net/ax25/ax25_ip.c b/net/ax25/ax25_ip.c
index b563a3f..2fa3be9 100644
--- a/net/ax25/ax25_ip.c
+++ b/net/ax25/ax25_ip.c
@@ -228,8 +228,23 @@ netdev_tx_t ax25_ip_xmit(struct sk_buff *skb)
 }
 #endif
 
+static bool ax25_validate_header(const char *header, unsigned int len)
+{
+	ax25_digi digi;
+
+	if (!len)
+		return false;
+
+	if (header[0])
+		return true;
+
+	return ax25_addr_parse(header + 1, len - 1, NULL, NULL, &digi, NULL,
+			       NULL);
+}
+
 const struct header_ops ax25_header_ops = {
 	.create = ax25_hard_header,
+	.validate = ax25_validate_header,
 };
 
 EXPORT_SYMBOL(ax25_header_ops);
-- 
2.7.0.rc3.207.g0ac5344

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH net-next 3/3] packet: validate variable length ll headers
  2016-03-10  2:58 [PATCH net-next 0/3] validate variable length ll headers Willem de Bruijn
  2016-03-10  2:58 ` [PATCH net-next 1/3] net: " Willem de Bruijn
  2016-03-10  2:58 ` [PATCH net-next 2/3] ax25: add link layer header validation function Willem de Bruijn
@ 2016-03-10  2:58 ` Willem de Bruijn
  2016-03-10  3:13 ` [PATCH net-next 0/3] " David Miller
  3 siblings, 0 replies; 7+ messages in thread
From: Willem de Bruijn @ 2016-03-10  2:58 UTC (permalink / raw)
  To: netdev; +Cc: davem, Willem de Bruijn

From: Willem de Bruijn <willemb@google.com>

Replace link layer header validation check ll_header_truncate with
more generic dev_validate_header.

Validation based on hard_header_len incorrectly drops valid packets
in variable length protocols, such as AX25. dev_validate_header
calls header_ops.validate for such protocols to ensure correctness
below hard_header_len.

See also http://comments.gmane.org/gmane.linux.network/401064

Fixes 9c7077622dd9 ("packet: make packet_snd fail on len smaller than l2 header")
Signed-off-by: Willem de Bruijn <willemb@google.com>
---
 net/packet/af_packet.c | 43 ++++++++++++++++++-------------------------
 1 file changed, 18 insertions(+), 25 deletions(-)

diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index d41b107..1ecfa71 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1915,6 +1915,10 @@ retry:
 		goto retry;
 	}
 
+	if (!dev_validate_header(dev, skb->data, len)) {
+		err = -EINVAL;
+		goto out_unlock;
+	}
 	if (len > (dev->mtu + dev->hard_header_len + extra_len) &&
 	    !packet_extra_vlan_len_allowed(dev, skb)) {
 		err = -EMSGSIZE;
@@ -2393,18 +2397,6 @@ static void tpacket_destruct_skb(struct sk_buff *skb)
 	sock_wfree(skb);
 }
 
-static bool ll_header_truncated(const struct net_device *dev, int len)
-{
-	/* net device doesn't like empty head */
-	if (unlikely(len < dev->hard_header_len)) {
-		net_warn_ratelimited("%s: packet size is too short (%d < %d)\n",
-				     current->comm, len, dev->hard_header_len);
-		return true;
-	}
-
-	return false;
-}
-
 static void tpacket_set_protocol(const struct net_device *dev,
 				 struct sk_buff *skb)
 {
@@ -2522,16 +2514,20 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
 		if (unlikely(err < 0))
 			return -EINVAL;
 	} else if (copylen) {
+		int hdrlen = min_t(int, copylen, tp_len);
+
 		skb_push(skb, dev->hard_header_len);
 		skb_put(skb, copylen - dev->hard_header_len);
-		err = skb_store_bits(skb, 0, data, copylen);
+		err = skb_store_bits(skb, 0, data, hdrlen);
 		if (unlikely(err))
 			return err;
+		if (!dev_validate_header(dev, skb->data, hdrlen))
+			return -EINVAL;
 		if (!skb->protocol)
 			tpacket_set_protocol(dev, skb);
 
-		data += copylen;
-		to_write -= copylen;
+		data += hdrlen;
+		to_write -= hdrlen;
 	}
 
 	offset = offset_in_page(data);
@@ -2703,13 +2699,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
 			copylen = __virtio16_to_cpu(vio_le(),
 						    vnet_hdr->hdr_len);
 		}
-		if (dev->hard_header_len) {
-			if (ll_header_truncated(dev, tp_len)) {
-				tp_len = -EINVAL;
-				goto tpacket_error;
-			}
-			copylen = max_t(int, copylen, dev->hard_header_len);
-		}
+		copylen = max_t(int, copylen, dev->hard_header_len);
 		skb = sock_alloc_send_skb(&po->sk,
 				hlen + tlen + sizeof(struct sockaddr_ll) +
 				(copylen - dev->hard_header_len),
@@ -2905,9 +2895,6 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
 		offset = dev_hard_header(skb, dev, ntohs(proto), addr, NULL, len);
 		if (unlikely(offset < 0))
 			goto out_free;
-	} else {
-		if (ll_header_truncated(dev, len))
-			goto out_free;
 	}
 
 	/* Returns -EFAULT on error */
@@ -2915,6 +2902,12 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
 	if (err)
 		goto out_free;
 
+	if (sock->type == SOCK_RAW &&
+	    !dev_validate_header(dev, skb->data, len)) {
+		err = -EINVAL;
+		goto out_free;
+	}
+
 	sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags);
 
 	if (!vnet_hdr.gso_type && (len > dev->mtu + reserve + extra_len) &&
-- 
2.7.0.rc3.207.g0ac5344

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH net-next 0/3] validate variable length ll headers
  2016-03-10  2:58 [PATCH net-next 0/3] validate variable length ll headers Willem de Bruijn
                   ` (2 preceding siblings ...)
  2016-03-10  2:58 ` [PATCH net-next 3/3] packet: validate variable length ll headers Willem de Bruijn
@ 2016-03-10  3:13 ` David Miller
  2016-03-10  4:22   ` Willem de Bruijn
  3 siblings, 1 reply; 7+ messages in thread
From: David Miller @ 2016-03-10  3:13 UTC (permalink / raw)
  To: willemdebruijn.kernel; +Cc: netdev, willemb

From: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
Date: Wed,  9 Mar 2016 21:58:31 -0500

> Allow device-specific validation of link layer headers. Existing
> checks drop all packets shorter than hard_header_len. For variable
> length protocols, such packets can be valid.
> 
> patch 1 adds header_ops.validate and dev_validate_header
> patch 2 implements the protocol specific callback for AX25
> patch 3 replaces ll_header_truncated with dev_validate_header

Series applied and queued up for -stable, thanks!

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH net-next 0/3] validate variable length ll headers
  2016-03-10  3:13 ` [PATCH net-next 0/3] " David Miller
@ 2016-03-10  4:22   ` Willem de Bruijn
  2016-03-10  4:26     ` David Miller
  0 siblings, 1 reply; 7+ messages in thread
From: Willem de Bruijn @ 2016-03-10  4:22 UTC (permalink / raw)
  To: David Miller; +Cc: Network Development, Willem de Bruijn

On Wed, Mar 9, 2016 at 10:13 PM, David Miller <davem@davemloft.net> wrote:
> From: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
> Date: Wed,  9 Mar 2016 21:58:31 -0500
>
>> Allow device-specific validation of link layer headers. Existing
>> checks drop all packets shorter than hard_header_len. For variable
>> length protocols, such packets can be valid.
>>
>> patch 1 adds header_ops.validate and dev_validate_header
>> patch 2 implements the protocol specific callback for AX25
>> patch 3 replaces ll_header_truncated with dev_validate_header
>
> Series applied and queued up for -stable, thanks!

Thanks, David. Please don't queue the earlier net patchset for stable.
I spotted an issue while converting to net-next, I'm afraid. I can send a
net v2 (as net-next won't apply), or a separate stable patch once 4.5 is cut.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH net-next 0/3] validate variable length ll headers
  2016-03-10  4:22   ` Willem de Bruijn
@ 2016-03-10  4:26     ` David Miller
  0 siblings, 0 replies; 7+ messages in thread
From: David Miller @ 2016-03-10  4:26 UTC (permalink / raw)
  To: willemdebruijn.kernel; +Cc: netdev, willemb

From: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
Date: Wed, 9 Mar 2016 23:22:59 -0500

> On Wed, Mar 9, 2016 at 10:13 PM, David Miller <davem@davemloft.net> wrote:
>> From: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
>> Date: Wed,  9 Mar 2016 21:58:31 -0500
>>
>>> Allow device-specific validation of link layer headers. Existing
>>> checks drop all packets shorter than hard_header_len. For variable
>>> length protocols, such packets can be valid.
>>>
>>> patch 1 adds header_ops.validate and dev_validate_header
>>> patch 2 implements the protocol specific callback for AX25
>>> patch 3 replaces ll_header_truncated with dev_validate_header
>>
>> Series applied and queued up for -stable, thanks!
> 
> Thanks, David. Please don't queue the earlier net patchset for stable.
> I spotted an issue while converting to net-next, I'm afraid. I can send a
> net v2 (as net-next won't apply), or a separate stable patch once 4.5 is cut.

I'll use the net-next patches as the basis for the backport I do,
thanks.

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2016-03-10  4:26 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-03-10  2:58 [PATCH net-next 0/3] validate variable length ll headers Willem de Bruijn
2016-03-10  2:58 ` [PATCH net-next 1/3] net: " Willem de Bruijn
2016-03-10  2:58 ` [PATCH net-next 2/3] ax25: add link layer header validation function Willem de Bruijn
2016-03-10  2:58 ` [PATCH net-next 3/3] packet: validate variable length ll headers Willem de Bruijn
2016-03-10  3:13 ` [PATCH net-next 0/3] " David Miller
2016-03-10  4:22   ` Willem de Bruijn
2016-03-10  4:26     ` David Miller

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.