diff options
author | Daniel Borkmann <dborkman@redhat.com> | 2014-04-04 19:04:03 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-04-07 12:54:39 -0400 |
commit | 5f9fde5f799df7156eeb3fa58282e9fd2f38a5f8 (patch) | |
tree | 26556f3c6534b9f725615d7db4a3772338add528 /net | |
parent | d80e773f16f66a610e04f6875d4da84e74a8fb6c (diff) |
net: filter: be more defensive on div/mod by X==0
The old interpreter behaviour was that we returned with 0
whenever we found a division by 0 would take place. In the new
interpreter we would currently just skip that instead and
continue execution.
It's true that a value of 0 as return might not be appropriate
in all cases, but current users (socket filters -> drop
packet, seccomp -> SECCOMP_RET_KILL, cls_bpf -> unclassified,
etc) seem fine with that behaviour. Better this than undefined
BPF program behaviour as it's expected that A contains the
result of the division. In future, as more use cases open up,
we could further adapt this return value to our needs, if
necessary.
So reintroduce return of 0 for division by 0 as in the old
interpreter. Also in case of K which is guaranteed to be 32bit
wide, sk_chk_filter() already takes care of preventing division
by 0 invoked through K, so we can generally spare us these tests.
Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
Reviewed-by: Alexei Starovoitov <ast@plumgrid.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/core/filter.c | 32 |
1 files changed, 16 insertions, 16 deletions
diff --git a/net/core/filter.c b/net/core/filter.c index 765556ba32ef..e08b3822c72a 100644 --- a/net/core/filter.c +++ b/net/core/filter.c | |||
@@ -295,43 +295,43 @@ select_insn: | |||
295 | (*(s64 *) &A) >>= K; | 295 | (*(s64 *) &A) >>= K; |
296 | CONT; | 296 | CONT; |
297 | BPF_ALU64_BPF_MOD_BPF_X: | 297 | BPF_ALU64_BPF_MOD_BPF_X: |
298 | if (unlikely(X == 0)) | ||
299 | return 0; | ||
298 | tmp = A; | 300 | tmp = A; |
299 | if (X) | 301 | A = do_div(tmp, X); |
300 | A = do_div(tmp, X); | ||
301 | CONT; | 302 | CONT; |
302 | BPF_ALU_BPF_MOD_BPF_X: | 303 | BPF_ALU_BPF_MOD_BPF_X: |
304 | if (unlikely(X == 0)) | ||
305 | return 0; | ||
303 | tmp = (u32) A; | 306 | tmp = (u32) A; |
304 | if (X) | 307 | A = do_div(tmp, (u32) X); |
305 | A = do_div(tmp, (u32) X); | ||
306 | CONT; | 308 | CONT; |
307 | BPF_ALU64_BPF_MOD_BPF_K: | 309 | BPF_ALU64_BPF_MOD_BPF_K: |
308 | tmp = A; | 310 | tmp = A; |
309 | if (K) | 311 | A = do_div(tmp, K); |
310 | A = do_div(tmp, K); | ||
311 | CONT; | 312 | CONT; |
312 | BPF_ALU_BPF_MOD_BPF_K: | 313 | BPF_ALU_BPF_MOD_BPF_K: |
313 | tmp = (u32) A; | 314 | tmp = (u32) A; |
314 | if (K) | 315 | A = do_div(tmp, (u32) K); |
315 | A = do_div(tmp, (u32) K); | ||
316 | CONT; | 316 | CONT; |
317 | BPF_ALU64_BPF_DIV_BPF_X: | 317 | BPF_ALU64_BPF_DIV_BPF_X: |
318 | if (X) | 318 | if (unlikely(X == 0)) |
319 | do_div(A, X); | 319 | return 0; |
320 | do_div(A, X); | ||
320 | CONT; | 321 | CONT; |
321 | BPF_ALU_BPF_DIV_BPF_X: | 322 | BPF_ALU_BPF_DIV_BPF_X: |
323 | if (unlikely(X == 0)) | ||
324 | return 0; | ||
322 | tmp = (u32) A; | 325 | tmp = (u32) A; |
323 | if (X) | 326 | do_div(tmp, (u32) X); |
324 | do_div(tmp, (u32) X); | ||
325 | A = (u32) tmp; | 327 | A = (u32) tmp; |
326 | CONT; | 328 | CONT; |
327 | BPF_ALU64_BPF_DIV_BPF_K: | 329 | BPF_ALU64_BPF_DIV_BPF_K: |
328 | if (K) | 330 | do_div(A, K); |
329 | do_div(A, K); | ||
330 | CONT; | 331 | CONT; |
331 | BPF_ALU_BPF_DIV_BPF_K: | 332 | BPF_ALU_BPF_DIV_BPF_K: |
332 | tmp = (u32) A; | 333 | tmp = (u32) A; |
333 | if (K) | 334 | do_div(tmp, (u32) K); |
334 | do_div(tmp, (u32) K); | ||
335 | A = (u32) tmp; | 335 | A = (u32) tmp; |
336 | CONT; | 336 | CONT; |
337 | BPF_ALU_BPF_END_BPF_TO_BE: | 337 | BPF_ALU_BPF_END_BPF_TO_BE: |