Implement skb_partial_csum_set, for setting partial csums on untrusted packets.
Use it in virtio_net (replacing buggy version there), it's also going to be used by TAP for partial csum support. Signed-off-by: Rusty Russell <[EMAIL PROTECTED]> Acked-by: David S. Miller <[EMAIL PROTECTED]> --- drivers/net/virtio_net.c | 11 +---------- include/linux/skbuff.h | 1 + net/core/skbuff.c | 29 +++++++++++++++++++++++++++++ 3 files changed, 31 insertions(+), 10 deletions(-) diff -r 72be3d596d31 include/linux/skbuff.h --- a/include/linux/skbuff.h Wed Jan 09 15:57:40 2008 +1100 +++ b/include/linux/skbuff.h Wed Jan 09 16:56:41 2008 +1100 @@ -1804,5 +1804,6 @@ static inline void skb_forward_csum(stru skb->ip_summed = CHECKSUM_NONE; } +bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off); #endif /* __KERNEL__ */ #endif /* _LINUX_SKBUFF_H */ diff -r 72be3d596d31 net/core/skbuff.c --- a/net/core/skbuff.c Wed Jan 09 15:57:40 2008 +1100 +++ b/net/core/skbuff.c Wed Jan 09 16:56:41 2008 +1100 @@ -2214,6 +2214,34 @@ int skb_cow_data(struct sk_buff *skb, in return elt; } +/** + * skb_partial_csum_set - set up and verify partial csum values for packet + * @skb: the skb to set + * @start: the number of bytes after skb->data to start checksumming. + * @off: the offset from start to place the checksum. + * + * For untrusted partially-checksummed packets, we need to make sure the values + * for skb->csum_start and skb->csum_offset are valid so we don't oops. + * + * This function checks and sets those values and skb->ip_summed: if this + * returns false you should drop the packet. + */ +bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off) +{ + if (unlikely(start > skb->len - 2) || + unlikely((int)start + off > skb->len - 2)) { + if (net_ratelimit()) + printk(KERN_WARNING + "bad partial csum: csum=%u/%u len=%u\n", + start, off, skb->len); + return false; + } + skb->ip_summed = CHECKSUM_PARTIAL; + skb->csum_start = skb_headroom(skb) + start; + skb->csum_offset = off; + return true; +} + EXPORT_SYMBOL(___pskb_trim); EXPORT_SYMBOL(__kfree_skb); EXPORT_SYMBOL(kfree_skb); @@ -2250,3 +2278,4 @@ EXPORT_SYMBOL(skb_append_datato_frags); EXPORT_SYMBOL_GPL(skb_to_sgvec); EXPORT_SYMBOL_GPL(skb_cow_data); +EXPORT_SYMBOL_GPL(skb_partial_csum_set); diff -r 72be3d596d31 drivers/net/virtio_net.c --- a/drivers/net/virtio_net.c Wed Jan 09 15:57:40 2008 +1100 +++ b/drivers/net/virtio_net.c Wed Jan 09 16:56:41 2008 +1100 @@ -89,17 +89,8 @@ static void receive_skb(struct net_devic if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) { pr_debug("Needs csum!\n"); - skb->ip_summed = CHECKSUM_PARTIAL; - skb->csum_start = hdr->csum_start; - skb->csum_offset = hdr->csum_offset; - if (skb->csum_start > skb->len - 2 - || skb->csum_offset > skb->len - 2) { - if (net_ratelimit()) - printk(KERN_WARNING "%s: csum=%u/%u len=%u\n", - dev->name, skb->csum_start, - skb->csum_offset, skb->len); + if (!skb_partial_csum_set(skb,hdr->csum_start,hdr->csum_offset)) goto frame_err; - } } if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) { -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html