virtio: 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 <rusty@rustcorp.com.au> Acked-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
9135f1901e
commit
f35d9d8aae
3 changed files with 31 additions and 10 deletions
|
@ -83,17 +83,8 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb,
|
|||
|
||||
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) {
|
||||
|
|
|
@ -1810,5 +1810,6 @@ static inline void skb_forward_csum(struct sk_buff *skb)
|
|||
skb->ip_summed = CHECKSUM_NONE;
|
||||
}
|
||||
|
||||
bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off);
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* _LINUX_SKBUFF_H */
|
||||
|
|
|
@ -2461,6 +2461,34 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer)
|
|||
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);
|
||||
|
@ -2497,3 +2525,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);
|
||||
|
|
Loading…
Reference in a new issue