]> xenbits.xensource.com Git - people/ssmith/nc2-2.6.27.git/commitdiff
patch debug-dump-skb-info-when-invalid
authorSteven Smith <ssmith@weybridge.uk.xensource.com>
Tue, 30 Jun 2009 11:55:47 +0000 (12:55 +0100)
committerSteven Smith <ssmith@weybridge.uk.xensource.com>
Tue, 30 Jun 2009 11:55:47 +0000 (12:55 +0100)
include/linux/skbuff.h
net/core/skbuff.c

index df633650619558e060a01ad3d780bbb38a68d218..b8fc57ac738ae76c4294176c7ea9f25e652d8d74 100644 (file)
@@ -1778,5 +1778,8 @@ int skb_checksum_setup(struct sk_buff *skb);
 static inline int skb_checksum_setup(struct sk_buff *skb) { return 0; }
 #endif
 
+extern void skb_dump_info(const struct sk_buff *skb);
+extern int  skb_mapping_valid(const struct sk_buff *);
+
 #endif /* __KERNEL__ */
 #endif /* _LINUX_SKBUFF_H */
index 957c9cd4bddc110211f46096a287ed117ebe98be..024e747be93bf34aacca079b6ad61912af6bc541 100644 (file)
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
+#include <asm/io.h>
 
 #include "kmap_skb.h"
 
 static struct kmem_cache *skbuff_head_cache __read_mostly;
 static struct kmem_cache *skbuff_fclone_cache __read_mostly;
 
+void skb_dump_info(const struct sk_buff *skb)
+{
+#ifdef CONFIG_XEN
+       int i, nr = skb_shinfo(skb)->nr_frags;
+#endif
+       struct ethhdr *ethh = eth_hdr(skb);
+
+       printk(KERN_ERR "skb: skb at %p with %d users\n", skb, atomic_read(&skb->users));
+       printk(KERN_ERR "skb: prev %p next %p prev->next %p next->prev %p\n",
+              skb->prev, skb->next,
+              skb->prev ? skb->prev->next : NULL,
+              skb->next ? skb->next->prev : NULL);
+       printk(KERN_ERR "skb: len is %#x (data:%#x mac:%#x) truesize %#x\n",
+              skb->len, skb->data_len, skb->mac_len, skb->truesize);
+
+        printk(KERN_ERR "skb: linear:%s\n", skb_is_nonlinear(skb) ? "No" : "Yes");
+        printk(KERN_ERR "skb: data %p head %p tail %p end %p\n",
+               skb->data, skb->head, skb->tail, skb->end);
+        printk(KERN_ERR "skb: flags are local_df:%d cloned:%d ip_summed:%d nohdr:%d\n",
+               skb->local_df, skb->cloned, skb->ip_summed, skb->nohdr);
+        printk(KERN_ERR "skb:               nfctinfo:%d pkt_type:%d fclone:%d ipvs_property:%d\n",
+               skb->nfctinfo, skb->pkt_type, skb->nohdr, skb->ipvs_property);
+#ifdef CONFIG_XEN
+        printk(KERN_ERR "skb:               proto_data_valid:%d proto_csum_blank:%d\n",
+               skb->proto_data_valid, skb->proto_csum_blank);
+#endif
+        printk(KERN_ERR "skb: shared info %p ref %#x\n", skb_shinfo(skb), atomic_read(&skb_shinfo(skb)->dataref));
+        printk(KERN_ERR "skb: frag_list %p\n", skb_shinfo(skb)->frag_list);
+
+       printk(KERN_ERR "skb: eth: (%p) src:%02x:%02x:%02x:%02x:%02x:%02x dest:%02x:%02x:%02x:%02x:%02x:%02x proto %u\n",
+              ethh,
+              ethh->h_source[0], ethh->h_source[1], ethh->h_source[2], ethh->h_source[3], ethh->h_source[4], ethh->h_source[5],
+              ethh->h_dest[0], ethh->h_dest[1], ethh->h_dest[2], ethh->h_dest[3], ethh->h_dest[4], ethh->h_dest[5],
+              ntohs(ethh->h_proto));
+       if (ethh->h_proto == __constant_htons(ETH_P_IP)) {
+               struct iphdr *iph = ip_hdr(skb);
+               printk(KERN_ERR "skb: ip: (%p) saddr "NIPQUAD_FMT" daddr "NIPQUAD_FMT" protocol %d frag_off %d\n",
+                      iph, NIPQUAD(iph->saddr), NIPQUAD(iph->daddr), iph->protocol, iph->frag_off);
+
+               if (iph->protocol == IPPROTO_TCP) {
+                       struct tcphdr *tcph = tcp_hdr(skb);
+                       printk(KERN_ERR "bnx2: tcp: (%p) source %d dest %d seq %u ack %u\n",
+                              tcph, ntohs(tcph->source), ntohs(tcph->dest), ntohl(tcph->seq), ntohl(tcph->ack_seq));
+               }
+       }
+
+#ifdef CONFIG_XEN
+       for(i=0; i<nr; i++) {
+               skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+               unsigned long pfn = page_to_pfn(frag->page);
+               unsigned long mfn = pfn_to_mfn(pfn);
+               printk(KERN_ERR "skb: %d/%d page:%p offset:%#x size:%#x virt:%p pfn:%#lx mfn:%#lx%s flags:%lx%s%s%s)\n",
+                      i, nr, frag->page, frag->page_offset, frag->size,
+                      phys_to_virt(page_to_phys(frag->page)), pfn, mfn,
+                      phys_to_machine_mapping_valid(pfn) ? "" : "(BAD)",
+                      frag->page->flags,
+                      PageForeign(frag->page) ? " FOREIGN" : "",
+                      PageBlkback(frag->page) ? " BLKBACK" : "",
+                      PageNetback(frag->page) ? " NETBACK" : "");
+       }
+#endif
+}
+EXPORT_SYMBOL(skb_dump_info);
+
+#ifdef CONFIG_XEN
+int skb_mapping_valid(const struct sk_buff *skb)
+{
+       int i, nr;
+
+       if (skb == NULL)
+               return 1;
+
+       if (skb_shinfo(skb) == NULL || skb_shinfo(skb) == (void*)0xffffffff)
+               return 1;
+
+       nr = skb_shinfo(skb)->nr_frags;
+
+       for (i = 0; i < nr; i++) {
+               skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+               unsigned long pfn = page_to_pfn(frag->page);
+               if (pfn > max_mapnr)
+                       return 0;
+               if(!phys_to_machine_mapping_valid(page_to_pfn(frag->page)))
+                       return 0;
+       }
+       return 1;
+}
+#else
+int skb_mapping_valid(const struct sk_buff *skb) { return 1; }
+#endif
+EXPORT_SYMBOL(skb_mapping_valid);
+
 static void sock_pipe_buf_release(struct pipe_inode_info *pipe,
                                  struct pipe_buffer *buf)
 {
@@ -1290,6 +1383,11 @@ int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len)
        if (offset > (int)skb->len - len)
                goto fault;
 
+       if (!skb_mapping_valid(skb)) {
+               skb_dump_info(skb);
+               BUG();
+       }
+
        /* Copy header. */
        if ((copy = start - offset) > 0) {
                if (copy > len)
@@ -1717,13 +1815,20 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
        int start = skb_headlen(skb);
        int i, copy = start - offset;
        int pos = 0;
+       int src_err = 0;
 
        /* Copy header. */
        if (copy > 0) {
                if (copy > len)
                        copy = len;
-               csum = csum_partial_copy_nocheck(skb->data + offset, to,
-                                                copy, csum);
+               csum = csum_partial_copy_generic(skb->data + offset, to,
+                                                copy, csum, &src_err, NULL);
+               if (src_err) {
+                       skb_dump_info(skb);
+                       printk(KERN_CRIT "checksum: CA-22751 bad skb in head\n");
+                       BUG();
+               }
+
                if ((len -= copy) == 0)
                        return csum;
                offset += copy;
@@ -1745,10 +1850,15 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
                        if (copy > len)
                                copy = len;
                        vaddr = kmap_skb_frag(frag);
-                       csum2 = csum_partial_copy_nocheck(vaddr +
+                       csum2 = csum_partial_copy_generic(vaddr +
                                                          frag->page_offset +
                                                          offset - start, to,
-                                                         copy, 0);
+                                                         copy, 0, &src_err, NULL);
+                       if (src_err) {
+                               skb_dump_info(skb);
+                               printk(KERN_CRIT "checksum: CA-22751 bad skb in frag %d\n", i);
+                               BUG();
+                       }
                        kunmap_skb_frag(vaddr);
                        csum = csum_block_add(csum, csum2, pos);
                        if (!(len -= copy))