diff options
Diffstat (limited to 'tags/2.6.20-4/20963_linux-2.6-xen-add-packet_auxdata-cmsg-2.patch')
-rw-r--r-- | tags/2.6.20-4/20963_linux-2.6-xen-add-packet_auxdata-cmsg-2.patch | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/tags/2.6.20-4/20963_linux-2.6-xen-add-packet_auxdata-cmsg-2.patch b/tags/2.6.20-4/20963_linux-2.6-xen-add-packet_auxdata-cmsg-2.patch new file mode 100644 index 0000000..8bf6bf7 --- /dev/null +++ b/tags/2.6.20-4/20963_linux-2.6-xen-add-packet_auxdata-cmsg-2.patch @@ -0,0 +1,144 @@ +From: Herbert Xu <herbert.xu@redhat.com> +Subject: Re: Help on BZ 223505 tcpdump causes ppc64 to enter xmon +Date: Wed, 24 Jan 2007 10:23:55 +1100 +Message-Id: <20070123232355.GA4724@gondor.apana.org.au> + +On Wed, Jan 24, 2007 at 09:03:24AM +1100, Herbert Xu wrote: +> +> OK, I've found the problem. The skb->cb buffer is already being +> used for sockaddr_ll which the aux data is overwriting. Let me +> fix this up by getting them to share the buffer. + +The obvious fix of putting them together in the cb doesn't quite work +because sockaddr_ll's last member can be as large as MAX_ADDR_LEN (32). +In fact this means that older kernels with skb->cb less than 44 bytes +may in fact be vulnerable if net devices with an address length of 32 +bytes exist. + +[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> + +Cheers, +-- +Visit Openswan at http://www.openswan.org/ +Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au> +Home Page: http://gondor.apana.org.au/~herbert/ +PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt +-- +Index: linux-2.6.20.i386/net/packet/af_packet.c +=================================================================== +--- linux-2.6.20.i386.orig/net/packet/af_packet.c ++++ linux-2.6.20.i386/net/packet/af_packet.c +@@ -60,6 +60,7 @@ + #include <linux/netdevice.h> + #include <linux/if_packet.h> + #include <linux/wireless.h> ++#include <linux/kernel.h> + #include <linux/kmod.h> + #include <net/ip.h> + #include <net/protocol.h> +@@ -215,7 +216,15 @@ struct packet_sock { + #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)) + + extern int skb_checksum_setup(struct sk_buff *skb); + +@@ -298,7 +307,7 @@ static int packet_rcv_spkt(struct sk_buf + /* drop conntrack reference */ + nf_reset(skb); + +- spkt = (struct sockaddr_pkt*)skb->cb; ++ spkt = &PACKET_SKB_CB(skb)->sa.pkt; + + skb_push(skb, skb->data-skb->mac.raw); + +@@ -467,7 +476,6 @@ static int packet_rcv(struct sk_buff *sk + u8 * skb_head = skb->data; + int skb_len = skb->len; + unsigned int snaplen, res; +- struct tpacket_auxdata *aux; + + if (skb->pkt_type == PACKET_LOOPBACK) + goto drop; +@@ -518,7 +526,10 @@ static int packet_rcv(struct sk_buff *sk + 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_hatype = dev->type; + sll->sll_protocol = skb->protocol; +@@ -532,14 +543,7 @@ static int packet_rcv(struct sk_buff *sk + if (skb_checksum_setup(skb)) + goto drop_n_acct; + +- aux = PACKET_SKB_CB(skb); +- 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; ++ PACKET_SKB_CB(skb)->origlen = skb->len; + + if (pskb_trim(skb, snaplen)) + goto drop_n_acct; +@@ -1113,7 +1117,7 @@ static int packet_recvmsg(struct kiocb * + * it in now. + */ + +- sll = (struct sockaddr_ll*)skb->cb; ++ sll = &PACKET_SKB_CB(skb)->sa.ll; + if (sock->type == SOCK_PACKET) + msg->msg_namelen = sizeof(struct sockaddr_pkt); + else +@@ -1138,11 +1142,21 @@ static int packet_recvmsg(struct kiocb * + sock_recv_timestamp(msg, sk, skb); + + 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) { +- struct tpacket_auxdata *aux = PACKET_SKB_CB(skb); +- put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(*aux), aux); ++ struct tpacket_auxdata 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); + } + + /* |