Merge tag 'perf-tools-for-v5.14-2021-07-01' of git://git.kernel.org/pub/scm/linux...
[linux-2.6-microblaze.git] / kernel / bpf / core.c
index 5e31ee9..034ad93 100644 (file)
@@ -1392,29 +1392,54 @@ static u64 ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn)
 select_insn:
        goto *jumptable[insn->code];
 
-       /* ALU */
-#define ALU(OPCODE, OP)                        \
-       ALU64_##OPCODE##_X:             \
-               DST = DST OP SRC;       \
-               CONT;                   \
-       ALU_##OPCODE##_X:               \
-               DST = (u32) DST OP (u32) SRC;   \
-               CONT;                   \
-       ALU64_##OPCODE##_K:             \
-               DST = DST OP IMM;               \
-               CONT;                   \
-       ALU_##OPCODE##_K:               \
-               DST = (u32) DST OP (u32) IMM;   \
+       /* Explicitly mask the register-based shift amounts with 63 or 31
+        * to avoid undefined behavior. Normally this won't affect the
+        * generated code, for example, in case of native 64 bit archs such
+        * as x86-64 or arm64, the compiler is optimizing the AND away for
+        * the interpreter. In case of JITs, each of the JIT backends compiles
+        * the BPF shift operations to machine instructions which produce
+        * implementation-defined results in such a case; the resulting
+        * contents of the register may be arbitrary, but program behaviour
+        * as a whole remains defined. In other words, in case of JIT backends,
+        * the AND must /not/ be added to the emitted LSH/RSH/ARSH translation.
+        */
+       /* ALU (shifts) */
+#define SHT(OPCODE, OP)                                        \
+       ALU64_##OPCODE##_X:                             \
+               DST = DST OP (SRC & 63);                \
+               CONT;                                   \
+       ALU_##OPCODE##_X:                               \
+               DST = (u32) DST OP ((u32) SRC & 31);    \
+               CONT;                                   \
+       ALU64_##OPCODE##_K:                             \
+               DST = DST OP IMM;                       \
+               CONT;                                   \
+       ALU_##OPCODE##_K:                               \
+               DST = (u32) DST OP (u32) IMM;           \
+               CONT;
+       /* ALU (rest) */
+#define ALU(OPCODE, OP)                                        \
+       ALU64_##OPCODE##_X:                             \
+               DST = DST OP SRC;                       \
+               CONT;                                   \
+       ALU_##OPCODE##_X:                               \
+               DST = (u32) DST OP (u32) SRC;           \
+               CONT;                                   \
+       ALU64_##OPCODE##_K:                             \
+               DST = DST OP IMM;                       \
+               CONT;                                   \
+       ALU_##OPCODE##_K:                               \
+               DST = (u32) DST OP (u32) IMM;           \
                CONT;
-
        ALU(ADD,  +)
        ALU(SUB,  -)
        ALU(AND,  &)
        ALU(OR,   |)
-       ALU(LSH, <<)
-       ALU(RSH, >>)
        ALU(XOR,  ^)
        ALU(MUL,  *)
+       SHT(LSH, <<)
+       SHT(RSH, >>)
+#undef SHT
 #undef ALU
        ALU_NEG:
                DST = (u32) -DST;
@@ -1439,13 +1464,13 @@ select_insn:
                insn++;
                CONT;
        ALU_ARSH_X:
-               DST = (u64) (u32) (((s32) DST) >> SRC);
+               DST = (u64) (u32) (((s32) DST) >> (SRC & 31));
                CONT;
        ALU_ARSH_K:
                DST = (u64) (u32) (((s32) DST) >> IMM);
                CONT;
        ALU64_ARSH_X:
-               (*(s64 *) &DST) >>= SRC;
+               (*(s64 *) &DST) >>= (SRC & 63);
                CONT;
        ALU64_ARSH_K:
                (*(s64 *) &DST) >>= IMM;