提交 cba328fc 编写于 作者: T Tetsuo Handa 提交者: David S. Miller

filter: Optimize instruction revalidation code.

Since repeating u16 value to u8 value conversion using switch() clause's
case statement is wasteful, this patch introduces u16 to u8 mapping table
and removes most of case statements. As a result, the size of net/core/filter.o
is reduced by about 29% on x86.
Signed-off-by: NTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Acked-by: NEric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 9e50e3ac
...@@ -383,7 +383,57 @@ EXPORT_SYMBOL(sk_run_filter); ...@@ -383,7 +383,57 @@ EXPORT_SYMBOL(sk_run_filter);
*/ */
int sk_chk_filter(struct sock_filter *filter, int flen) int sk_chk_filter(struct sock_filter *filter, int flen)
{ {
struct sock_filter *ftest; /*
* Valid instructions are initialized to non-0.
* Invalid instructions are initialized to 0.
*/
static const u8 codes[] = {
[BPF_ALU|BPF_ADD|BPF_K] = BPF_S_ALU_ADD_K + 1,
[BPF_ALU|BPF_ADD|BPF_X] = BPF_S_ALU_ADD_X + 1,
[BPF_ALU|BPF_SUB|BPF_K] = BPF_S_ALU_SUB_K + 1,
[BPF_ALU|BPF_SUB|BPF_X] = BPF_S_ALU_SUB_X + 1,
[BPF_ALU|BPF_MUL|BPF_K] = BPF_S_ALU_MUL_K + 1,
[BPF_ALU|BPF_MUL|BPF_X] = BPF_S_ALU_MUL_X + 1,
[BPF_ALU|BPF_DIV|BPF_X] = BPF_S_ALU_DIV_X + 1,
[BPF_ALU|BPF_AND|BPF_K] = BPF_S_ALU_AND_K + 1,
[BPF_ALU|BPF_AND|BPF_X] = BPF_S_ALU_AND_X + 1,
[BPF_ALU|BPF_OR|BPF_K] = BPF_S_ALU_OR_K + 1,
[BPF_ALU|BPF_OR|BPF_X] = BPF_S_ALU_OR_X + 1,
[BPF_ALU|BPF_LSH|BPF_K] = BPF_S_ALU_LSH_K + 1,
[BPF_ALU|BPF_LSH|BPF_X] = BPF_S_ALU_LSH_X + 1,
[BPF_ALU|BPF_RSH|BPF_K] = BPF_S_ALU_RSH_K + 1,
[BPF_ALU|BPF_RSH|BPF_X] = BPF_S_ALU_RSH_X + 1,
[BPF_ALU|BPF_NEG] = BPF_S_ALU_NEG + 1,
[BPF_LD|BPF_W|BPF_ABS] = BPF_S_LD_W_ABS + 1,
[BPF_LD|BPF_H|BPF_ABS] = BPF_S_LD_H_ABS + 1,
[BPF_LD|BPF_B|BPF_ABS] = BPF_S_LD_B_ABS + 1,
[BPF_LD|BPF_W|BPF_LEN] = BPF_S_LD_W_LEN + 1,
[BPF_LD|BPF_W|BPF_IND] = BPF_S_LD_W_IND + 1,
[BPF_LD|BPF_H|BPF_IND] = BPF_S_LD_H_IND + 1,
[BPF_LD|BPF_B|BPF_IND] = BPF_S_LD_B_IND + 1,
[BPF_LD|BPF_IMM] = BPF_S_LD_IMM + 1,
[BPF_LDX|BPF_W|BPF_LEN] = BPF_S_LDX_W_LEN + 1,
[BPF_LDX|BPF_B|BPF_MSH] = BPF_S_LDX_B_MSH + 1,
[BPF_LDX|BPF_IMM] = BPF_S_LDX_IMM + 1,
[BPF_MISC|BPF_TAX] = BPF_S_MISC_TAX + 1,
[BPF_MISC|BPF_TXA] = BPF_S_MISC_TXA + 1,
[BPF_RET|BPF_K] = BPF_S_RET_K + 1,
[BPF_RET|BPF_A] = BPF_S_RET_A + 1,
[BPF_ALU|BPF_DIV|BPF_K] = BPF_S_ALU_DIV_K + 1,
[BPF_LD|BPF_MEM] = BPF_S_LD_MEM + 1,
[BPF_LDX|BPF_MEM] = BPF_S_LDX_MEM + 1,
[BPF_ST] = BPF_S_ST + 1,
[BPF_STX] = BPF_S_STX + 1,
[BPF_JMP|BPF_JA] = BPF_S_JMP_JA + 1,
[BPF_JMP|BPF_JEQ|BPF_K] = BPF_S_JMP_JEQ_K + 1,
[BPF_JMP|BPF_JEQ|BPF_X] = BPF_S_JMP_JEQ_X + 1,
[BPF_JMP|BPF_JGE|BPF_K] = BPF_S_JMP_JGE_K + 1,
[BPF_JMP|BPF_JGE|BPF_X] = BPF_S_JMP_JGE_X + 1,
[BPF_JMP|BPF_JGT|BPF_K] = BPF_S_JMP_JGT_K + 1,
[BPF_JMP|BPF_JGT|BPF_X] = BPF_S_JMP_JGT_X + 1,
[BPF_JMP|BPF_JSET|BPF_K] = BPF_S_JMP_JSET_K + 1,
[BPF_JMP|BPF_JSET|BPF_X] = BPF_S_JMP_JSET_X + 1,
};
int pc; int pc;
if (flen == 0 || flen > BPF_MAXINSNS) if (flen == 0 || flen > BPF_MAXINSNS)
...@@ -391,136 +441,31 @@ int sk_chk_filter(struct sock_filter *filter, int flen) ...@@ -391,136 +441,31 @@ int sk_chk_filter(struct sock_filter *filter, int flen)
/* check the filter code now */ /* check the filter code now */
for (pc = 0; pc < flen; pc++) { for (pc = 0; pc < flen; pc++) {
ftest = &filter[pc]; struct sock_filter *ftest = &filter[pc];
u16 code = ftest->code;
/* Only allow valid instructions */
switch (ftest->code) {
case BPF_ALU|BPF_ADD|BPF_K:
ftest->code = BPF_S_ALU_ADD_K;
break;
case BPF_ALU|BPF_ADD|BPF_X:
ftest->code = BPF_S_ALU_ADD_X;
break;
case BPF_ALU|BPF_SUB|BPF_K:
ftest->code = BPF_S_ALU_SUB_K;
break;
case BPF_ALU|BPF_SUB|BPF_X:
ftest->code = BPF_S_ALU_SUB_X;
break;
case BPF_ALU|BPF_MUL|BPF_K:
ftest->code = BPF_S_ALU_MUL_K;
break;
case BPF_ALU|BPF_MUL|BPF_X:
ftest->code = BPF_S_ALU_MUL_X;
break;
case BPF_ALU|BPF_DIV|BPF_X:
ftest->code = BPF_S_ALU_DIV_X;
break;
case BPF_ALU|BPF_AND|BPF_K:
ftest->code = BPF_S_ALU_AND_K;
break;
case BPF_ALU|BPF_AND|BPF_X:
ftest->code = BPF_S_ALU_AND_X;
break;
case BPF_ALU|BPF_OR|BPF_K:
ftest->code = BPF_S_ALU_OR_K;
break;
case BPF_ALU|BPF_OR|BPF_X:
ftest->code = BPF_S_ALU_OR_X;
break;
case BPF_ALU|BPF_LSH|BPF_K:
ftest->code = BPF_S_ALU_LSH_K;
break;
case BPF_ALU|BPF_LSH|BPF_X:
ftest->code = BPF_S_ALU_LSH_X;
break;
case BPF_ALU|BPF_RSH|BPF_K:
ftest->code = BPF_S_ALU_RSH_K;
break;
case BPF_ALU|BPF_RSH|BPF_X:
ftest->code = BPF_S_ALU_RSH_X;
break;
case BPF_ALU|BPF_NEG:
ftest->code = BPF_S_ALU_NEG;
break;
case BPF_LD|BPF_W|BPF_ABS:
ftest->code = BPF_S_LD_W_ABS;
break;
case BPF_LD|BPF_H|BPF_ABS:
ftest->code = BPF_S_LD_H_ABS;
break;
case BPF_LD|BPF_B|BPF_ABS:
ftest->code = BPF_S_LD_B_ABS;
break;
case BPF_LD|BPF_W|BPF_LEN:
ftest->code = BPF_S_LD_W_LEN;
break;
case BPF_LD|BPF_W|BPF_IND:
ftest->code = BPF_S_LD_W_IND;
break;
case BPF_LD|BPF_H|BPF_IND:
ftest->code = BPF_S_LD_H_IND;
break;
case BPF_LD|BPF_B|BPF_IND:
ftest->code = BPF_S_LD_B_IND;
break;
case BPF_LD|BPF_IMM:
ftest->code = BPF_S_LD_IMM;
break;
case BPF_LDX|BPF_W|BPF_LEN:
ftest->code = BPF_S_LDX_W_LEN;
break;
case BPF_LDX|BPF_B|BPF_MSH:
ftest->code = BPF_S_LDX_B_MSH;
break;
case BPF_LDX|BPF_IMM:
ftest->code = BPF_S_LDX_IMM;
break;
case BPF_MISC|BPF_TAX:
ftest->code = BPF_S_MISC_TAX;
break;
case BPF_MISC|BPF_TXA:
ftest->code = BPF_S_MISC_TXA;
break;
case BPF_RET|BPF_K:
ftest->code = BPF_S_RET_K;
break;
case BPF_RET|BPF_A:
ftest->code = BPF_S_RET_A;
break;
if (code >= ARRAY_SIZE(codes))
return -EINVAL;
code = codes[code];
/* Undo the '+ 1' in codes[] after validation. */
if (!code--)
return -EINVAL;
/* Some instructions need special checks */ /* Some instructions need special checks */
switch (code) {
case BPF_S_ALU_DIV_K:
/* check for division by zero */ /* check for division by zero */
case BPF_ALU|BPF_DIV|BPF_K:
if (ftest->k == 0) if (ftest->k == 0)
return -EINVAL; return -EINVAL;
ftest->code = BPF_S_ALU_DIV_K;
break; break;
case BPF_S_LD_MEM:
/* check for invalid memory addresses */ case BPF_S_LDX_MEM:
case BPF_LD|BPF_MEM: case BPF_S_ST:
if (ftest->k >= BPF_MEMWORDS) case BPF_S_STX:
return -EINVAL; /* check for invalid memory addresses */
ftest->code = BPF_S_LD_MEM;
break;
case BPF_LDX|BPF_MEM:
if (ftest->k >= BPF_MEMWORDS)
return -EINVAL;
ftest->code = BPF_S_LDX_MEM;
break;
case BPF_ST:
if (ftest->k >= BPF_MEMWORDS)
return -EINVAL;
ftest->code = BPF_S_ST;
break;
case BPF_STX:
if (ftest->k >= BPF_MEMWORDS) if (ftest->k >= BPF_MEMWORDS)
return -EINVAL; return -EINVAL;
ftest->code = BPF_S_STX;
break; break;
case BPF_S_JMP_JA:
case BPF_JMP|BPF_JA:
/* /*
* Note, the large ftest->k might cause loops. * Note, the large ftest->k might cause loops.
* Compare this with conditional jumps below, * Compare this with conditional jumps below,
...@@ -528,40 +473,7 @@ int sk_chk_filter(struct sock_filter *filter, int flen) ...@@ -528,40 +473,7 @@ int sk_chk_filter(struct sock_filter *filter, int flen)
*/ */
if (ftest->k >= (unsigned)(flen-pc-1)) if (ftest->k >= (unsigned)(flen-pc-1))
return -EINVAL; return -EINVAL;
ftest->code = BPF_S_JMP_JA;
break;
case BPF_JMP|BPF_JEQ|BPF_K:
ftest->code = BPF_S_JMP_JEQ_K;
break;
case BPF_JMP|BPF_JEQ|BPF_X:
ftest->code = BPF_S_JMP_JEQ_X;
break; break;
case BPF_JMP|BPF_JGE|BPF_K:
ftest->code = BPF_S_JMP_JGE_K;
break;
case BPF_JMP|BPF_JGE|BPF_X:
ftest->code = BPF_S_JMP_JGE_X;
break;
case BPF_JMP|BPF_JGT|BPF_K:
ftest->code = BPF_S_JMP_JGT_K;
break;
case BPF_JMP|BPF_JGT|BPF_X:
ftest->code = BPF_S_JMP_JGT_X;
break;
case BPF_JMP|BPF_JSET|BPF_K:
ftest->code = BPF_S_JMP_JSET_K;
break;
case BPF_JMP|BPF_JSET|BPF_X:
ftest->code = BPF_S_JMP_JSET_X;
break;
default:
return -EINVAL;
}
/* for conditionals both must be safe */
switch (ftest->code) {
case BPF_S_JMP_JEQ_K: case BPF_S_JMP_JEQ_K:
case BPF_S_JMP_JEQ_X: case BPF_S_JMP_JEQ_X:
case BPF_S_JMP_JGE_K: case BPF_S_JMP_JGE_K:
...@@ -570,10 +482,13 @@ int sk_chk_filter(struct sock_filter *filter, int flen) ...@@ -570,10 +482,13 @@ int sk_chk_filter(struct sock_filter *filter, int flen)
case BPF_S_JMP_JGT_X: case BPF_S_JMP_JGT_X:
case BPF_S_JMP_JSET_X: case BPF_S_JMP_JSET_X:
case BPF_S_JMP_JSET_K: case BPF_S_JMP_JSET_K:
/* for conditionals both must be safe */
if (pc + ftest->jt + 1 >= flen || if (pc + ftest->jt + 1 >= flen ||
pc + ftest->jf + 1 >= flen) pc + ftest->jf + 1 >= flen)
return -EINVAL; return -EINVAL;
break;
} }
ftest->code = code;
} }
/* last instruction must be a RET code */ /* last instruction must be a RET code */
...@@ -581,10 +496,8 @@ int sk_chk_filter(struct sock_filter *filter, int flen) ...@@ -581,10 +496,8 @@ int sk_chk_filter(struct sock_filter *filter, int flen)
case BPF_S_RET_K: case BPF_S_RET_K:
case BPF_S_RET_A: case BPF_S_RET_A:
return 0; return 0;
break; }
default: return -EINVAL;
return -EINVAL;
}
} }
EXPORT_SYMBOL(sk_chk_filter); EXPORT_SYMBOL(sk_chk_filter);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册