Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpf: fix 64-bit divide

ALU64_DIV instruction should be dividing 64-bit by 64-bit,
whereas do_div() does 64-bit by 32-bit divide.
x64 and arm64 JITs correctly implement 64 by 64 unsigned divide.
llvm BPF backend emits code assuming that ALU64_DIV does 64 by 64.

Fixes: 89aa075832b0 ("net: sock: allow eBPF programs to be attached to sockets")
Reported-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: Alexei Starovoitov <ast@plumgrid.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Alexei Starovoitov and committed by
David S. Miller
876a7ae6 8e046d68

+6 -6
+6 -6
kernel/bpf/core.c
··· 357 357 ALU64_MOD_X: 358 358 if (unlikely(SRC == 0)) 359 359 return 0; 360 - tmp = DST; 361 - DST = do_div(tmp, SRC); 360 + div64_u64_rem(DST, SRC, &tmp); 361 + DST = tmp; 362 362 CONT; 363 363 ALU_MOD_X: 364 364 if (unlikely(SRC == 0)) ··· 367 367 DST = do_div(tmp, (u32) SRC); 368 368 CONT; 369 369 ALU64_MOD_K: 370 - tmp = DST; 371 - DST = do_div(tmp, IMM); 370 + div64_u64_rem(DST, IMM, &tmp); 371 + DST = tmp; 372 372 CONT; 373 373 ALU_MOD_K: 374 374 tmp = (u32) DST; ··· 377 377 ALU64_DIV_X: 378 378 if (unlikely(SRC == 0)) 379 379 return 0; 380 - do_div(DST, SRC); 380 + DST = div64_u64(DST, SRC); 381 381 CONT; 382 382 ALU_DIV_X: 383 383 if (unlikely(SRC == 0)) ··· 387 387 DST = (u32) tmp; 388 388 CONT; 389 389 ALU64_DIV_K: 390 - do_div(DST, IMM); 390 + DST = div64_u64(DST, IMM); 391 391 CONT; 392 392 ALU_DIV_K: 393 393 tmp = (u32) DST;