diff options
author | Luke Nelson <lukenels@cs.washington.edu> | 2019-06-29 01:57:50 -0400 |
---|---|---|
committer | Daniel Borkmann <daniel@iogearbox.net> | 2019-07-03 05:14:28 -0400 |
commit | 6fa632e719eec4d1b1ebf3ddc0b2d667997b057b (patch) | |
tree | d2d6f3e67778c27a1e27c37059ac1b0a31122fd2 | |
parent | 68a8357ec15bdce55266e9fba8b8b3b8143fa7d2 (diff) |
bpf, x32: Fix bug with ALU64 {LSH, RSH, ARSH} BPF_K shift by 0
The current x32 BPF JIT does not correctly compile shift operations when
the immediate shift amount is 0. The expected behavior is for this to
be a no-op.
The following program demonstrates the bug. The expexceted result is 1,
but the current JITed code returns 2.
r0 = 1
r1 = 1
r1 <<= 0
if r1 == 1 goto end
r0 = 2
end:
exit
This patch simplifies the code and fixes the bug.
Fixes: 03f5781be2c7 ("bpf, x86_32: add eBPF JIT compiler for ia32")
Co-developed-by: Xi Wang <xi.wang@gmail.com>
Signed-off-by: Xi Wang <xi.wang@gmail.com>
Signed-off-by: Luke Nelson <luke.r.nels@gmail.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
-rw-r--r-- | arch/x86/net/bpf_jit_comp32.c | 63 |
1 files changed, 6 insertions, 57 deletions
diff --git a/arch/x86/net/bpf_jit_comp32.c b/arch/x86/net/bpf_jit_comp32.c index f34ef513f4f9..1d12d2174085 100644 --- a/arch/x86/net/bpf_jit_comp32.c +++ b/arch/x86/net/bpf_jit_comp32.c | |||
@@ -894,27 +894,10 @@ static inline void emit_ia32_lsh_i64(const u8 dst[], const u32 val, | |||
894 | } | 894 | } |
895 | /* Do LSH operation */ | 895 | /* Do LSH operation */ |
896 | if (val < 32) { | 896 | if (val < 32) { |
897 | /* shl dreg_hi,imm8 */ | 897 | /* shld dreg_hi,dreg_lo,imm8 */ |
898 | EMIT3(0xC1, add_1reg(0xE0, dreg_hi), val); | 898 | EMIT4(0x0F, 0xA4, add_2reg(0xC0, dreg_hi, dreg_lo), val); |
899 | /* mov ebx,dreg_lo */ | ||
900 | EMIT2(0x8B, add_2reg(0xC0, dreg_lo, IA32_EBX)); | ||
901 | /* shl dreg_lo,imm8 */ | 899 | /* shl dreg_lo,imm8 */ |
902 | EMIT3(0xC1, add_1reg(0xE0, dreg_lo), val); | 900 | EMIT3(0xC1, add_1reg(0xE0, dreg_lo), val); |
903 | |||
904 | /* IA32_ECX = 32 - val */ | ||
905 | /* mov ecx,val */ | ||
906 | EMIT2(0xB1, val); | ||
907 | /* movzx ecx,ecx */ | ||
908 | EMIT3(0x0F, 0xB6, add_2reg(0xC0, IA32_ECX, IA32_ECX)); | ||
909 | /* neg ecx */ | ||
910 | EMIT2(0xF7, add_1reg(0xD8, IA32_ECX)); | ||
911 | /* add ecx,32 */ | ||
912 | EMIT3(0x83, add_1reg(0xC0, IA32_ECX), 32); | ||
913 | |||
914 | /* shr ebx,cl */ | ||
915 | EMIT2(0xD3, add_1reg(0xE8, IA32_EBX)); | ||
916 | /* or dreg_hi,ebx */ | ||
917 | EMIT2(0x09, add_2reg(0xC0, dreg_hi, IA32_EBX)); | ||
918 | } else if (val >= 32 && val < 64) { | 901 | } else if (val >= 32 && val < 64) { |
919 | u32 value = val - 32; | 902 | u32 value = val - 32; |
920 | 903 | ||
@@ -960,27 +943,10 @@ static inline void emit_ia32_rsh_i64(const u8 dst[], const u32 val, | |||
960 | 943 | ||
961 | /* Do RSH operation */ | 944 | /* Do RSH operation */ |
962 | if (val < 32) { | 945 | if (val < 32) { |
963 | /* shr dreg_lo,imm8 */ | 946 | /* shrd dreg_lo,dreg_hi,imm8 */ |
964 | EMIT3(0xC1, add_1reg(0xE8, dreg_lo), val); | 947 | EMIT4(0x0F, 0xAC, add_2reg(0xC0, dreg_lo, dreg_hi), val); |
965 | /* mov ebx,dreg_hi */ | ||
966 | EMIT2(0x8B, add_2reg(0xC0, dreg_hi, IA32_EBX)); | ||
967 | /* shr dreg_hi,imm8 */ | 948 | /* shr dreg_hi,imm8 */ |
968 | EMIT3(0xC1, add_1reg(0xE8, dreg_hi), val); | 949 | EMIT3(0xC1, add_1reg(0xE8, dreg_hi), val); |
969 | |||
970 | /* IA32_ECX = 32 - val */ | ||
971 | /* mov ecx,val */ | ||
972 | EMIT2(0xB1, val); | ||
973 | /* movzx ecx,ecx */ | ||
974 | EMIT3(0x0F, 0xB6, add_2reg(0xC0, IA32_ECX, IA32_ECX)); | ||
975 | /* neg ecx */ | ||
976 | EMIT2(0xF7, add_1reg(0xD8, IA32_ECX)); | ||
977 | /* add ecx,32 */ | ||
978 | EMIT3(0x83, add_1reg(0xC0, IA32_ECX), 32); | ||
979 | |||
980 | /* shl ebx,cl */ | ||
981 | EMIT2(0xD3, add_1reg(0xE0, IA32_EBX)); | ||
982 | /* or dreg_lo,ebx */ | ||
983 | EMIT2(0x09, add_2reg(0xC0, dreg_lo, IA32_EBX)); | ||
984 | } else if (val >= 32 && val < 64) { | 950 | } else if (val >= 32 && val < 64) { |
985 | u32 value = val - 32; | 951 | u32 value = val - 32; |
986 | 952 | ||
@@ -1025,27 +991,10 @@ static inline void emit_ia32_arsh_i64(const u8 dst[], const u32 val, | |||
1025 | } | 991 | } |
1026 | /* Do RSH operation */ | 992 | /* Do RSH operation */ |
1027 | if (val < 32) { | 993 | if (val < 32) { |
1028 | /* shr dreg_lo,imm8 */ | 994 | /* shrd dreg_lo,dreg_hi,imm8 */ |
1029 | EMIT3(0xC1, add_1reg(0xE8, dreg_lo), val); | 995 | EMIT4(0x0F, 0xAC, add_2reg(0xC0, dreg_lo, dreg_hi), val); |
1030 | /* mov ebx,dreg_hi */ | ||
1031 | EMIT2(0x8B, add_2reg(0xC0, dreg_hi, IA32_EBX)); | ||
1032 | /* ashr dreg_hi,imm8 */ | 996 | /* ashr dreg_hi,imm8 */ |
1033 | EMIT3(0xC1, add_1reg(0xF8, dreg_hi), val); | 997 | EMIT3(0xC1, add_1reg(0xF8, dreg_hi), val); |
1034 | |||
1035 | /* IA32_ECX = 32 - val */ | ||
1036 | /* mov ecx,val */ | ||
1037 | EMIT2(0xB1, val); | ||
1038 | /* movzx ecx,ecx */ | ||
1039 | EMIT3(0x0F, 0xB6, add_2reg(0xC0, IA32_ECX, IA32_ECX)); | ||
1040 | /* neg ecx */ | ||
1041 | EMIT2(0xF7, add_1reg(0xD8, IA32_ECX)); | ||
1042 | /* add ecx,32 */ | ||
1043 | EMIT3(0x83, add_1reg(0xC0, IA32_ECX), 32); | ||
1044 | |||
1045 | /* shl ebx,cl */ | ||
1046 | EMIT2(0xD3, add_1reg(0xE0, IA32_EBX)); | ||
1047 | /* or dreg_lo,ebx */ | ||
1048 | EMIT2(0x09, add_2reg(0xC0, dreg_lo, IA32_EBX)); | ||
1049 | } else if (val >= 32 && val < 64) { | 998 | } else if (val >= 32 && val < 64) { |
1050 | u32 value = val - 32; | 999 | u32 value = val - 32; |
1051 | 1000 | ||