aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2007-02-05 02:33:10 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2007-02-08 15:38:47 -0500
commitffbc61117d32dc4e768f999325ecfb2528d6b303 (patch)
treef59a235c4eb22ac5ad9ede80f814f5d6ab1e6641 /net
parent8dc4194474159660d7f37c495e3fc3f10d0db8cc (diff)
[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>
Diffstat (limited to 'net')
-rw-r--r--net/packet/af_packet.c46
1 files changed, 30 insertions, 16 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 8973ea78831e..a6fa48788e8f 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -60,6 +60,7 @@
60#include <linux/netdevice.h> 60#include <linux/netdevice.h>
61#include <linux/if_packet.h> 61#include <linux/if_packet.h>
62#include <linux/wireless.h> 62#include <linux/wireless.h>
63#include <linux/kernel.h>
63#include <linux/kmod.h> 64#include <linux/kmod.h>
64#include <net/ip.h> 65#include <net/ip.h>
65#include <net/protocol.h> 66#include <net/protocol.h>
@@ -215,7 +216,15 @@ struct packet_sock {
215#endif 216#endif
216}; 217};
217 218
218#define PACKET_SKB_CB(__skb) ((struct tpacket_auxdata *)((__skb)->cb)) 219struct packet_skb_cb {
220 unsigned int origlen;
221 union {
222 struct sockaddr_pkt pkt;
223 struct sockaddr_ll ll;
224 } sa;
225};
226
227#define PACKET_SKB_CB(__skb) ((struct packet_skb_cb *)((__skb)->cb))
219 228
220#ifdef CONFIG_PACKET_MMAP 229#ifdef CONFIG_PACKET_MMAP
221 230
@@ -296,7 +305,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, struct
296 /* drop conntrack reference */ 305 /* drop conntrack reference */
297 nf_reset(skb); 306 nf_reset(skb);
298 307
299 spkt = (struct sockaddr_pkt*)skb->cb; 308 spkt = &PACKET_SKB_CB(skb)->sa.pkt;
300 309
301 skb_push(skb, skb->data-skb->mac.raw); 310 skb_push(skb, skb->data-skb->mac.raw);
302 311
@@ -465,7 +474,6 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet
465 u8 * skb_head = skb->data; 474 u8 * skb_head = skb->data;
466 int skb_len = skb->len; 475 int skb_len = skb->len;
467 unsigned int snaplen, res; 476 unsigned int snaplen, res;
468 struct tpacket_auxdata *aux;
469 477
470 if (skb->pkt_type == PACKET_LOOPBACK) 478 if (skb->pkt_type == PACKET_LOOPBACK)
471 goto drop; 479 goto drop;
@@ -516,7 +524,10 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet
516 skb = nskb; 524 skb = nskb;
517 } 525 }
518 526
519 sll = (struct sockaddr_ll*)skb->cb; 527 BUILD_BUG_ON(sizeof(*PACKET_SKB_CB(skb)) + MAX_ADDR_LEN - 8 >
528 sizeof(skb->cb));
529
530 sll = &PACKET_SKB_CB(skb)->sa.ll;
520 sll->sll_family = AF_PACKET; 531 sll->sll_family = AF_PACKET;
521 sll->sll_hatype = dev->type; 532 sll->sll_hatype = dev->type;
522 sll->sll_protocol = skb->protocol; 533 sll->sll_protocol = skb->protocol;
@@ -527,14 +538,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet
527 if (dev->hard_header_parse) 538 if (dev->hard_header_parse)
528 sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr); 539 sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr);
529 540
530 aux = PACKET_SKB_CB(skb); 541 PACKET_SKB_CB(skb)->origlen = skb->len;
531 aux->tp_status = TP_STATUS_USER;
532 if (skb->ip_summed == CHECKSUM_PARTIAL)
533 aux->tp_status |= TP_STATUS_CSUMNOTREADY;
534 aux->tp_len = skb->len;
535 aux->tp_snaplen = snaplen;
536 aux->tp_mac = 0;
537 aux->tp_net = skb->nh.raw - skb->data;
538 542
539 if (pskb_trim(skb, snaplen)) 543 if (pskb_trim(skb, snaplen))
540 goto drop_n_acct; 544 goto drop_n_acct;
@@ -1106,7 +1110,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
1106 * it in now. 1110 * it in now.
1107 */ 1111 */
1108 1112
1109 sll = (struct sockaddr_ll*)skb->cb; 1113 sll = &PACKET_SKB_CB(skb)->sa.ll;
1110 if (sock->type == SOCK_PACKET) 1114 if (sock->type == SOCK_PACKET)
1111 msg->msg_namelen = sizeof(struct sockaddr_pkt); 1115 msg->msg_namelen = sizeof(struct sockaddr_pkt);
1112 else 1116 else
@@ -1131,11 +1135,21 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
1131 sock_recv_timestamp(msg, sk, skb); 1135 sock_recv_timestamp(msg, sk, skb);
1132 1136
1133 if (msg->msg_name) 1137 if (msg->msg_name)
1134 memcpy(msg->msg_name, skb->cb, msg->msg_namelen); 1138 memcpy(msg->msg_name, &PACKET_SKB_CB(skb)->sa,
1139 msg->msg_namelen);
1135 1140
1136 if (pkt_sk(sk)->auxdata) { 1141 if (pkt_sk(sk)->auxdata) {
1137 struct tpacket_auxdata *aux = PACKET_SKB_CB(skb); 1142 struct tpacket_auxdata aux;
1138 put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(*aux), aux); 1143
1144 aux.tp_status = TP_STATUS_USER;
1145 if (skb->ip_summed == CHECKSUM_PARTIAL)
1146 aux.tp_status |= TP_STATUS_CSUMNOTREADY;
1147 aux.tp_len = PACKET_SKB_CB(skb)->origlen;
1148 aux.tp_snaplen = skb->len;
1149 aux.tp_mac = 0;
1150 aux.tp_net = skb->nh.raw - skb->data;
1151
1152 put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(aux), &aux);
1139 } 1153 }
1140 1154
1141 /* 1155 /*