bpf: Support new unconditional bswap instruction
authorYonghong Song <yonghong.song@linux.dev>
Fri, 28 Jul 2023 01:12:13 +0000 (18:12 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Fri, 28 Jul 2023 01:52:33 +0000 (18:52 -0700)
The existing 'be' and 'le' insns will do conditional bswap
depends on host endianness. This patch implements
unconditional bswap insns.

Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
Link: https://lore.kernel.org/r/20230728011213.3712808-1-yonghong.song@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
arch/x86/net/bpf_jit_comp.c
kernel/bpf/core.c
kernel/bpf/verifier.c

index 031ef3c..4942a4c 100644 (file)
@@ -1322,6 +1322,7 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image
                        break;
 
                case BPF_ALU | BPF_END | BPF_FROM_BE:
+               case BPF_ALU64 | BPF_END | BPF_FROM_LE:
                        switch (imm32) {
                        case 16:
                                /* Emit 'ror %ax, 8' to swap lower 2 bytes */
index c37c454..ad58697 100644 (file)
@@ -1524,6 +1524,7 @@ EXPORT_SYMBOL_GPL(__bpf_call_base);
        INSN_3(ALU64, DIV,  X),                 \
        INSN_3(ALU64, MOD,  X),                 \
        INSN_2(ALU64, NEG),                     \
+       INSN_3(ALU64, END, TO_LE),              \
        /*   Immediate based. */                \
        INSN_3(ALU64, ADD,  K),                 \
        INSN_3(ALU64, SUB,  K),                 \
@@ -1848,6 +1849,19 @@ select_insn:
                        break;
                }
                CONT;
+       ALU64_END_TO_LE:
+               switch (IMM) {
+               case 16:
+                       DST = (__force u16) __swab16(DST);
+                       break;
+               case 32:
+                       DST = (__force u32) __swab32(DST);
+                       break;
+               case 64:
+                       DST = (__force u64) __swab64(DST);
+                       break;
+               }
+               CONT;
 
        /* CALL */
        JMP_CALL:
index 7a6945b..a3dcaee 100644 (file)
@@ -3012,8 +3012,10 @@ static bool is_reg64(struct bpf_verifier_env *env, struct bpf_insn *insn,
                }
        }
 
+       if (class == BPF_ALU64 && op == BPF_END && (insn->imm == 16 || insn->imm == 32))
+               return false;
+
        if (class == BPF_ALU64 || class == BPF_JMP ||
-           /* BPF_END always use BPF_ALU class. */
            (class == BPF_ALU && op == BPF_END && insn->imm == 64))
                return true;
 
@@ -13076,7 +13078,8 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
                } else {
                        if (insn->src_reg != BPF_REG_0 || insn->off != 0 ||
                            (insn->imm != 16 && insn->imm != 32 && insn->imm != 64) ||
-                           BPF_CLASS(insn->code) == BPF_ALU64) {
+                           (BPF_CLASS(insn->code) == BPF_ALU64 &&
+                            BPF_SRC(insn->code) != BPF_TO_LE)) {
                                verbose(env, "BPF_END uses reserved fields\n");
                                return -EINVAL;
                        }