From: Patrick McHardy
> Kris Katterjohn wrote:
> > --- x/net/core/filter.c     2005-12-28 16:51:35.000000000 -0600
> > +++ y/net/core/filter.c     2005-12-28 16:53:32.000000000 -0600
> > @@ -250,7 +250,7 @@ load_b:
> >                     mem[fentry->k] = X;
> >                     continue;
> >             default:
> > -                   /* Invalid instruction counts as RET */
> > +                   /* Should never be reached */
> 
> This stuff has had a number of bad bugs before, if it can't be reached,
> please call BUG or something similar instead of silently ignoring the
> error.

I'll just remove the default label and return statement.
 
> >                     return 0;
> >             }
> >  
> > @@ -300,38 +300,87 @@ int sk_chk_filter(struct sock_filter *fi
> >     for (pc = 0; pc < flen; pc++) {
> >             /* all jumps are forward as they are not signed */
> >             ftest = &filter[pc];
> > -           if (BPF_CLASS(ftest->code) == BPF_JMP) {
> > -                   /* but they mustn't jump off the end */
> > -                   if (BPF_OP(ftest->code) == BPF_JA) {
> > -                           /*
> > -                            * Note, the large ftest->k might cause loops.
> > -                            * Compare this with conditional jumps below,
> > -                            * where offsets are limited. --ANK (981016)
> > -                            */
> > -                           if (ftest->k >= (unsigned)(flen-pc-1))
> > -                                   return -EINVAL;
> > -                   } else {
> > -                           /* for conditionals both must be safe */
> > -                           if (pc + ftest->jt +1 >= flen ||
> > -                               pc + ftest->jf +1 >= flen)
> > -                                   return -EINVAL;
> > -                   }
> > -           }
> >  
> > -           /* check for division by zero   -Kris Katterjohn 2005-10-30 */
> > -           if (ftest->code == (BPF_ALU|BPF_DIV|BPF_K) && ftest->k == 0)
> > -                   return -EINVAL;
> > +           /* Only allow valid instructions -Kris Katterjohn 2005-12-28 */
> > +           switch (ftest->code) {
> > +           case BPF_ALU|BPF_ADD|BPF_K:
> > +           case BPF_ALU|BPF_ADD|BPF_X:
> > +           case BPF_ALU|BPF_SUB|BPF_K:
> > +           case BPF_ALU|BPF_SUB|BPF_X:
> > +           case BPF_ALU|BPF_MUL|BPF_K:
> > +           case BPF_ALU|BPF_MUL|BPF_X:
> > +           case BPF_ALU|BPF_DIV|BPF_X:
> > +           case BPF_ALU|BPF_AND|BPF_K:
> > +           case BPF_ALU|BPF_AND|BPF_X:
> > +           case BPF_ALU|BPF_OR|BPF_K:
> > +           case BPF_ALU|BPF_OR|BPF_X:
> > +           case BPF_ALU|BPF_LSH|BPF_K:
> > +           case BPF_ALU|BPF_LSH|BPF_X:
> > +           case BPF_ALU|BPF_RSH|BPF_K:
> > +           case BPF_ALU|BPF_RSH|BPF_X:
> > +           case BPF_ALU|BPF_NEG:
> > +           case BPF_LD|BPF_W|BPF_ABS:
> > +           case BPF_LD|BPF_H|BPF_ABS:
> > +           case BPF_LD|BPF_B|BPF_ABS:
> > +           case BPF_LD|BPF_W|BPF_LEN:
> > +           case BPF_LD|BPF_W|BPF_IND:
> > +           case BPF_LD|BPF_H|BPF_IND:
> > +           case BPF_LD|BPF_B|BPF_IND:
> > +           case BPF_LD|BPF_IMM:
> > +           case BPF_LDX|BPF_W|BPF_LEN:
> > +           case BPF_LDX|BPF_B|BPF_MSH:
> > +           case BPF_LDX|BPF_IMM:
> > +           case BPF_MISC|BPF_TAX:
> > +           case BPF_MISC|BPF_TXA:
> > +           case BPF_RET|BPF_K:
> > +           case BPF_RET|BPF_A:
> > +                   break;
> 
> I think this could be done more readable using BPF_CLASS().

If it's done with BPF_CLASS, then it would either be a lot longer or not check
for only valid instructions. i.e. You'd check for BPF_RET, but not
BPF_RET|BPF_K and BPF_RET|BPF_X which are the actual instructions. I thought
about doing with with BPF_CLASS, but this way is shorter and checks for 
everything.

> > +
> > +           /* Some instructions need special checks */
> > +
> > +           case BPF_ALU|BPF_DIV|BPF_K:
> > +                   /* check for division by zero 
> > +                    *    -Kris Katterjohn 2005-10-30
> 
> Please don't annotate every single comment with your name and date,
> especially not totally useless ones such as this. If you want some
> record of your changes inside the file, place it somewhere at the
> top, where it doesn't clutter up the code.

Okay. That was my first change to the kernel, and I didn't think I'd be doing
more to it to clutter it up.

> > +                    */
> > +                   if (ftest->k == 0)
> > +                           return -EINVAL;
> 
> Why do you keep the runtime check then?

The runtime is for BPF_ALU|BPF_DIV|BPF_X, not BPF_ALU|BPF_DIV|BPF_K. The BPF_K
instruction is constant and can be checked for at any time, but with BPF_X,
it changes with each packet and must be checked at runtime.


--- x/net/core/filter.c 2005-12-28 16:51:35.000000000 -0600
+++ y/net/core/filter.c 2005-12-29 12:19:48.000000000 -0600
@@ -13,6 +13,7 @@
  * 2 of the License, or (at your option) any later version.
  *
  * Andi Kleen - Fix a few bad bugs and races.
+ * Kris Katterjohn 2005-12-28 - Added many additional checks in sk_chk_filter()
  */
 
 #include <linux/module.h>
@@ -249,9 +250,6 @@ load_b:
                case BPF_STX:
                        mem[fentry->k] = X;
                        continue;
-               default:
-                       /* Invalid instruction counts as RET */
-                       return 0;
                }
 
                /*
@@ -300,38 +298,85 @@ int sk_chk_filter(struct sock_filter *fi
        for (pc = 0; pc < flen; pc++) {
                /* all jumps are forward as they are not signed */
                ftest = &filter[pc];
-               if (BPF_CLASS(ftest->code) == BPF_JMP) {
-                       /* but they mustn't jump off the end */
-                       if (BPF_OP(ftest->code) == BPF_JA) {
-                               /*
-                                * Note, the large ftest->k might cause loops.
-                                * Compare this with conditional jumps below,
-                                * where offsets are limited. --ANK (981016)
-                                */
-                               if (ftest->k >= (unsigned)(flen-pc-1))
-                                       return -EINVAL;
-                       } else {
-                               /* for conditionals both must be safe */
-                               if (pc + ftest->jt +1 >= flen ||
-                                   pc + ftest->jf +1 >= flen)
-                                       return -EINVAL;
-                       }
-               }
 
-               /* check for division by zero   -Kris Katterjohn 2005-10-30 */
-               if (ftest->code == (BPF_ALU|BPF_DIV|BPF_K) && ftest->k == 0)
-                       return -EINVAL;
+               /* Only allow valid instructions */
+               switch (ftest->code) {
+               case BPF_ALU|BPF_ADD|BPF_K:
+               case BPF_ALU|BPF_ADD|BPF_X:
+               case BPF_ALU|BPF_SUB|BPF_K:
+               case BPF_ALU|BPF_SUB|BPF_X:
+               case BPF_ALU|BPF_MUL|BPF_K:
+               case BPF_ALU|BPF_MUL|BPF_X:
+               case BPF_ALU|BPF_DIV|BPF_X:
+               case BPF_ALU|BPF_AND|BPF_K:
+               case BPF_ALU|BPF_AND|BPF_X:
+               case BPF_ALU|BPF_OR|BPF_K:
+               case BPF_ALU|BPF_OR|BPF_X:
+               case BPF_ALU|BPF_LSH|BPF_K:
+               case BPF_ALU|BPF_LSH|BPF_X:
+               case BPF_ALU|BPF_RSH|BPF_K:
+               case BPF_ALU|BPF_RSH|BPF_X:
+               case BPF_ALU|BPF_NEG:
+               case BPF_LD|BPF_W|BPF_ABS:
+               case BPF_LD|BPF_H|BPF_ABS:
+               case BPF_LD|BPF_B|BPF_ABS:
+               case BPF_LD|BPF_W|BPF_LEN:
+               case BPF_LD|BPF_W|BPF_IND:
+               case BPF_LD|BPF_H|BPF_IND:
+               case BPF_LD|BPF_B|BPF_IND:
+               case BPF_LD|BPF_IMM:
+               case BPF_LDX|BPF_W|BPF_LEN:
+               case BPF_LDX|BPF_B|BPF_MSH:
+               case BPF_LDX|BPF_IMM:
+               case BPF_MISC|BPF_TAX:
+               case BPF_MISC|BPF_TXA:
+               case BPF_RET|BPF_K:
+               case BPF_RET|BPF_A:
+                       break;
+
+               /* Some instructions need special checks */
 
-               /* check that memory operations use valid addresses. */
-               if (ftest->k >= BPF_MEMWORDS) {
-                       /* but it might not be a memory operation... */
-                       switch (ftest->code) {
-                       case BPF_ST:    
-                       case BPF_STX:   
-                       case BPF_LD|BPF_MEM:    
-                       case BPF_LDX|BPF_MEM:   
+               case BPF_ALU|BPF_DIV|BPF_K:
+                       /* check for division by zero */
+                       if (ftest->k == 0)
                                return -EINVAL;
-                       }
+                       break;
+
+               case BPF_LD|BPF_MEM:
+               case BPF_LDX|BPF_MEM:
+               case BPF_ST:
+               case BPF_STX:
+                       /* check for invalid memory addresses */
+                       if (ftest->k >= BPF_MEMWORDS)
+                               return -EINVAL;
+                       break;
+
+               case BPF_JMP|BPF_JA:
+                       /*
+                        * Note, the large ftest->k might cause loops.
+                        * Compare this with conditional jumps below,
+                        * where offsets are limited. --ANK (981016)
+                        */
+                       if (ftest->k >= (unsigned)(flen-pc-1))
+                               return -EINVAL;
+                       break;
+
+               case BPF_JMP|BPF_JEQ|BPF_K:
+               case BPF_JMP|BPF_JEQ|BPF_X:
+               case BPF_JMP|BPF_JGE|BPF_K:
+               case BPF_JMP|BPF_JGE|BPF_X:
+               case BPF_JMP|BPF_JGT|BPF_K:
+               case BPF_JMP|BPF_JGT|BPF_X:
+               case BPF_JMP|BPF_JSET|BPF_K:
+               case BPF_JMP|BPF_JSET|BPF_X:
+                       /* for conditionals both must be safe */
+                       if (pc + ftest->jt + 1 >= flen ||
+                           pc + ftest->jf + 1 >= flen)
+                               return -EINVAL;
+                       break;
+
+               default:
+                       return -EINVAL;
                }
        }
 


-
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

Reply via email to