Skip to content

Commit 72b603e

Browse files
Alexei Starovoitovdavem330
authored andcommitted
bpf: x86: add missing 'shift by register' instructions to x64 eBPF JIT
'shift by register' operations are supported by eBPF interpreter, but were accidently left out of x64 JIT compiler. Fix it and add a testcase. Reported-by: Brendan Gregg <brendan.d.gregg@gmail.com> Signed-off-by: Alexei Starovoitov <ast@plumgrid.com> Fixes: 6225827 ("net: filter: x86: internal BPF JIT") Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 9785820 commit 72b603e

File tree

2 files changed

+80
-0
lines changed

2 files changed

+80
-0
lines changed

arch/x86/net/bpf_jit_comp.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,48 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
515515
EMIT3(0xC1, add_1reg(b3, dst_reg), imm32);
516516
break;
517517

518+
case BPF_ALU | BPF_LSH | BPF_X:
519+
case BPF_ALU | BPF_RSH | BPF_X:
520+
case BPF_ALU | BPF_ARSH | BPF_X:
521+
case BPF_ALU64 | BPF_LSH | BPF_X:
522+
case BPF_ALU64 | BPF_RSH | BPF_X:
523+
case BPF_ALU64 | BPF_ARSH | BPF_X:
524+
525+
/* check for bad case when dst_reg == rcx */
526+
if (dst_reg == BPF_REG_4) {
527+
/* mov r11, dst_reg */
528+
EMIT_mov(AUX_REG, dst_reg);
529+
dst_reg = AUX_REG;
530+
}
531+
532+
if (src_reg != BPF_REG_4) { /* common case */
533+
EMIT1(0x51); /* push rcx */
534+
535+
/* mov rcx, src_reg */
536+
EMIT_mov(BPF_REG_4, src_reg);
537+
}
538+
539+
/* shl %rax, %cl | shr %rax, %cl | sar %rax, %cl */
540+
if (BPF_CLASS(insn->code) == BPF_ALU64)
541+
EMIT1(add_1mod(0x48, dst_reg));
542+
else if (is_ereg(dst_reg))
543+
EMIT1(add_1mod(0x40, dst_reg));
544+
545+
switch (BPF_OP(insn->code)) {
546+
case BPF_LSH: b3 = 0xE0; break;
547+
case BPF_RSH: b3 = 0xE8; break;
548+
case BPF_ARSH: b3 = 0xF8; break;
549+
}
550+
EMIT2(0xD3, add_1reg(b3, dst_reg));
551+
552+
if (src_reg != BPF_REG_4)
553+
EMIT1(0x59); /* pop rcx */
554+
555+
if (insn->dst_reg == BPF_REG_4)
556+
/* mov dst_reg, r11 */
557+
EMIT_mov(insn->dst_reg, AUX_REG);
558+
break;
559+
518560
case BPF_ALU | BPF_END | BPF_FROM_BE:
519561
switch (imm32) {
520562
case 16:

lib/test_bpf.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1341,6 +1341,44 @@ static struct bpf_test tests[] = {
13411341
{ },
13421342
{ { 0, -1 } }
13431343
},
1344+
{
1345+
"INT: shifts by register",
1346+
.u.insns_int = {
1347+
BPF_MOV64_IMM(R0, -1234),
1348+
BPF_MOV64_IMM(R1, 1),
1349+
BPF_ALU32_REG(BPF_RSH, R0, R1),
1350+
BPF_JMP_IMM(BPF_JEQ, R0, 0x7ffffd97, 1),
1351+
BPF_EXIT_INSN(),
1352+
BPF_MOV64_IMM(R2, 1),
1353+
BPF_ALU64_REG(BPF_LSH, R0, R2),
1354+
BPF_MOV32_IMM(R4, -1234),
1355+
BPF_JMP_REG(BPF_JEQ, R0, R4, 1),
1356+
BPF_EXIT_INSN(),
1357+
BPF_ALU64_IMM(BPF_AND, R4, 63),
1358+
BPF_ALU64_REG(BPF_LSH, R0, R4), /* R0 <= 46 */
1359+
BPF_MOV64_IMM(R3, 47),
1360+
BPF_ALU64_REG(BPF_ARSH, R0, R3),
1361+
BPF_JMP_IMM(BPF_JEQ, R0, -617, 1),
1362+
BPF_EXIT_INSN(),
1363+
BPF_MOV64_IMM(R2, 1),
1364+
BPF_ALU64_REG(BPF_LSH, R4, R2), /* R4 = 46 << 1 */
1365+
BPF_JMP_IMM(BPF_JEQ, R4, 92, 1),
1366+
BPF_EXIT_INSN(),
1367+
BPF_MOV64_IMM(R4, 4),
1368+
BPF_ALU64_REG(BPF_LSH, R4, R4), /* R4 = 4 << 4 */
1369+
BPF_JMP_IMM(BPF_JEQ, R4, 64, 1),
1370+
BPF_EXIT_INSN(),
1371+
BPF_MOV64_IMM(R4, 5),
1372+
BPF_ALU32_REG(BPF_LSH, R4, R4), /* R4 = 5 << 5 */
1373+
BPF_JMP_IMM(BPF_JEQ, R4, 160, 1),
1374+
BPF_EXIT_INSN(),
1375+
BPF_MOV64_IMM(R0, -1),
1376+
BPF_EXIT_INSN(),
1377+
},
1378+
INTERNAL,
1379+
{ },
1380+
{ { 0, -1 } }
1381+
},
13441382
{
13451383
"INT: DIV + ABS",
13461384
.u.insns_int = {

0 commit comments

Comments
 (0)