diff options
| author | Eric Dumazet <edumazet@google.com> | 2014-01-15 09:50:07 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2014-01-15 20:02:08 -0500 |
| commit | aee636c4809fa54848ff07a899b326eb1f9987a2 (patch) | |
| tree | 8f0c327f82dd7d5056dc487064f05f3f804f2fea | |
| parent | ba42fad0964a41f0830e80c1b6be49c1e6bfcc01 (diff) | |
bpf: do not use reciprocal divide
At first Jakub Zawadzki noticed that some divisions by reciprocal_divide
were not correct. (off by one in some cases)
http://www.wireshark.org/~darkjames/reciprocal-buggy.c
He could also show this with BPF:
http://www.wireshark.org/~darkjames/set-and-dump-filter-k-bug.c
The reciprocal divide in linux kernel is not generic enough,
lets remove its use in BPF, as it is not worth the pain with
current cpus.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reported-by: Jakub Zawadzki <darkjames-ws@darkjames.pl>
Cc: Mircea Gherzan <mgherzan@gmail.com>
Cc: Daniel Borkmann <dxchgb@gmail.com>
Cc: Hannes Frederic Sowa <hannes@stressinduktion.org>
Cc: Matt Evans <matt@ozlabs.org>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: David S. Miller <davem@davemloft.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | arch/arm/net/bpf_jit_32.c | 6 | ||||
| -rw-r--r-- | arch/powerpc/net/bpf_jit_comp.c | 7 | ||||
| -rw-r--r-- | arch/s390/net/bpf_jit_comp.c | 17 | ||||
| -rw-r--r-- | arch/sparc/net/bpf_jit_comp.c | 17 | ||||
| -rw-r--r-- | arch/x86/net/bpf_jit_comp.c | 14 | ||||
| -rw-r--r-- | net/core/filter.c | 30 |
6 files changed, 45 insertions, 46 deletions
diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c index 9ed155ad0f97..271b5e971568 100644 --- a/arch/arm/net/bpf_jit_32.c +++ b/arch/arm/net/bpf_jit_32.c | |||
| @@ -641,10 +641,10 @@ load_ind: | |||
| 641 | emit(ARM_MUL(r_A, r_A, r_X), ctx); | 641 | emit(ARM_MUL(r_A, r_A, r_X), ctx); |
| 642 | break; | 642 | break; |
| 643 | case BPF_S_ALU_DIV_K: | 643 | case BPF_S_ALU_DIV_K: |
| 644 | /* current k == reciprocal_value(userspace k) */ | 644 | if (k == 1) |
| 645 | break; | ||
| 645 | emit_mov_i(r_scratch, k, ctx); | 646 | emit_mov_i(r_scratch, k, ctx); |
| 646 | /* A = top 32 bits of the product */ | 647 | emit_udiv(r_A, r_A, r_scratch, ctx); |
| 647 | emit(ARM_UMULL(r_scratch, r_A, r_A, r_scratch), ctx); | ||
| 648 | break; | 648 | break; |
| 649 | case BPF_S_ALU_DIV_X: | 649 | case BPF_S_ALU_DIV_X: |
| 650 | update_on_xread(ctx); | 650 | update_on_xread(ctx); |
diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c index ac3c2a10dafd..555034f8505e 100644 --- a/arch/powerpc/net/bpf_jit_comp.c +++ b/arch/powerpc/net/bpf_jit_comp.c | |||
| @@ -223,10 +223,11 @@ static int bpf_jit_build_body(struct sk_filter *fp, u32 *image, | |||
| 223 | } | 223 | } |
| 224 | PPC_DIVWU(r_A, r_A, r_X); | 224 | PPC_DIVWU(r_A, r_A, r_X); |
| 225 | break; | 225 | break; |
| 226 | case BPF_S_ALU_DIV_K: /* A = reciprocal_divide(A, K); */ | 226 | case BPF_S_ALU_DIV_K: /* A /= K */ |
| 227 | if (K == 1) | ||
| 228 | break; | ||
| 227 | PPC_LI32(r_scratch1, K); | 229 | PPC_LI32(r_scratch1, K); |
| 228 | /* Top 32 bits of 64bit result -> A */ | 230 | PPC_DIVWU(r_A, r_A, r_scratch1); |
| 229 | PPC_MULHWU(r_A, r_A, r_scratch1); | ||
| 230 | break; | 231 | break; |
| 231 | case BPF_S_ALU_AND_X: | 232 | case BPF_S_ALU_AND_X: |
| 232 | ctx->seen |= SEEN_XREG; | 233 | ctx->seen |= SEEN_XREG; |
diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c index 16871da37371..fc0fa77728e1 100644 --- a/arch/s390/net/bpf_jit_comp.c +++ b/arch/s390/net/bpf_jit_comp.c | |||
| @@ -371,11 +371,13 @@ static int bpf_jit_insn(struct bpf_jit *jit, struct sock_filter *filter, | |||
| 371 | /* dr %r4,%r12 */ | 371 | /* dr %r4,%r12 */ |
| 372 | EMIT2(0x1d4c); | 372 | EMIT2(0x1d4c); |
| 373 | break; | 373 | break; |
| 374 | case BPF_S_ALU_DIV_K: /* A = reciprocal_divide(A, K) */ | 374 | case BPF_S_ALU_DIV_K: /* A /= K */ |
| 375 | /* m %r4,<d(K)>(%r13) */ | 375 | if (K == 1) |
| 376 | EMIT4_DISP(0x5c40d000, EMIT_CONST(K)); | 376 | break; |
| 377 | /* lr %r5,%r4 */ | 377 | /* lhi %r4,0 */ |
| 378 | EMIT2(0x1854); | 378 | EMIT4(0xa7480000); |
| 379 | /* d %r4,<d(K)>(%r13) */ | ||
| 380 | EMIT4_DISP(0x5d40d000, EMIT_CONST(K)); | ||
| 379 | break; | 381 | break; |
| 380 | case BPF_S_ALU_MOD_X: /* A %= X */ | 382 | case BPF_S_ALU_MOD_X: /* A %= X */ |
| 381 | jit->seen |= SEEN_XREG | SEEN_RET0; | 383 | jit->seen |= SEEN_XREG | SEEN_RET0; |
| @@ -391,6 +393,11 @@ static int bpf_jit_insn(struct bpf_jit *jit, struct sock_filter *filter, | |||
| 391 | EMIT2(0x1854); | 393 | EMIT2(0x1854); |
| 392 | break; | 394 | break; |
| 393 | case BPF_S_ALU_MOD_K: /* A %= K */ | 395 | case BPF_S_ALU_MOD_K: /* A %= K */ |
| 396 | if (K == 1) { | ||
| 397 | /* lhi %r5,0 */ | ||
| 398 | EMIT4(0xa7580000); | ||
| 399 | break; | ||
| 400 | } | ||
| 394 | /* lhi %r4,0 */ | 401 | /* lhi %r4,0 */ |
| 395 | EMIT4(0xa7480000); | 402 | EMIT4(0xa7480000); |
| 396 | /* d %r4,<d(K)>(%r13) */ | 403 | /* d %r4,<d(K)>(%r13) */ |
diff --git a/arch/sparc/net/bpf_jit_comp.c b/arch/sparc/net/bpf_jit_comp.c index 218b6b23c378..01fe9946d388 100644 --- a/arch/sparc/net/bpf_jit_comp.c +++ b/arch/sparc/net/bpf_jit_comp.c | |||
| @@ -497,9 +497,20 @@ void bpf_jit_compile(struct sk_filter *fp) | |||
| 497 | case BPF_S_ALU_MUL_K: /* A *= K */ | 497 | case BPF_S_ALU_MUL_K: /* A *= K */ |
| 498 | emit_alu_K(MUL, K); | 498 | emit_alu_K(MUL, K); |
| 499 | break; | 499 | break; |
| 500 | case BPF_S_ALU_DIV_K: /* A /= K */ | 500 | case BPF_S_ALU_DIV_K: /* A /= K with K != 0*/ |
| 501 | emit_alu_K(MUL, K); | 501 | if (K == 1) |
| 502 | emit_read_y(r_A); | 502 | break; |
| 503 | emit_write_y(G0); | ||
| 504 | #ifdef CONFIG_SPARC32 | ||
| 505 | /* The Sparc v8 architecture requires | ||
| 506 | * three instructions between a %y | ||
| 507 | * register write and the first use. | ||
| 508 | */ | ||
| 509 | emit_nop(); | ||
| 510 | emit_nop(); | ||
| 511 | emit_nop(); | ||
| 512 | #endif | ||
| 513 | emit_alu_K(DIV, K); | ||
| 503 | break; | 514 | break; |
| 504 | case BPF_S_ALU_DIV_X: /* A /= X; */ | 515 | case BPF_S_ALU_DIV_X: /* A /= X; */ |
| 505 | emit_cmpi(r_X, 0); | 516 | emit_cmpi(r_X, 0); |
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index 26328e800869..4ed75dd81d05 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c | |||
| @@ -359,15 +359,21 @@ void bpf_jit_compile(struct sk_filter *fp) | |||
| 359 | EMIT2(0x89, 0xd0); /* mov %edx,%eax */ | 359 | EMIT2(0x89, 0xd0); /* mov %edx,%eax */ |
| 360 | break; | 360 | break; |
| 361 | case BPF_S_ALU_MOD_K: /* A %= K; */ | 361 | case BPF_S_ALU_MOD_K: /* A %= K; */ |
| 362 | if (K == 1) { | ||
| 363 | CLEAR_A(); | ||
| 364 | break; | ||
| 365 | } | ||
| 362 | EMIT2(0x31, 0xd2); /* xor %edx,%edx */ | 366 | EMIT2(0x31, 0xd2); /* xor %edx,%edx */ |
| 363 | EMIT1(0xb9);EMIT(K, 4); /* mov imm32,%ecx */ | 367 | EMIT1(0xb9);EMIT(K, 4); /* mov imm32,%ecx */ |
| 364 | EMIT2(0xf7, 0xf1); /* div %ecx */ | 368 | EMIT2(0xf7, 0xf1); /* div %ecx */ |
| 365 | EMIT2(0x89, 0xd0); /* mov %edx,%eax */ | 369 | EMIT2(0x89, 0xd0); /* mov %edx,%eax */ |
| 366 | break; | 370 | break; |
| 367 | case BPF_S_ALU_DIV_K: /* A = reciprocal_divide(A, K); */ | 371 | case BPF_S_ALU_DIV_K: /* A /= K */ |
| 368 | EMIT3(0x48, 0x69, 0xc0); /* imul imm32,%rax,%rax */ | 372 | if (K == 1) |
| 369 | EMIT(K, 4); | 373 | break; |
| 370 | EMIT4(0x48, 0xc1, 0xe8, 0x20); /* shr $0x20,%rax */ | 374 | EMIT2(0x31, 0xd2); /* xor %edx,%edx */ |
| 375 | EMIT1(0xb9);EMIT(K, 4); /* mov imm32,%ecx */ | ||
| 376 | EMIT2(0xf7, 0xf1); /* div %ecx */ | ||
| 371 | break; | 377 | break; |
| 372 | case BPF_S_ALU_AND_X: | 378 | case BPF_S_ALU_AND_X: |
| 373 | seen |= SEEN_XREG; | 379 | seen |= SEEN_XREG; |
diff --git a/net/core/filter.c b/net/core/filter.c index 01b780856db2..ad30d626a5bd 100644 --- a/net/core/filter.c +++ b/net/core/filter.c | |||
| @@ -36,7 +36,6 @@ | |||
| 36 | #include <asm/uaccess.h> | 36 | #include <asm/uaccess.h> |
| 37 | #include <asm/unaligned.h> | 37 | #include <asm/unaligned.h> |
| 38 | #include <linux/filter.h> | 38 | #include <linux/filter.h> |
| 39 | #include <linux/reciprocal_div.h> | ||
| 40 | #include <linux/ratelimit.h> | 39 | #include <linux/ratelimit.h> |
| 41 | #include <linux/seccomp.h> | 40 | #include <linux/seccomp.h> |
| 42 | #include <linux/if_vlan.h> | 41 | #include <linux/if_vlan.h> |
| @@ -166,7 +165,7 @@ unsigned int sk_run_filter(const struct sk_buff *skb, | |||
| 166 | A /= X; | 165 | A /= X; |
| 167 | continue; | 166 | continue; |
| 168 | case BPF_S_ALU_DIV_K: | 167 | case BPF_S_ALU_DIV_K: |
| 169 | A = reciprocal_divide(A, K); | 168 | A /= K; |
| 170 | continue; | 169 | continue; |
| 171 | case BPF_S_ALU_MOD_X: | 170 | case BPF_S_ALU_MOD_X: |
| 172 | if (X == 0) | 171 | if (X == 0) |
| @@ -553,11 +552,6 @@ int sk_chk_filter(struct sock_filter *filter, unsigned int flen) | |||
| 553 | /* Some instructions need special checks */ | 552 | /* Some instructions need special checks */ |
| 554 | switch (code) { | 553 | switch (code) { |
| 555 | case BPF_S_ALU_DIV_K: | 554 | case BPF_S_ALU_DIV_K: |
| 556 | /* check for division by zero */ | ||
| 557 | if (ftest->k == 0) | ||
| 558 | return -EINVAL; | ||
| 559 | ftest->k = reciprocal_value(ftest->k); | ||
| 560 | break; | ||
| 561 | case BPF_S_ALU_MOD_K: | 555 | case BPF_S_ALU_MOD_K: |
| 562 | /* check for division by zero */ | 556 | /* check for division by zero */ |
| 563 | if (ftest->k == 0) | 557 | if (ftest->k == 0) |
| @@ -853,27 +847,7 @@ void sk_decode_filter(struct sock_filter *filt, struct sock_filter *to) | |||
| 853 | to->code = decodes[code]; | 847 | to->code = decodes[code]; |
| 854 | to->jt = filt->jt; | 848 | to->jt = filt->jt; |
| 855 | to->jf = filt->jf; | 849 | to->jf = filt->jf; |
| 856 | 850 | to->k = filt->k; | |
| 857 | if (code == BPF_S_ALU_DIV_K) { | ||
| 858 | /* | ||
| 859 | * When loaded this rule user gave us X, which was | ||
| 860 | * translated into R = r(X). Now we calculate the | ||
| 861 | * RR = r(R) and report it back. If next time this | ||
| 862 | * value is loaded and RRR = r(RR) is calculated | ||
| 863 | * then the R == RRR will be true. | ||
| 864 | * | ||
| 865 | * One exception. X == 1 translates into R == 0 and | ||
| 866 | * we can't calculate RR out of it with r(). | ||
| 867 | */ | ||
| 868 | |||
| 869 | if (filt->k == 0) | ||
| 870 | to->k = 1; | ||
| 871 | else | ||
| 872 | to->k = reciprocal_value(filt->k); | ||
| 873 | |||
| 874 | BUG_ON(reciprocal_value(to->k) != filt->k); | ||
| 875 | } else | ||
| 876 | to->k = filt->k; | ||
| 877 | } | 851 | } |
| 878 | 852 | ||
| 879 | int sk_get_filter(struct sock *sk, struct sock_filter __user *ubuf, unsigned int len) | 853 | int sk_get_filter(struct sock *sk, struct sock_filter __user *ubuf, unsigned int len) |
