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: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
52b4620294
@ -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,18 +1916,10 @@ retry:
|
|||||||
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
|
err = -EMSGSIZE;
|
||||||
* packet in hand.
|
goto out_unlock;
|
||||||
*/
|
|
||||||
struct ethhdr *ehdr;
|
|
||||||
skb_reset_mac_header(skb);
|
|
||||||
ehdr = eth_hdr(skb);
|
|
||||||
if (ehdr->h_proto != htons(ETH_P_8021Q)) {
|
|
||||||
err = -EMSGSIZE;
|
|
||||||
goto out_unlock;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
skb->protocol = proto;
|
skb->protocol = proto;
|
||||||
@ -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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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)
|
|||||||
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)
|
|||||||
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,
|
tp_len = -EMSGSIZE;
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
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,18 +2775,10 @@ 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
|
err = -EMSGSIZE;
|
||||||
* packet in hand.
|
goto out_free;
|
||||||
*/
|
|
||||||
struct ethhdr *ehdr;
|
|
||||||
skb_reset_mac_header(skb);
|
|
||||||
ehdr = eth_hdr(skb);
|
|
||||||
if (ehdr->h_proto != htons(ETH_P_8021Q)) {
|
|
||||||
err = -EMSGSIZE;
|
|
||||||
goto out_free;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
skb->protocol = proto;
|
skb->protocol = proto;
|
||||||
@ -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;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user