aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/cls_u32.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched/cls_u32.c')
-rw-r--r--net/sched/cls_u32.c60
1 files changed, 43 insertions, 17 deletions
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
index 07372f60bee3..b0c2a82178af 100644
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c
@@ -31,6 +31,7 @@
31 */ 31 */
32 32
33#include <linux/module.h> 33#include <linux/module.h>
34#include <linux/slab.h>
34#include <linux/types.h> 35#include <linux/types.h>
35#include <linux/kernel.h> 36#include <linux/kernel.h>
36#include <linux/string.h> 37#include <linux/string.h>
@@ -97,11 +98,11 @@ static int u32_classify(struct sk_buff *skb, struct tcf_proto *tp, struct tcf_re
97{ 98{
98 struct { 99 struct {
99 struct tc_u_knode *knode; 100 struct tc_u_knode *knode;
100 u8 *ptr; 101 unsigned int off;
101 } stack[TC_U32_MAXDEPTH]; 102 } stack[TC_U32_MAXDEPTH];
102 103
103 struct tc_u_hnode *ht = (struct tc_u_hnode*)tp->root; 104 struct tc_u_hnode *ht = (struct tc_u_hnode*)tp->root;
104 u8 *ptr = skb_network_header(skb); 105 unsigned int off = skb_network_offset(skb);
105 struct tc_u_knode *n; 106 struct tc_u_knode *n;
106 int sdepth = 0; 107 int sdepth = 0;
107 int off2 = 0; 108 int off2 = 0;
@@ -133,8 +134,16 @@ next_knode:
133#endif 134#endif
134 135
135 for (i = n->sel.nkeys; i>0; i--, key++) { 136 for (i = n->sel.nkeys; i>0; i--, key++) {
137 int toff = off + key->off + (off2 & key->offmask);
138 __be32 *data, _data;
136 139
137 if ((*(__be32*)(ptr+key->off+(off2&key->offmask))^key->val)&key->mask) { 140 if (skb_headroom(skb) + toff > INT_MAX)
141 goto out;
142
143 data = skb_header_pointer(skb, toff, 4, &_data);
144 if (!data)
145 goto out;
146 if ((*data ^ key->val) & key->mask) {
138 n = n->next; 147 n = n->next;
139 goto next_knode; 148 goto next_knode;
140 } 149 }
@@ -173,29 +182,45 @@ check_terminal:
173 if (sdepth >= TC_U32_MAXDEPTH) 182 if (sdepth >= TC_U32_MAXDEPTH)
174 goto deadloop; 183 goto deadloop;
175 stack[sdepth].knode = n; 184 stack[sdepth].knode = n;
176 stack[sdepth].ptr = ptr; 185 stack[sdepth].off = off;
177 sdepth++; 186 sdepth++;
178 187
179 ht = n->ht_down; 188 ht = n->ht_down;
180 sel = 0; 189 sel = 0;
181 if (ht->divisor) 190 if (ht->divisor) {
182 sel = ht->divisor&u32_hash_fold(*(__be32*)(ptr+n->sel.hoff), &n->sel,n->fshift); 191 __be32 *data, _data;
183 192
193 data = skb_header_pointer(skb, off + n->sel.hoff, 4,
194 &_data);
195 if (!data)
196 goto out;
197 sel = ht->divisor & u32_hash_fold(*data, &n->sel,
198 n->fshift);
199 }
184 if (!(n->sel.flags&(TC_U32_VAROFFSET|TC_U32_OFFSET|TC_U32_EAT))) 200 if (!(n->sel.flags&(TC_U32_VAROFFSET|TC_U32_OFFSET|TC_U32_EAT)))
185 goto next_ht; 201 goto next_ht;
186 202
187 if (n->sel.flags&(TC_U32_OFFSET|TC_U32_VAROFFSET)) { 203 if (n->sel.flags&(TC_U32_OFFSET|TC_U32_VAROFFSET)) {
188 off2 = n->sel.off + 3; 204 off2 = n->sel.off + 3;
189 if (n->sel.flags&TC_U32_VAROFFSET) 205 if (n->sel.flags & TC_U32_VAROFFSET) {
190 off2 += ntohs(n->sel.offmask & *(__be16*)(ptr+n->sel.offoff)) >>n->sel.offshift; 206 __be16 *data, _data;
207
208 data = skb_header_pointer(skb,
209 off + n->sel.offoff,
210 2, &_data);
211 if (!data)
212 goto out;
213 off2 += ntohs(n->sel.offmask & *data) >>
214 n->sel.offshift;
215 }
191 off2 &= ~3; 216 off2 &= ~3;
192 } 217 }
193 if (n->sel.flags&TC_U32_EAT) { 218 if (n->sel.flags&TC_U32_EAT) {
194 ptr += off2; 219 off += off2;
195 off2 = 0; 220 off2 = 0;
196 } 221 }
197 222
198 if (ptr < skb_tail_pointer(skb)) 223 if (off < skb->len)
199 goto next_ht; 224 goto next_ht;
200 } 225 }
201 226
@@ -203,14 +228,15 @@ check_terminal:
203 if (sdepth--) { 228 if (sdepth--) {
204 n = stack[sdepth].knode; 229 n = stack[sdepth].knode;
205 ht = n->ht_up; 230 ht = n->ht_up;
206 ptr = stack[sdepth].ptr; 231 off = stack[sdepth].off;
207 goto check_terminal; 232 goto check_terminal;
208 } 233 }
234out:
209 return -1; 235 return -1;
210 236
211deadloop: 237deadloop:
212 if (net_ratelimit()) 238 if (net_ratelimit())
213 printk("cls_u32: dead loop\n"); 239 printk(KERN_WARNING "cls_u32: dead loop\n");
214 return -1; 240 return -1;
215} 241}
216 242
@@ -767,15 +793,15 @@ static struct tcf_proto_ops cls_u32_ops __read_mostly = {
767 793
768static int __init init_u32(void) 794static int __init init_u32(void)
769{ 795{
770 printk("u32 classifier\n"); 796 pr_info("u32 classifier\n");
771#ifdef CONFIG_CLS_U32_PERF 797#ifdef CONFIG_CLS_U32_PERF
772 printk(" Performance counters on\n"); 798 pr_info(" Performance counters on\n");
773#endif 799#endif
774#ifdef CONFIG_NET_CLS_IND 800#ifdef CONFIG_NET_CLS_IND
775 printk(" input device check on \n"); 801 pr_info(" input device check on\n");
776#endif 802#endif
777#ifdef CONFIG_NET_CLS_ACT 803#ifdef CONFIG_NET_CLS_ACT
778 printk(" Actions configured \n"); 804 pr_info(" Actions configured\n");
779#endif 805#endif
780 return register_tcf_proto_ops(&cls_u32_ops); 806 return register_tcf_proto_ops(&cls_u32_ops);
781} 807}