| From foo@baz Sat Apr 16 10:02:53 PDT 2016 |
| From: Willem de Bruijn <willemb@google.com> |
| Date: Wed, 9 Mar 2016 21:58:32 -0500 |
| Subject: net: validate variable length ll headers |
| |
| From: Willem de Bruijn <willemb@google.com> |
| |
| [ Upstream commit 2793a23aacbd754dbbb5cb75093deb7e4103bace ] |
| |
| 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> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| include/linux/netdevice.h | 22 ++++++++++++++++++++-- |
| 1 file changed, 20 insertions(+), 2 deletions(-) |
| |
| --- a/include/linux/netdevice.h |
| +++ b/include/linux/netdevice.h |
| @@ -265,6 +265,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 |
| @@ -1398,8 +1399,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 |
| @@ -2493,6 +2493,24 @@ static inline int dev_parse_header(const |
| 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) |