arm64: bpf: fix endianness conversion bugs
[firefly-linux-kernel-4.4.55.git] / arch / arm64 / net / bpf_jit_comp.c
index c81ddd4ff7f7878dd44af92a6ff0085de32ad15d..c047598b09e051cfdad2b7e1f24c21bb6e6153f8 100644 (file)
@@ -289,23 +289,41 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
        case BPF_ALU | BPF_END | BPF_FROM_BE:
 #ifdef CONFIG_CPU_BIG_ENDIAN
                if (BPF_SRC(code) == BPF_FROM_BE)
-                       break;
+                       goto emit_bswap_uxt;
 #else /* !CONFIG_CPU_BIG_ENDIAN */
                if (BPF_SRC(code) == BPF_FROM_LE)
-                       break;
+                       goto emit_bswap_uxt;
 #endif
                switch (imm) {
                case 16:
                        emit(A64_REV16(is64, dst, dst), ctx);
+                       /* zero-extend 16 bits into 64 bits */
+                       emit(A64_UXTH(is64, dst, dst), ctx);
                        break;
                case 32:
                        emit(A64_REV32(is64, dst, dst), ctx);
+                       /* upper 32 bits already cleared */
                        break;
                case 64:
                        emit(A64_REV64(dst, dst), ctx);
                        break;
                }
                break;
+emit_bswap_uxt:
+               switch (imm) {
+               case 16:
+                       /* zero-extend 16 bits into 64 bits */
+                       emit(A64_UXTH(is64, dst, dst), ctx);
+                       break;
+               case 32:
+                       /* zero-extend 32 bits into 64 bits */
+                       emit(A64_UXTW(is64, dst, dst), ctx);
+                       break;
+               case 64:
+                       /* nop */
+                       break;
+               }
+               break;
        /* dst = imm */
        case BPF_ALU | BPF_MOV | BPF_K:
        case BPF_ALU64 | BPF_MOV | BPF_K: