[PACKET]: Fix skb->cb clobbering between aux and sockaddr
Both aux data and sockaddr tries to use the same buffer which obviously doesn't work. We just happen to have 4 bytes free in the skb->cb if you take away the maximum length of sockaddr_ll. That's just enough to store the one piece of info from aux data that we can't generate at recvmsg(2) time. This is what the following patch does. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
8dc4194474
commit
ffbc61117d
|
@ -60,6 +60,7 @@
|
||||||
#include <linux/netdevice.h>
|
#include <linux/netdevice.h>
|
||||||
#include <linux/if_packet.h>
|
#include <linux/if_packet.h>
|
||||||
#include <linux/wireless.h>
|
#include <linux/wireless.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
#include <linux/kmod.h>
|
#include <linux/kmod.h>
|
||||||
#include <net/ip.h>
|
#include <net/ip.h>
|
||||||
#include <net/protocol.h>
|
#include <net/protocol.h>
|
||||||
|
@ -215,7 +216,15 @@ struct packet_sock {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PACKET_SKB_CB(__skb) ((struct tpacket_auxdata *)((__skb)->cb))
|
struct packet_skb_cb {
|
||||||
|
unsigned int origlen;
|
||||||
|
union {
|
||||||
|
struct sockaddr_pkt pkt;
|
||||||
|
struct sockaddr_ll ll;
|
||||||
|
} sa;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PACKET_SKB_CB(__skb) ((struct packet_skb_cb *)((__skb)->cb))
|
||||||
|
|
||||||
#ifdef CONFIG_PACKET_MMAP
|
#ifdef CONFIG_PACKET_MMAP
|
||||||
|
|
||||||
|
@ -296,7 +305,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, struct
|
||||||
/* drop conntrack reference */
|
/* drop conntrack reference */
|
||||||
nf_reset(skb);
|
nf_reset(skb);
|
||||||
|
|
||||||
spkt = (struct sockaddr_pkt*)skb->cb;
|
spkt = &PACKET_SKB_CB(skb)->sa.pkt;
|
||||||
|
|
||||||
skb_push(skb, skb->data-skb->mac.raw);
|
skb_push(skb, skb->data-skb->mac.raw);
|
||||||
|
|
||||||
|
@ -465,7 +474,6 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet
|
||||||
u8 * skb_head = skb->data;
|
u8 * skb_head = skb->data;
|
||||||
int skb_len = skb->len;
|
int skb_len = skb->len;
|
||||||
unsigned int snaplen, res;
|
unsigned int snaplen, res;
|
||||||
struct tpacket_auxdata *aux;
|
|
||||||
|
|
||||||
if (skb->pkt_type == PACKET_LOOPBACK)
|
if (skb->pkt_type == PACKET_LOOPBACK)
|
||||||
goto drop;
|
goto drop;
|
||||||
|
@ -516,7 +524,10 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet
|
||||||
skb = nskb;
|
skb = nskb;
|
||||||
}
|
}
|
||||||
|
|
||||||
sll = (struct sockaddr_ll*)skb->cb;
|
BUILD_BUG_ON(sizeof(*PACKET_SKB_CB(skb)) + MAX_ADDR_LEN - 8 >
|
||||||
|
sizeof(skb->cb));
|
||||||
|
|
||||||
|
sll = &PACKET_SKB_CB(skb)->sa.ll;
|
||||||
sll->sll_family = AF_PACKET;
|
sll->sll_family = AF_PACKET;
|
||||||
sll->sll_hatype = dev->type;
|
sll->sll_hatype = dev->type;
|
||||||
sll->sll_protocol = skb->protocol;
|
sll->sll_protocol = skb->protocol;
|
||||||
|
@ -527,14 +538,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet
|
||||||
if (dev->hard_header_parse)
|
if (dev->hard_header_parse)
|
||||||
sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr);
|
sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr);
|
||||||
|
|
||||||
aux = PACKET_SKB_CB(skb);
|
PACKET_SKB_CB(skb)->origlen = skb->len;
|
||||||
aux->tp_status = TP_STATUS_USER;
|
|
||||||
if (skb->ip_summed == CHECKSUM_PARTIAL)
|
|
||||||
aux->tp_status |= TP_STATUS_CSUMNOTREADY;
|
|
||||||
aux->tp_len = skb->len;
|
|
||||||
aux->tp_snaplen = snaplen;
|
|
||||||
aux->tp_mac = 0;
|
|
||||||
aux->tp_net = skb->nh.raw - skb->data;
|
|
||||||
|
|
||||||
if (pskb_trim(skb, snaplen))
|
if (pskb_trim(skb, snaplen))
|
||||||
goto drop_n_acct;
|
goto drop_n_acct;
|
||||||
|
@ -1106,7 +1110,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||||||
* it in now.
|
* it in now.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
sll = (struct sockaddr_ll*)skb->cb;
|
sll = &PACKET_SKB_CB(skb)->sa.ll;
|
||||||
if (sock->type == SOCK_PACKET)
|
if (sock->type == SOCK_PACKET)
|
||||||
msg->msg_namelen = sizeof(struct sockaddr_pkt);
|
msg->msg_namelen = sizeof(struct sockaddr_pkt);
|
||||||
else
|
else
|
||||||
|
@ -1131,11 +1135,21 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||||||
sock_recv_timestamp(msg, sk, skb);
|
sock_recv_timestamp(msg, sk, skb);
|
||||||
|
|
||||||
if (msg->msg_name)
|
if (msg->msg_name)
|
||||||
memcpy(msg->msg_name, skb->cb, msg->msg_namelen);
|
memcpy(msg->msg_name, &PACKET_SKB_CB(skb)->sa,
|
||||||
|
msg->msg_namelen);
|
||||||
|
|
||||||
if (pkt_sk(sk)->auxdata) {
|
if (pkt_sk(sk)->auxdata) {
|
||||||
struct tpacket_auxdata *aux = PACKET_SKB_CB(skb);
|
struct tpacket_auxdata aux;
|
||||||
put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(*aux), aux);
|
|
||||||
|
aux.tp_status = TP_STATUS_USER;
|
||||||
|
if (skb->ip_summed == CHECKSUM_PARTIAL)
|
||||||
|
aux.tp_status |= TP_STATUS_CSUMNOTREADY;
|
||||||
|
aux.tp_len = PACKET_SKB_CB(skb)->origlen;
|
||||||
|
aux.tp_snaplen = skb->len;
|
||||||
|
aux.tp_mac = 0;
|
||||||
|
aux.tp_net = skb->nh.raw - skb->data;
|
||||||
|
|
||||||
|
put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(aux), &aux);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue