[IPV6]: IPV6_CHECKSUM socket option can corrupt kernel memory
So here is a patch that introduces skb_store_bits -- the opposite of skb_copy_bits, and uses them to read/write the csum field in rawv6. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:

committed by
David S. Miller

parent
fd92833a52
commit
357b40a18b
@@ -985,6 +985,94 @@ fault:
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
/**
|
||||
* skb_store_bits - store bits from kernel buffer to skb
|
||||
* @skb: destination buffer
|
||||
* @offset: offset in destination
|
||||
* @from: source buffer
|
||||
* @len: number of bytes to copy
|
||||
*
|
||||
* Copy the specified number of bytes from the source buffer to the
|
||||
* destination skb. This function handles all the messy bits of
|
||||
* traversing fragment lists and such.
|
||||
*/
|
||||
|
||||
int skb_store_bits(const struct sk_buff *skb, int offset, void *from, int len)
|
||||
{
|
||||
int i, copy;
|
||||
int start = skb_headlen(skb);
|
||||
|
||||
if (offset > (int)skb->len - len)
|
||||
goto fault;
|
||||
|
||||
if ((copy = start - offset) > 0) {
|
||||
if (copy > len)
|
||||
copy = len;
|
||||
memcpy(skb->data + offset, from, copy);
|
||||
if ((len -= copy) == 0)
|
||||
return 0;
|
||||
offset += copy;
|
||||
from += copy;
|
||||
}
|
||||
|
||||
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
|
||||
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
|
||||
int end;
|
||||
|
||||
BUG_TRAP(start <= offset + len);
|
||||
|
||||
end = start + frag->size;
|
||||
if ((copy = end - offset) > 0) {
|
||||
u8 *vaddr;
|
||||
|
||||
if (copy > len)
|
||||
copy = len;
|
||||
|
||||
vaddr = kmap_skb_frag(frag);
|
||||
memcpy(vaddr + frag->page_offset + offset - start,
|
||||
from, copy);
|
||||
kunmap_skb_frag(vaddr);
|
||||
|
||||
if ((len -= copy) == 0)
|
||||
return 0;
|
||||
offset += copy;
|
||||
from += copy;
|
||||
}
|
||||
start = end;
|
||||
}
|
||||
|
||||
if (skb_shinfo(skb)->frag_list) {
|
||||
struct sk_buff *list = skb_shinfo(skb)->frag_list;
|
||||
|
||||
for (; list; list = list->next) {
|
||||
int end;
|
||||
|
||||
BUG_TRAP(start <= offset + len);
|
||||
|
||||
end = start + list->len;
|
||||
if ((copy = end - offset) > 0) {
|
||||
if (copy > len)
|
||||
copy = len;
|
||||
if (skb_store_bits(list, offset - start,
|
||||
from, copy))
|
||||
goto fault;
|
||||
if ((len -= copy) == 0)
|
||||
return 0;
|
||||
offset += copy;
|
||||
from += copy;
|
||||
}
|
||||
start = end;
|
||||
}
|
||||
}
|
||||
if (!len)
|
||||
return 0;
|
||||
|
||||
fault:
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(skb_store_bits);
|
||||
|
||||
/* Checksum skb data. */
|
||||
|
||||
unsigned int skb_checksum(const struct sk_buff *skb, int offset,
|
||||
|
Reference in New Issue
Block a user