Commit 52b46202 authored by David S. Miller's avatar David S. Miller

Merge branch 'packet-fixes'

Daniel Borkmann says:

====================
packet fixes

Fixes a couple of issues in packet sockets, i.e. on TX ring side. See
individual patches for details.

v2 -> v3:
 - First two patches unchanged, kept Jason's Ack
 - Reworked 3rd patch and split into 3:
  - check for dev type as discussed with Willem
  - infer skb->protocol
  - fix max len for dgram
v1 -> v2:
 - Added patch 2 as suggested by Dave
 - Rest is unchanged from previous submission
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents d7475de5 5cfb4c8d
...@@ -1741,6 +1741,20 @@ static void fanout_release(struct sock *sk) ...@@ -1741,6 +1741,20 @@ static void fanout_release(struct sock *sk)
kfree_rcu(po->rollover, rcu); kfree_rcu(po->rollover, rcu);
} }
static bool packet_extra_vlan_len_allowed(const struct net_device *dev,
struct sk_buff *skb)
{
/* Earlier code assumed this would be a VLAN pkt, double-check
* this now that we have the actual packet in hand. We can only
* do this check on Ethernet devices.
*/
if (unlikely(dev->type != ARPHRD_ETHER))
return false;
skb_reset_mac_header(skb);
return likely(eth_hdr(skb)->h_proto == htons(ETH_P_8021Q));
}
static const struct proto_ops packet_ops; static const struct proto_ops packet_ops;
static const struct proto_ops packet_ops_spkt; static const struct proto_ops packet_ops_spkt;
...@@ -1902,19 +1916,11 @@ static int packet_sendmsg_spkt(struct socket *sock, struct msghdr *msg, ...@@ -1902,19 +1916,11 @@ static int packet_sendmsg_spkt(struct socket *sock, struct msghdr *msg,
goto retry; goto retry;
} }
if (len > (dev->mtu + dev->hard_header_len + extra_len)) { if (len > (dev->mtu + dev->hard_header_len + extra_len) &&
/* Earlier code assumed this would be a VLAN pkt, !packet_extra_vlan_len_allowed(dev, skb)) {
* double-check this now that we have the actual
* packet in hand.
*/
struct ethhdr *ehdr;
skb_reset_mac_header(skb);
ehdr = eth_hdr(skb);
if (ehdr->h_proto != htons(ETH_P_8021Q)) {
err = -EMSGSIZE; err = -EMSGSIZE;
goto out_unlock; goto out_unlock;
} }
}
skb->protocol = proto; skb->protocol = proto;
skb->dev = dev; skb->dev = dev;
...@@ -2332,6 +2338,15 @@ static bool ll_header_truncated(const struct net_device *dev, int len) ...@@ -2332,6 +2338,15 @@ static bool ll_header_truncated(const struct net_device *dev, int len)
return false; return false;
} }
static void tpacket_set_protocol(const struct net_device *dev,
struct sk_buff *skb)
{
if (dev->type == ARPHRD_ETHER) {
skb_reset_mac_header(skb);
skb->protocol = eth_hdr(skb)->h_proto;
}
}
static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
void *frame, struct net_device *dev, int size_max, void *frame, struct net_device *dev, int size_max,
__be16 proto, unsigned char *addr, int hlen) __be16 proto, unsigned char *addr, int hlen)
...@@ -2368,8 +2383,6 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, ...@@ -2368,8 +2383,6 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
skb_reserve(skb, hlen); skb_reserve(skb, hlen);
skb_reset_network_header(skb); skb_reset_network_header(skb);
if (!packet_use_direct_xmit(po))
skb_probe_transport_header(skb, 0);
if (unlikely(po->tp_tx_has_off)) { if (unlikely(po->tp_tx_has_off)) {
int off_min, off_max, off; int off_min, off_max, off;
off_min = po->tp_hdrlen - sizeof(struct sockaddr_ll); off_min = po->tp_hdrlen - sizeof(struct sockaddr_ll);
...@@ -2415,6 +2428,8 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, ...@@ -2415,6 +2428,8 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
dev->hard_header_len); dev->hard_header_len);
if (unlikely(err)) if (unlikely(err))
return err; return err;
if (!skb->protocol)
tpacket_set_protocol(dev, skb);
data += dev->hard_header_len; data += dev->hard_header_len;
to_write -= dev->hard_header_len; to_write -= dev->hard_header_len;
...@@ -2449,6 +2464,8 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, ...@@ -2449,6 +2464,8 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
len = ((to_write > len_max) ? len_max : to_write); len = ((to_write > len_max) ? len_max : to_write);
} }
skb_probe_transport_header(skb, 0);
return tp_len; return tp_len;
} }
...@@ -2493,12 +2510,13 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) ...@@ -2493,12 +2510,13 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
if (unlikely(!(dev->flags & IFF_UP))) if (unlikely(!(dev->flags & IFF_UP)))
goto out_put; goto out_put;
reserve = dev->hard_header_len + VLAN_HLEN; if (po->sk.sk_socket->type == SOCK_RAW)
reserve = dev->hard_header_len;
size_max = po->tx_ring.frame_size size_max = po->tx_ring.frame_size
- (po->tp_hdrlen - sizeof(struct sockaddr_ll)); - (po->tp_hdrlen - sizeof(struct sockaddr_ll));
if (size_max > dev->mtu + reserve) if (size_max > dev->mtu + reserve + VLAN_HLEN)
size_max = dev->mtu + reserve; size_max = dev->mtu + reserve + VLAN_HLEN;
do { do {
ph = packet_current_frame(po, &po->tx_ring, ph = packet_current_frame(po, &po->tx_ring,
...@@ -2525,18 +2543,10 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) ...@@ -2525,18 +2543,10 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
tp_len = tpacket_fill_skb(po, skb, ph, dev, size_max, proto, tp_len = tpacket_fill_skb(po, skb, ph, dev, size_max, proto,
addr, hlen); addr, hlen);
if (likely(tp_len >= 0) && if (likely(tp_len >= 0) &&
tp_len > dev->mtu + dev->hard_header_len) { tp_len > dev->mtu + reserve &&
struct ethhdr *ehdr; !packet_extra_vlan_len_allowed(dev, skb))
/* Earlier code assumed this would be a VLAN pkt,
* double-check this now that we have the actual
* packet in hand.
*/
skb_reset_mac_header(skb);
ehdr = eth_hdr(skb);
if (ehdr->h_proto != htons(ETH_P_8021Q))
tp_len = -EMSGSIZE; tp_len = -EMSGSIZE;
}
if (unlikely(tp_len < 0)) { if (unlikely(tp_len < 0)) {
if (po->tp_loss) { if (po->tp_loss) {
__packet_set_status(po, ph, __packet_set_status(po, ph,
...@@ -2765,19 +2775,11 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) ...@@ -2765,19 +2775,11 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags); sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags);
if (!gso_type && (len > dev->mtu + reserve + extra_len)) { if (!gso_type && (len > dev->mtu + reserve + extra_len) &&
/* Earlier code assumed this would be a VLAN pkt, !packet_extra_vlan_len_allowed(dev, skb)) {
* double-check this now that we have the actual
* packet in hand.
*/
struct ethhdr *ehdr;
skb_reset_mac_header(skb);
ehdr = eth_hdr(skb);
if (ehdr->h_proto != htons(ETH_P_8021Q)) {
err = -EMSGSIZE; err = -EMSGSIZE;
goto out_free; goto out_free;
} }
}
skb->protocol = proto; skb->protocol = proto;
skb->dev = dev; skb->dev = dev;
...@@ -2807,8 +2809,8 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) ...@@ -2807,8 +2809,8 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
len += vnet_hdr_len; len += vnet_hdr_len;
} }
if (!packet_use_direct_xmit(po))
skb_probe_transport_header(skb, reserve); skb_probe_transport_header(skb, reserve);
if (unlikely(extra_len == 4)) if (unlikely(extra_len == 4))
skb->no_fcs = 1; skb->no_fcs = 1;
......
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