Skip to content

Commit b799207

Browse files
thejhborkmann
authored andcommitted
bpf: 32-bit RSH verification must truncate input before the ALU op
When I wrote commit 468f6ea ("bpf: fix 32-bit ALU op verification"), I assumed that, in order to emulate 64-bit arithmetic with 32-bit logic, it is sufficient to just truncate the output to 32 bits; and so I just moved the register size coercion that used to be at the start of the function to the end of the function. That assumption is true for almost every op, but not for 32-bit right shifts, because those can propagate information towards the least significant bit. Fix it by always truncating inputs for 32-bit ops to 32 bits. Also get rid of the coerce_reg_to_size() after the ALU op, since that has no effect. Fixes: 468f6ea ("bpf: fix 32-bit ALU op verification") Acked-by: Daniel Borkmann <daniel@iogearbox.net> Signed-off-by: Jann Horn <jannh@google.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
1 parent b0584ea commit b799207

File tree

1 file changed

+9
-1
lines changed

1 file changed

+9
-1
lines changed

Diff for: kernel/bpf/verifier.c

+9-1
Original file line numberDiff line numberDiff line change
@@ -2896,6 +2896,15 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env,
28962896
u64 umin_val, umax_val;
28972897
u64 insn_bitness = (BPF_CLASS(insn->code) == BPF_ALU64) ? 64 : 32;
28982898

2899+
if (insn_bitness == 32) {
2900+
/* Relevant for 32-bit RSH: Information can propagate towards
2901+
* LSB, so it isn't sufficient to only truncate the output to
2902+
* 32 bits.
2903+
*/
2904+
coerce_reg_to_size(dst_reg, 4);
2905+
coerce_reg_to_size(&src_reg, 4);
2906+
}
2907+
28992908
smin_val = src_reg.smin_value;
29002909
smax_val = src_reg.smax_value;
29012910
umin_val = src_reg.umin_value;
@@ -3131,7 +3140,6 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env,
31313140
if (BPF_CLASS(insn->code) != BPF_ALU64) {
31323141
/* 32-bit ALU ops are (32,32)->32 */
31333142
coerce_reg_to_size(dst_reg, 4);
3134-
coerce_reg_to_size(&src_reg, 4);
31353143
}
31363144

31373145
__reg_deduce_bounds(dst_reg);

0 commit comments

Comments
 (0)