aboutsummaryrefslogtreecommitdiffstats
path: root/net/core
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2005-04-20 01:30:14 -0400
committerDavid S. Miller <davem@davemloft.net>2005-04-20 01:30:14 -0400
commit357b40a18b04c699da1d45608436e9b76b50e251 (patch)
tree51c4480c9508a911d52a3f69bbe84ec1191fd202 /net/core
parentfd92833a52b972aafacced959f4a3f7541936a9b (diff)
[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>
Diffstat (limited to 'net/core')
-rw-r--r--net/core/skbuff.c88
1 files changed, 88 insertions, 0 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index bf02ca9f80ac..c96559574a3f 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -985,6 +985,94 @@ fault:
985 return -EFAULT; 985 return -EFAULT;
986} 986}
987 987
988/**
989 * skb_store_bits - store bits from kernel buffer to skb
990 * @skb: destination buffer
991 * @offset: offset in destination
992 * @from: source buffer
993 * @len: number of bytes to copy
994 *
995 * Copy the specified number of bytes from the source buffer to the
996 * destination skb. This function handles all the messy bits of
997 * traversing fragment lists and such.
998 */
999
1000int skb_store_bits(const struct sk_buff *skb, int offset, void *from, int len)
1001{
1002 int i, copy;
1003 int start = skb_headlen(skb);
1004
1005 if (offset > (int)skb->len - len)
1006 goto fault;
1007
1008 if ((copy = start - offset) > 0) {
1009 if (copy > len)
1010 copy = len;
1011 memcpy(skb->data + offset, from, copy);
1012 if ((len -= copy) == 0)
1013 return 0;
1014 offset += copy;
1015 from += copy;
1016 }
1017
1018 for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
1019 skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
1020 int end;
1021
1022 BUG_TRAP(start <= offset + len);
1023
1024 end = start + frag->size;
1025 if ((copy = end - offset) > 0) {
1026 u8 *vaddr;
1027
1028 if (copy > len)
1029 copy = len;
1030
1031 vaddr = kmap_skb_frag(frag);
1032 memcpy(vaddr + frag->page_offset + offset - start,
1033 from, copy);
1034 kunmap_skb_frag(vaddr);
1035
1036 if ((len -= copy) == 0)
1037 return 0;
1038 offset += copy;
1039 from += copy;
1040 }
1041 start = end;
1042 }
1043
1044 if (skb_shinfo(skb)->frag_list) {
1045 struct sk_buff *list = skb_shinfo(skb)->frag_list;
1046
1047 for (; list; list = list->next) {
1048 int end;
1049
1050 BUG_TRAP(start <= offset + len);
1051
1052 end = start + list->len;
1053 if ((copy = end - offset) > 0) {
1054 if (copy > len)
1055 copy = len;
1056 if (skb_store_bits(list, offset - start,
1057 from, copy))
1058 goto fault;
1059 if ((len -= copy) == 0)
1060 return 0;
1061 offset += copy;
1062 from += copy;
1063 }
1064 start = end;
1065 }
1066 }
1067 if (!len)
1068 return 0;
1069
1070fault:
1071 return -EFAULT;
1072}
1073
1074EXPORT_SYMBOL(skb_store_bits);
1075
988/* Checksum skb data. */ 1076/* Checksum skb data. */
989 1077
990unsigned int skb_checksum(const struct sk_buff *skb, int offset, 1078unsigned int skb_checksum(const struct sk_buff *skb, int offset,