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 <holz...@linux.vnet.ibm.com>
Acked-by: Daniel Borkmann <dan...@iogearbox.net>
Signed-off-by: Alexei Starovoitov <a...@plumgrid.com>
---
The bug is old and sneaked in during the very first eBPF code drop:
Fixes: bd4cf0ed331a ("net: filter: rework/optimize internal BPF interpreter's 
instruction set")
but it's not affecting classic and shouldn't be backported further
than commit 89aa075832b0 (which is the above Fixes tag).
It was found by exhaustive tests being written by Michael Holzheu.

 kernel/bpf/core.c |   12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 4139a0f8b558..54f0e7fcd0e2 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -357,8 +357,8 @@ select_insn:
        ALU64_MOD_X:
                if (unlikely(SRC == 0))
                        return 0;
-               tmp = DST;
-               DST = do_div(tmp, SRC);
+               div64_u64_rem(DST, SRC, &tmp);
+               DST = tmp;
                CONT;
        ALU_MOD_X:
                if (unlikely(SRC == 0))
@@ -367,8 +367,8 @@ select_insn:
                DST = do_div(tmp, (u32) SRC);
                CONT;
        ALU64_MOD_K:
-               tmp = DST;
-               DST = do_div(tmp, IMM);
+               div64_u64_rem(DST, IMM, &tmp);
+               DST = tmp;
                CONT;
        ALU_MOD_K:
                tmp = (u32) DST;
@@ -377,7 +377,7 @@ select_insn:
        ALU64_DIV_X:
                if (unlikely(SRC == 0))
                        return 0;
-               do_div(DST, SRC);
+               DST = div64_u64(DST, SRC);
                CONT;
        ALU_DIV_X:
                if (unlikely(SRC == 0))
@@ -387,7 +387,7 @@ select_insn:
                DST = (u32) tmp;
                CONT;
        ALU64_DIV_K:
-               do_div(DST, IMM);
+               DST = div64_u64(DST, IMM);
                CONT;
        ALU_DIV_K:
                tmp = (u32) DST;
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to