diff options
author | Daniel Borkmann <daniel@iogearbox.net> | 2015-11-11 17:25:42 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-11-15 18:00:35 -0500 |
commit | 3c70c132488794e2489ab045559b0ce0afcf17de (patch) | |
tree | 7d48a54696aaa56ab9db32fb8e04b57cfcfae3de /net/packet | |
parent | 8fd6c80d9dd938ca338c70698533a7e304752846 (diff) |
packet: only allow extra vlan len on ethernet devices
Packet sockets can be used by various net devices and are not
really restricted to ARPHRD_ETHER device types. However, when
currently checking for the extra 4 bytes that can be transmitted
in VLAN case, our assumption is that we generally probe on
ARPHRD_ETHER devices. Therefore, before looking into Ethernet
header, check the device type first.
This also fixes the issue where non-ARPHRD_ETHER devices could
have no dev->hard_header_len in TX_RING SOCK_RAW case, and thus
the check would test unfilled linear part of the skb (instead
of non-linear).
Fixes: 57f89bfa2140 ("network: Allow af_packet to transmit +4 bytes for VLAN packets.")
Fixes: 52f1454f629f ("packet: allow to transmit +4 byte in TX_RING slot for VLAN case")
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/packet')
-rw-r--r-- | net/packet/af_packet.c | 60 |
1 files changed, 25 insertions, 35 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index bdecf17a15bb..8795b0fb1ed1 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
@@ -1741,6 +1741,20 @@ static void fanout_release(struct sock *sk) | |||
1741 | kfree_rcu(po->rollover, rcu); | 1741 | kfree_rcu(po->rollover, rcu); |
1742 | } | 1742 | } |
1743 | 1743 | ||
1744 | static bool packet_extra_vlan_len_allowed(const struct net_device *dev, | ||
1745 | struct sk_buff *skb) | ||
1746 | { | ||
1747 | /* Earlier code assumed this would be a VLAN pkt, double-check | ||
1748 | * this now that we have the actual packet in hand. We can only | ||
1749 | * do this check on Ethernet devices. | ||
1750 | */ | ||
1751 | if (unlikely(dev->type != ARPHRD_ETHER)) | ||
1752 | return false; | ||
1753 | |||
1754 | skb_reset_mac_header(skb); | ||
1755 | return likely(eth_hdr(skb)->h_proto == htons(ETH_P_8021Q)); | ||
1756 | } | ||
1757 | |||
1744 | static const struct proto_ops packet_ops; | 1758 | static const struct proto_ops packet_ops; |
1745 | 1759 | ||
1746 | static const struct proto_ops packet_ops_spkt; | 1760 | static const struct proto_ops packet_ops_spkt; |
@@ -1902,18 +1916,10 @@ retry: | |||
1902 | goto retry; | 1916 | goto retry; |
1903 | } | 1917 | } |
1904 | 1918 | ||
1905 | if (len > (dev->mtu + dev->hard_header_len + extra_len)) { | 1919 | if (len > (dev->mtu + dev->hard_header_len + extra_len) && |
1906 | /* Earlier code assumed this would be a VLAN pkt, | 1920 | !packet_extra_vlan_len_allowed(dev, skb)) { |
1907 | * double-check this now that we have the actual | 1921 | err = -EMSGSIZE; |
1908 | * packet in hand. | 1922 | goto out_unlock; |
1909 | */ | ||
1910 | struct ethhdr *ehdr; | ||
1911 | skb_reset_mac_header(skb); | ||
1912 | ehdr = eth_hdr(skb); | ||
1913 | if (ehdr->h_proto != htons(ETH_P_8021Q)) { | ||
1914 | err = -EMSGSIZE; | ||
1915 | goto out_unlock; | ||
1916 | } | ||
1917 | } | 1923 | } |
1918 | 1924 | ||
1919 | skb->protocol = proto; | 1925 | skb->protocol = proto; |
@@ -2525,18 +2531,10 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) | |||
2525 | tp_len = tpacket_fill_skb(po, skb, ph, dev, size_max, proto, | 2531 | tp_len = tpacket_fill_skb(po, skb, ph, dev, size_max, proto, |
2526 | addr, hlen); | 2532 | addr, hlen); |
2527 | if (likely(tp_len >= 0) && | 2533 | if (likely(tp_len >= 0) && |
2528 | tp_len > dev->mtu + dev->hard_header_len) { | 2534 | tp_len > dev->mtu + dev->hard_header_len && |
2529 | struct ethhdr *ehdr; | 2535 | !packet_extra_vlan_len_allowed(dev, skb)) |
2530 | /* Earlier code assumed this would be a VLAN pkt, | 2536 | tp_len = -EMSGSIZE; |
2531 | * double-check this now that we have the actual | ||
2532 | * packet in hand. | ||
2533 | */ | ||
2534 | 2537 | ||
2535 | skb_reset_mac_header(skb); | ||
2536 | ehdr = eth_hdr(skb); | ||
2537 | if (ehdr->h_proto != htons(ETH_P_8021Q)) | ||
2538 | tp_len = -EMSGSIZE; | ||
2539 | } | ||
2540 | if (unlikely(tp_len < 0)) { | 2538 | if (unlikely(tp_len < 0)) { |
2541 | if (po->tp_loss) { | 2539 | if (po->tp_loss) { |
2542 | __packet_set_status(po, ph, | 2540 | __packet_set_status(po, ph, |
@@ -2765,18 +2763,10 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) | |||
2765 | 2763 | ||
2766 | sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags); | 2764 | sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags); |
2767 | 2765 | ||
2768 | if (!gso_type && (len > dev->mtu + reserve + extra_len)) { | 2766 | if (!gso_type && (len > dev->mtu + reserve + extra_len) && |
2769 | /* Earlier code assumed this would be a VLAN pkt, | 2767 | !packet_extra_vlan_len_allowed(dev, skb)) { |
2770 | * double-check this now that we have the actual | 2768 | err = -EMSGSIZE; |
2771 | * packet in hand. | 2769 | goto out_free; |
2772 | */ | ||
2773 | struct ethhdr *ehdr; | ||
2774 | skb_reset_mac_header(skb); | ||
2775 | ehdr = eth_hdr(skb); | ||
2776 | if (ehdr->h_proto != htons(ETH_P_8021Q)) { | ||
2777 | err = -EMSGSIZE; | ||
2778 | goto out_free; | ||
2779 | } | ||
2780 | } | 2770 | } |
2781 | 2771 | ||
2782 | skb->protocol = proto; | 2772 | skb->protocol = proto; |