aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/mips/include/asm/uasm.h1
-rw-r--r--arch/mips/include/uapi/asm/inst.h1
-rw-r--r--arch/mips/mm/uasm-micromips.c1
-rw-r--r--arch/mips/mm/uasm-mips.c1
-rw-r--r--arch/mips/mm/uasm.c9
-rw-r--r--arch/mips/net/ebpf_jit.c4
-rw-r--r--arch/powerpc/include/asm/ppc-opcode.h2
-rw-r--r--arch/powerpc/net/bpf_jit.h4
-rw-r--r--arch/powerpc/net/bpf_jit_comp64.c6
-rw-r--r--arch/s390/net/bpf_jit_comp.c12
-rw-r--r--drivers/net/ethernet/netronome/nfp/bpf/jit.c45
-rw-r--r--kernel/bpf/core.c52
-rw-r--r--kernel/bpf/verifier.c5
-rw-r--r--tools/testing/selftests/bpf/test_verifier.c29
14 files changed, 137 insertions, 35 deletions
diff --git a/arch/mips/include/asm/uasm.h b/arch/mips/include/asm/uasm.h
index 59dae37f6b8d..b1990dd75f27 100644
--- a/arch/mips/include/asm/uasm.h
+++ b/arch/mips/include/asm/uasm.h
@@ -157,6 +157,7 @@ Ip_u2u1s3(_slti);
157Ip_u2u1s3(_sltiu); 157Ip_u2u1s3(_sltiu);
158Ip_u3u1u2(_sltu); 158Ip_u3u1u2(_sltu);
159Ip_u2u1u3(_sra); 159Ip_u2u1u3(_sra);
160Ip_u3u2u1(_srav);
160Ip_u2u1u3(_srl); 161Ip_u2u1u3(_srl);
161Ip_u3u2u1(_srlv); 162Ip_u3u2u1(_srlv);
162Ip_u3u1u2(_subu); 163Ip_u3u1u2(_subu);
diff --git a/arch/mips/include/uapi/asm/inst.h b/arch/mips/include/uapi/asm/inst.h
index 273ef58f4d43..40fbb5dd66df 100644
--- a/arch/mips/include/uapi/asm/inst.h
+++ b/arch/mips/include/uapi/asm/inst.h
@@ -371,6 +371,7 @@ enum mm_32a_minor_op {
371 mm_srl32_op = 0x040, 371 mm_srl32_op = 0x040,
372 mm_srlv32_op = 0x050, 372 mm_srlv32_op = 0x050,
373 mm_sra_op = 0x080, 373 mm_sra_op = 0x080,
374 mm_srav_op = 0x090,
374 mm_rotr_op = 0x0c0, 375 mm_rotr_op = 0x0c0,
375 mm_lwxs_op = 0x118, 376 mm_lwxs_op = 0x118,
376 mm_addu32_op = 0x150, 377 mm_addu32_op = 0x150,
diff --git a/arch/mips/mm/uasm-micromips.c b/arch/mips/mm/uasm-micromips.c
index 24e5b0d06899..75ef90486fe6 100644
--- a/arch/mips/mm/uasm-micromips.c
+++ b/arch/mips/mm/uasm-micromips.c
@@ -104,6 +104,7 @@ static const struct insn insn_table_MM[insn_invalid] = {
104 [insn_sltiu] = {M(mm_sltiu32_op, 0, 0, 0, 0, 0), RT | RS | SIMM}, 104 [insn_sltiu] = {M(mm_sltiu32_op, 0, 0, 0, 0, 0), RT | RS | SIMM},
105 [insn_sltu] = {M(mm_pool32a_op, 0, 0, 0, 0, mm_sltu_op), RT | RS | RD}, 105 [insn_sltu] = {M(mm_pool32a_op, 0, 0, 0, 0, mm_sltu_op), RT | RS | RD},
106 [insn_sra] = {M(mm_pool32a_op, 0, 0, 0, 0, mm_sra_op), RT | RS | RD}, 106 [insn_sra] = {M(mm_pool32a_op, 0, 0, 0, 0, mm_sra_op), RT | RS | RD},
107 [insn_srav] = {M(mm_pool32a_op, 0, 0, 0, 0, mm_srav_op), RT | RS | RD},
107 [insn_srl] = {M(mm_pool32a_op, 0, 0, 0, 0, mm_srl32_op), RT | RS | RD}, 108 [insn_srl] = {M(mm_pool32a_op, 0, 0, 0, 0, mm_srl32_op), RT | RS | RD},
108 [insn_srlv] = {M(mm_pool32a_op, 0, 0, 0, 0, mm_srlv32_op), RT | RS | RD}, 109 [insn_srlv] = {M(mm_pool32a_op, 0, 0, 0, 0, mm_srlv32_op), RT | RS | RD},
109 [insn_rotr] = {M(mm_pool32a_op, 0, 0, 0, 0, mm_rotr_op), RT | RS | RD}, 110 [insn_rotr] = {M(mm_pool32a_op, 0, 0, 0, 0, mm_rotr_op), RT | RS | RD},
diff --git a/arch/mips/mm/uasm-mips.c b/arch/mips/mm/uasm-mips.c
index 60ceb93c71a0..6abe40fc413d 100644
--- a/arch/mips/mm/uasm-mips.c
+++ b/arch/mips/mm/uasm-mips.c
@@ -171,6 +171,7 @@ static const struct insn insn_table[insn_invalid] = {
171 [insn_sltiu] = {M(sltiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM}, 171 [insn_sltiu] = {M(sltiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM},
172 [insn_sltu] = {M(spec_op, 0, 0, 0, 0, sltu_op), RS | RT | RD}, 172 [insn_sltu] = {M(spec_op, 0, 0, 0, 0, sltu_op), RS | RT | RD},
173 [insn_sra] = {M(spec_op, 0, 0, 0, 0, sra_op), RT | RD | RE}, 173 [insn_sra] = {M(spec_op, 0, 0, 0, 0, sra_op), RT | RD | RE},
174 [insn_srav] = {M(spec_op, 0, 0, 0, 0, srav_op), RS | RT | RD},
174 [insn_srl] = {M(spec_op, 0, 0, 0, 0, srl_op), RT | RD | RE}, 175 [insn_srl] = {M(spec_op, 0, 0, 0, 0, srl_op), RT | RD | RE},
175 [insn_srlv] = {M(spec_op, 0, 0, 0, 0, srlv_op), RS | RT | RD}, 176 [insn_srlv] = {M(spec_op, 0, 0, 0, 0, srlv_op), RS | RT | RD},
176 [insn_subu] = {M(spec_op, 0, 0, 0, 0, subu_op), RS | RT | RD}, 177 [insn_subu] = {M(spec_op, 0, 0, 0, 0, subu_op), RS | RT | RD},
diff --git a/arch/mips/mm/uasm.c b/arch/mips/mm/uasm.c
index 57570c0649b4..45b6264ff308 100644
--- a/arch/mips/mm/uasm.c
+++ b/arch/mips/mm/uasm.c
@@ -61,10 +61,10 @@ enum opcode {
61 insn_mthc0, insn_mthi, insn_mtlo, insn_mul, insn_multu, insn_nor, 61 insn_mthc0, insn_mthi, insn_mtlo, insn_mul, insn_multu, insn_nor,
62 insn_or, insn_ori, insn_pref, insn_rfe, insn_rotr, insn_sb, 62 insn_or, insn_ori, insn_pref, insn_rfe, insn_rotr, insn_sb,
63 insn_sc, insn_scd, insn_sd, insn_sh, insn_sll, insn_sllv, 63 insn_sc, insn_scd, insn_sd, insn_sh, insn_sll, insn_sllv,
64 insn_slt, insn_slti, insn_sltiu, insn_sltu, insn_sra, insn_srl, 64 insn_slt, insn_slti, insn_sltiu, insn_sltu, insn_sra, insn_srav,
65 insn_srlv, insn_subu, insn_sw, insn_sync, insn_syscall, insn_tlbp, 65 insn_srl, insn_srlv, insn_subu, insn_sw, insn_sync, insn_syscall,
66 insn_tlbr, insn_tlbwi, insn_tlbwr, insn_wait, insn_wsbh, insn_xor, 66 insn_tlbp, insn_tlbr, insn_tlbwi, insn_tlbwr, insn_wait, insn_wsbh,
67 insn_xori, insn_yield, 67 insn_xor, insn_xori, insn_yield,
68 insn_invalid /* insn_invalid must be last */ 68 insn_invalid /* insn_invalid must be last */
69}; 69};
70 70
@@ -353,6 +353,7 @@ I_u2u1s3(_slti)
353I_u2u1s3(_sltiu) 353I_u2u1s3(_sltiu)
354I_u3u1u2(_sltu) 354I_u3u1u2(_sltu)
355I_u2u1u3(_sra) 355I_u2u1u3(_sra)
356I_u3u2u1(_srav)
356I_u2u1u3(_srl) 357I_u2u1u3(_srl)
357I_u3u2u1(_srlv) 358I_u3u2u1(_srlv)
358I_u2u1u3(_rotr) 359I_u2u1u3(_rotr)
diff --git a/arch/mips/net/ebpf_jit.c b/arch/mips/net/ebpf_jit.c
index aeb7b1b0f202..b16710a8a9e7 100644
--- a/arch/mips/net/ebpf_jit.c
+++ b/arch/mips/net/ebpf_jit.c
@@ -854,6 +854,7 @@ static int build_one_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
854 case BPF_ALU | BPF_MOD | BPF_X: /* ALU_REG */ 854 case BPF_ALU | BPF_MOD | BPF_X: /* ALU_REG */
855 case BPF_ALU | BPF_LSH | BPF_X: /* ALU_REG */ 855 case BPF_ALU | BPF_LSH | BPF_X: /* ALU_REG */
856 case BPF_ALU | BPF_RSH | BPF_X: /* ALU_REG */ 856 case BPF_ALU | BPF_RSH | BPF_X: /* ALU_REG */
857 case BPF_ALU | BPF_ARSH | BPF_X: /* ALU_REG */
857 src = ebpf_to_mips_reg(ctx, insn, src_reg_no_fp); 858 src = ebpf_to_mips_reg(ctx, insn, src_reg_no_fp);
858 dst = ebpf_to_mips_reg(ctx, insn, dst_reg); 859 dst = ebpf_to_mips_reg(ctx, insn, dst_reg);
859 if (src < 0 || dst < 0) 860 if (src < 0 || dst < 0)
@@ -913,6 +914,9 @@ static int build_one_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
913 case BPF_RSH: 914 case BPF_RSH:
914 emit_instr(ctx, srlv, dst, dst, src); 915 emit_instr(ctx, srlv, dst, dst, src);
915 break; 916 break;
917 case BPF_ARSH:
918 emit_instr(ctx, srav, dst, dst, src);
919 break;
916 default: 920 default:
917 pr_err("ALU_REG NOT HANDLED\n"); 921 pr_err("ALU_REG NOT HANDLED\n");
918 return -EINVAL; 922 return -EINVAL;
diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h
index a6e9e314c707..901459226eca 100644
--- a/arch/powerpc/include/asm/ppc-opcode.h
+++ b/arch/powerpc/include/asm/ppc-opcode.h
@@ -342,6 +342,8 @@
342#define PPC_INST_SLW 0x7c000030 342#define PPC_INST_SLW 0x7c000030
343#define PPC_INST_SLD 0x7c000036 343#define PPC_INST_SLD 0x7c000036
344#define PPC_INST_SRW 0x7c000430 344#define PPC_INST_SRW 0x7c000430
345#define PPC_INST_SRAW 0x7c000630
346#define PPC_INST_SRAWI 0x7c000670
345#define PPC_INST_SRD 0x7c000436 347#define PPC_INST_SRD 0x7c000436
346#define PPC_INST_SRAD 0x7c000634 348#define PPC_INST_SRAD 0x7c000634
347#define PPC_INST_SRADI 0x7c000674 349#define PPC_INST_SRADI 0x7c000674
diff --git a/arch/powerpc/net/bpf_jit.h b/arch/powerpc/net/bpf_jit.h
index 47fc6660845d..c2d5192ed64f 100644
--- a/arch/powerpc/net/bpf_jit.h
+++ b/arch/powerpc/net/bpf_jit.h
@@ -152,6 +152,10 @@
152 ___PPC_RS(a) | ___PPC_RB(s)) 152 ___PPC_RS(a) | ___PPC_RB(s))
153#define PPC_SRW(d, a, s) EMIT(PPC_INST_SRW | ___PPC_RA(d) | \ 153#define PPC_SRW(d, a, s) EMIT(PPC_INST_SRW | ___PPC_RA(d) | \
154 ___PPC_RS(a) | ___PPC_RB(s)) 154 ___PPC_RS(a) | ___PPC_RB(s))
155#define PPC_SRAW(d, a, s) EMIT(PPC_INST_SRAW | ___PPC_RA(d) | \
156 ___PPC_RS(a) | ___PPC_RB(s))
157#define PPC_SRAWI(d, a, i) EMIT(PPC_INST_SRAWI | ___PPC_RA(d) | \
158 ___PPC_RS(a) | __PPC_SH(i))
155#define PPC_SRD(d, a, s) EMIT(PPC_INST_SRD | ___PPC_RA(d) | \ 159#define PPC_SRD(d, a, s) EMIT(PPC_INST_SRD | ___PPC_RA(d) | \
156 ___PPC_RS(a) | ___PPC_RB(s)) 160 ___PPC_RS(a) | ___PPC_RB(s))
157#define PPC_SRAD(d, a, s) EMIT(PPC_INST_SRAD | ___PPC_RA(d) | \ 161#define PPC_SRAD(d, a, s) EMIT(PPC_INST_SRAD | ___PPC_RA(d) | \
diff --git a/arch/powerpc/net/bpf_jit_comp64.c b/arch/powerpc/net/bpf_jit_comp64.c
index 17482f5de3e2..7dc81877057d 100644
--- a/arch/powerpc/net/bpf_jit_comp64.c
+++ b/arch/powerpc/net/bpf_jit_comp64.c
@@ -529,9 +529,15 @@ static int bpf_jit_build_body(struct bpf_prog *fp, u32 *image,
529 if (imm != 0) 529 if (imm != 0)
530 PPC_SRDI(dst_reg, dst_reg, imm); 530 PPC_SRDI(dst_reg, dst_reg, imm);
531 break; 531 break;
532 case BPF_ALU | BPF_ARSH | BPF_X: /* (s32) dst >>= src */
533 PPC_SRAW(dst_reg, dst_reg, src_reg);
534 goto bpf_alu32_trunc;
532 case BPF_ALU64 | BPF_ARSH | BPF_X: /* (s64) dst >>= src */ 535 case BPF_ALU64 | BPF_ARSH | BPF_X: /* (s64) dst >>= src */
533 PPC_SRAD(dst_reg, dst_reg, src_reg); 536 PPC_SRAD(dst_reg, dst_reg, src_reg);
534 break; 537 break;
538 case BPF_ALU | BPF_ARSH | BPF_K: /* (s32) dst >>= imm */
539 PPC_SRAWI(dst_reg, dst_reg, imm);
540 goto bpf_alu32_trunc;
535 case BPF_ALU64 | BPF_ARSH | BPF_K: /* (s64) dst >>= imm */ 541 case BPF_ALU64 | BPF_ARSH | BPF_K: /* (s64) dst >>= imm */
536 if (imm != 0) 542 if (imm != 0)
537 PPC_SRADI(dst_reg, dst_reg, imm); 543 PPC_SRADI(dst_reg, dst_reg, imm);
diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c
index d7052cbe984f..3ff758eeb71d 100644
--- a/arch/s390/net/bpf_jit_comp.c
+++ b/arch/s390/net/bpf_jit_comp.c
@@ -821,10 +821,22 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, int i
821 /* 821 /*
822 * BPF_ARSH 822 * BPF_ARSH
823 */ 823 */
824 case BPF_ALU | BPF_ARSH | BPF_X: /* ((s32) dst) >>= src */
825 /* sra %dst,%dst,0(%src) */
826 EMIT4_DISP(0x8a000000, dst_reg, src_reg, 0);
827 EMIT_ZERO(dst_reg);
828 break;
824 case BPF_ALU64 | BPF_ARSH | BPF_X: /* ((s64) dst) >>= src */ 829 case BPF_ALU64 | BPF_ARSH | BPF_X: /* ((s64) dst) >>= src */
825 /* srag %dst,%dst,0(%src) */ 830 /* srag %dst,%dst,0(%src) */
826 EMIT6_DISP_LH(0xeb000000, 0x000a, dst_reg, dst_reg, src_reg, 0); 831 EMIT6_DISP_LH(0xeb000000, 0x000a, dst_reg, dst_reg, src_reg, 0);
827 break; 832 break;
833 case BPF_ALU | BPF_ARSH | BPF_K: /* ((s32) dst >> imm */
834 if (imm == 0)
835 break;
836 /* sra %dst,imm(%r0) */
837 EMIT4_DISP(0x8a000000, dst_reg, REG_0, imm);
838 EMIT_ZERO(dst_reg);
839 break;
828 case BPF_ALU64 | BPF_ARSH | BPF_K: /* ((s64) dst) >>= imm */ 840 case BPF_ALU64 | BPF_ARSH | BPF_K: /* ((s64) dst) >>= imm */
829 if (imm == 0) 841 if (imm == 0)
830 break; 842 break;
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/jit.c b/drivers/net/ethernet/netronome/nfp/bpf/jit.c
index 97d33bb4d84d..662cbc21d909 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/jit.c
+++ b/drivers/net/ethernet/netronome/nfp/bpf/jit.c
@@ -2382,6 +2382,49 @@ static int neg_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
2382 return 0; 2382 return 0;
2383} 2383}
2384 2384
2385static int __ashr_imm(struct nfp_prog *nfp_prog, u8 dst, u8 shift_amt)
2386{
2387 /* Set signedness bit (MSB of result). */
2388 emit_alu(nfp_prog, reg_none(), reg_a(dst), ALU_OP_OR, reg_imm(0));
2389 emit_shf(nfp_prog, reg_both(dst), reg_none(), SHF_OP_ASHR, reg_b(dst),
2390 SHF_SC_R_SHF, shift_amt);
2391 wrp_immed(nfp_prog, reg_both(dst + 1), 0);
2392
2393 return 0;
2394}
2395
2396static int ashr_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
2397{
2398 const struct bpf_insn *insn = &meta->insn;
2399 u64 umin, umax;
2400 u8 dst, src;
2401
2402 dst = insn->dst_reg * 2;
2403 umin = meta->umin_src;
2404 umax = meta->umax_src;
2405 if (umin == umax)
2406 return __ashr_imm(nfp_prog, dst, umin);
2407
2408 src = insn->src_reg * 2;
2409 /* NOTE: the first insn will set both indirect shift amount (source A)
2410 * and signedness bit (MSB of result).
2411 */
2412 emit_alu(nfp_prog, reg_none(), reg_a(src), ALU_OP_OR, reg_b(dst));
2413 emit_shf_indir(nfp_prog, reg_both(dst), reg_none(), SHF_OP_ASHR,
2414 reg_b(dst), SHF_SC_R_SHF);
2415 wrp_immed(nfp_prog, reg_both(dst + 1), 0);
2416
2417 return 0;
2418}
2419
2420static int ashr_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
2421{
2422 const struct bpf_insn *insn = &meta->insn;
2423 u8 dst = insn->dst_reg * 2;
2424
2425 return __ashr_imm(nfp_prog, dst, insn->imm);
2426}
2427
2385static int shl_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) 2428static int shl_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
2386{ 2429{
2387 const struct bpf_insn *insn = &meta->insn; 2430 const struct bpf_insn *insn = &meta->insn;
@@ -3286,6 +3329,8 @@ static const instr_cb_t instr_cb[256] = {
3286 [BPF_ALU | BPF_DIV | BPF_K] = div_imm, 3329 [BPF_ALU | BPF_DIV | BPF_K] = div_imm,
3287 [BPF_ALU | BPF_NEG] = neg_reg, 3330 [BPF_ALU | BPF_NEG] = neg_reg,
3288 [BPF_ALU | BPF_LSH | BPF_K] = shl_imm, 3331 [BPF_ALU | BPF_LSH | BPF_K] = shl_imm,
3332 [BPF_ALU | BPF_ARSH | BPF_X] = ashr_reg,
3333 [BPF_ALU | BPF_ARSH | BPF_K] = ashr_imm,
3289 [BPF_ALU | BPF_END | BPF_X] = end_reg32, 3334 [BPF_ALU | BPF_END | BPF_X] = end_reg32,
3290 [BPF_LD | BPF_IMM | BPF_DW] = imm_ld8, 3335 [BPF_LD | BPF_IMM | BPF_DW] = imm_ld8,
3291 [BPF_LD | BPF_ABS | BPF_B] = data_ld1, 3336 [BPF_LD | BPF_ABS | BPF_B] = data_ld1,
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 628b3970a49b..a5b223ef7131 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -933,32 +933,34 @@ EXPORT_SYMBOL_GPL(__bpf_call_base);
933#define BPF_INSN_MAP(INSN_2, INSN_3) \ 933#define BPF_INSN_MAP(INSN_2, INSN_3) \
934 /* 32 bit ALU operations. */ \ 934 /* 32 bit ALU operations. */ \
935 /* Register based. */ \ 935 /* Register based. */ \
936 INSN_3(ALU, ADD, X), \ 936 INSN_3(ALU, ADD, X), \
937 INSN_3(ALU, SUB, X), \ 937 INSN_3(ALU, SUB, X), \
938 INSN_3(ALU, AND, X), \ 938 INSN_3(ALU, AND, X), \
939 INSN_3(ALU, OR, X), \ 939 INSN_3(ALU, OR, X), \
940 INSN_3(ALU, LSH, X), \ 940 INSN_3(ALU, LSH, X), \
941 INSN_3(ALU, RSH, X), \ 941 INSN_3(ALU, RSH, X), \
942 INSN_3(ALU, XOR, X), \ 942 INSN_3(ALU, XOR, X), \
943 INSN_3(ALU, MUL, X), \ 943 INSN_3(ALU, MUL, X), \
944 INSN_3(ALU, MOV, X), \ 944 INSN_3(ALU, MOV, X), \
945 INSN_3(ALU, DIV, X), \ 945 INSN_3(ALU, ARSH, X), \
946 INSN_3(ALU, MOD, X), \ 946 INSN_3(ALU, DIV, X), \
947 INSN_3(ALU, MOD, X), \
947 INSN_2(ALU, NEG), \ 948 INSN_2(ALU, NEG), \
948 INSN_3(ALU, END, TO_BE), \ 949 INSN_3(ALU, END, TO_BE), \
949 INSN_3(ALU, END, TO_LE), \ 950 INSN_3(ALU, END, TO_LE), \
950 /* Immediate based. */ \ 951 /* Immediate based. */ \
951 INSN_3(ALU, ADD, K), \ 952 INSN_3(ALU, ADD, K), \
952 INSN_3(ALU, SUB, K), \ 953 INSN_3(ALU, SUB, K), \
953 INSN_3(ALU, AND, K), \ 954 INSN_3(ALU, AND, K), \
954 INSN_3(ALU, OR, K), \ 955 INSN_3(ALU, OR, K), \
955 INSN_3(ALU, LSH, K), \ 956 INSN_3(ALU, LSH, K), \
956 INSN_3(ALU, RSH, K), \ 957 INSN_3(ALU, RSH, K), \
957 INSN_3(ALU, XOR, K), \ 958 INSN_3(ALU, XOR, K), \
958 INSN_3(ALU, MUL, K), \ 959 INSN_3(ALU, MUL, K), \
959 INSN_3(ALU, MOV, K), \ 960 INSN_3(ALU, MOV, K), \
960 INSN_3(ALU, DIV, K), \ 961 INSN_3(ALU, ARSH, K), \
961 INSN_3(ALU, MOD, K), \ 962 INSN_3(ALU, DIV, K), \
963 INSN_3(ALU, MOD, K), \
962 /* 64 bit ALU operations. */ \ 964 /* 64 bit ALU operations. */ \
963 /* Register based. */ \ 965 /* Register based. */ \
964 INSN_3(ALU64, ADD, X), \ 966 INSN_3(ALU64, ADD, X), \
@@ -1137,6 +1139,12 @@ select_insn:
1137 DST = (u64) (u32) insn[0].imm | ((u64) (u32) insn[1].imm) << 32; 1139 DST = (u64) (u32) insn[0].imm | ((u64) (u32) insn[1].imm) << 32;
1138 insn++; 1140 insn++;
1139 CONT; 1141 CONT;
1142 ALU_ARSH_X:
1143 DST = (u64) (u32) ((*(s32 *) &DST) >> SRC);
1144 CONT;
1145 ALU_ARSH_K:
1146 DST = (u64) (u32) ((*(s32 *) &DST) >> IMM);
1147 CONT;
1140 ALU64_ARSH_X: 1148 ALU64_ARSH_X:
1141 (*(s64 *) &DST) >>= SRC; 1149 (*(s64 *) &DST) >>= SRC;
1142 CONT; 1150 CONT;
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 7658c61c1a88..2752d35ad073 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -3649,11 +3649,6 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
3649 return -EINVAL; 3649 return -EINVAL;
3650 } 3650 }
3651 3651
3652 if (opcode == BPF_ARSH && BPF_CLASS(insn->code) != BPF_ALU64) {
3653 verbose(env, "BPF_ARSH not supported for 32 bit ALU\n");
3654 return -EINVAL;
3655 }
3656
3657 if ((opcode == BPF_LSH || opcode == BPF_RSH || 3652 if ((opcode == BPF_LSH || opcode == BPF_RSH ||
3658 opcode == BPF_ARSH) && BPF_SRC(insn->code) == BPF_K) { 3653 opcode == BPF_ARSH) && BPF_SRC(insn->code) == BPF_K) {
3659 int size = BPF_CLASS(insn->code) == BPF_ALU64 ? 64 : 32; 3654 int size = BPF_CLASS(insn->code) == BPF_ALU64 ? 64 : 32;
diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c
index b4b4a3f93639..36ce58b4933e 100644
--- a/tools/testing/selftests/bpf/test_verifier.c
+++ b/tools/testing/selftests/bpf/test_verifier.c
@@ -721,8 +721,18 @@ static struct bpf_test tests[] = {
721 BPF_ALU32_IMM(BPF_ARSH, BPF_REG_0, 5), 721 BPF_ALU32_IMM(BPF_ARSH, BPF_REG_0, 5),
722 BPF_EXIT_INSN(), 722 BPF_EXIT_INSN(),
723 }, 723 },
724 .result = REJECT, 724 .result = ACCEPT,
725 .errstr = "unknown opcode c4", 725 .retval = 0,
726 },
727 {
728 "arsh32 on imm 2",
729 .insns = {
730 BPF_LD_IMM64(BPF_REG_0, 0x1122334485667788),
731 BPF_ALU32_IMM(BPF_ARSH, BPF_REG_0, 7),
732 BPF_EXIT_INSN(),
733 },
734 .result = ACCEPT,
735 .retval = -16069393,
726 }, 736 },
727 { 737 {
728 "arsh32 on reg", 738 "arsh32 on reg",
@@ -732,8 +742,19 @@ static struct bpf_test tests[] = {
732 BPF_ALU32_REG(BPF_ARSH, BPF_REG_0, BPF_REG_1), 742 BPF_ALU32_REG(BPF_ARSH, BPF_REG_0, BPF_REG_1),
733 BPF_EXIT_INSN(), 743 BPF_EXIT_INSN(),
734 }, 744 },
735 .result = REJECT, 745 .result = ACCEPT,
736 .errstr = "unknown opcode cc", 746 .retval = 0,
747 },
748 {
749 "arsh32 on reg 2",
750 .insns = {
751 BPF_LD_IMM64(BPF_REG_0, 0xffff55667788),
752 BPF_MOV64_IMM(BPF_REG_1, 15),
753 BPF_ALU32_REG(BPF_ARSH, BPF_REG_0, BPF_REG_1),
754 BPF_EXIT_INSN(),
755 },
756 .result = ACCEPT,
757 .retval = 43724,
737 }, 758 },
738 { 759 {
739 "arsh64 on imm", 760 "arsh64 on imm",