summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
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.patch144
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);
+ }
+
+ /*