diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 94ba5163d4c5..2ace865e75e3 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -7880,13 +7880,38 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
 			return -EINVAL;
 		}
 
-		if ((opcode == BPF_LSH || opcode == BPF_RSH ||
-		     opcode == BPF_ARSH) && BPF_SRC(insn->code) == BPF_K) {
+		if (opcode == BPF_LSH || opcode == BPF_RSH ||
+		     opcode == BPF_ARSH) {
 			int size = BPF_CLASS(insn->code) == BPF_ALU64 ? 64 : 32;
 
-			if (insn->imm < 0 || insn->imm >= size) {
-				verbose(env, "invalid shift %d\n", insn->imm);
-				return -EINVAL;
+			if (BPF_SRC(insn->code) == BPF_K) {
+				if (insn->imm < 0 || insn->imm >= size) {
+					verbose(env, "invalid shift %d\n", insn->imm);
+					return -EINVAL;
+				}
+			}
+			if (BPF_SRC(insn->code) == BPF_X) {
+				struct bpf_reg_state *src_reg;
+				src_reg = &regs[insn->src_reg];
+				if (size == 64) {
+					if (src_reg->smin_value < 0) {
+						verbose(env, "invalid shift %lld\n", src_reg->smin_value);
+						return -EINVAL;
+					}
+					if (src_reg->smax_value >= size) {
+						verbose(env, "invalid shift %lld\n", src_reg->smax_value);
+						return -EINVAL;
+					}
+				} else {
+					if (src_reg->s32_min_value < 0) {
+						verbose(env, "invalid shift %d\n", src_reg->s32_min_value);
+						return -EINVAL;
+					}
+					if (src_reg->s32_max_value >= size) {
+						verbose(env, "invalid shift %d\n", src_reg->s32_max_value);
+						return -EINVAL;
+					}
+				}
 			}
 		}