Skip to content

Commit 3f161e0

Browse files
iii-ihcahca
authored andcommitted
s390/bpf: implement BPF_PROBE_MEM
This is a s390 port of x86 commit 3dec541 ("bpf: Add support for BTF pointers to x86 JIT"). Signed-off-by: Ilya Leoshkevich <[email protected]> Reviewed-by: Heiko Carstens <[email protected]> Signed-off-by: Heiko Carstens <[email protected]>
1 parent 05a68e8 commit 3f161e0

File tree

1 file changed

+138
-1
lines changed

1 file changed

+138
-1
lines changed

arch/s390/net/bpf_jit_comp.c

Lines changed: 138 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ struct bpf_jit {
4949
int r1_thunk_ip; /* Address of expoline thunk for 'br %r1' */
5050
int r14_thunk_ip; /* Address of expoline thunk for 'br %r14' */
5151
int tail_call_start; /* Tail call start offset */
52+
int excnt; /* Number of exception table entries */
5253
int labels[1]; /* Labels for local jumps */
5354
};
5455

@@ -588,6 +589,84 @@ static void bpf_jit_epilogue(struct bpf_jit *jit, u32 stack_depth)
588589
}
589590
}
590591

592+
static int get_probe_mem_regno(const u8 *insn)
593+
{
594+
/*
595+
* insn must point to llgc, llgh, llgf or lg, which have destination
596+
* register at the same position.
597+
*/
598+
if (insn[0] != 0xe3) /* common llgc, llgh, llgf and lg prefix */
599+
return -1;
600+
if (insn[5] != 0x90 && /* llgc */
601+
insn[5] != 0x91 && /* llgh */
602+
insn[5] != 0x16 && /* llgf */
603+
insn[5] != 0x04) /* lg */
604+
return -1;
605+
return insn[1] >> 4;
606+
}
607+
608+
static bool ex_handler_bpf(const struct exception_table_entry *x,
609+
struct pt_regs *regs)
610+
{
611+
int regno;
612+
u8 *insn;
613+
614+
regs->psw.addr = extable_fixup(x);
615+
insn = (u8 *)__rewind_psw(regs->psw, regs->int_code >> 16);
616+
regno = get_probe_mem_regno(insn);
617+
if (WARN_ON_ONCE(regno < 0))
618+
/* JIT bug - unexpected instruction. */
619+
return false;
620+
regs->gprs[regno] = 0;
621+
return true;
622+
}
623+
624+
static int bpf_jit_probe_mem(struct bpf_jit *jit, struct bpf_prog *fp,
625+
int probe_prg, int nop_prg)
626+
{
627+
struct exception_table_entry *ex;
628+
s64 delta;
629+
u8 *insn;
630+
int prg;
631+
int i;
632+
633+
if (!fp->aux->extable)
634+
/* Do nothing during early JIT passes. */
635+
return 0;
636+
insn = jit->prg_buf + probe_prg;
637+
if (WARN_ON_ONCE(get_probe_mem_regno(insn) < 0))
638+
/* JIT bug - unexpected probe instruction. */
639+
return -1;
640+
if (WARN_ON_ONCE(probe_prg + insn_length(*insn) != nop_prg))
641+
/* JIT bug - gap between probe and nop instructions. */
642+
return -1;
643+
for (i = 0; i < 2; i++) {
644+
if (WARN_ON_ONCE(jit->excnt >= fp->aux->num_exentries))
645+
/* Verifier bug - not enough entries. */
646+
return -1;
647+
ex = &fp->aux->extable[jit->excnt];
648+
/* Add extable entries for probe and nop instructions. */
649+
prg = i == 0 ? probe_prg : nop_prg;
650+
delta = jit->prg_buf + prg - (u8 *)&ex->insn;
651+
if (WARN_ON_ONCE(delta < INT_MIN || delta > INT_MAX))
652+
/* JIT bug - code and extable must be close. */
653+
return -1;
654+
ex->insn = delta;
655+
/*
656+
* Always land on the nop. Note that extable infrastructure
657+
* ignores fixup field, it is handled by ex_handler_bpf().
658+
*/
659+
delta = jit->prg_buf + nop_prg - (u8 *)&ex->fixup;
660+
if (WARN_ON_ONCE(delta < INT_MIN || delta > INT_MAX))
661+
/* JIT bug - landing pad and extable must be close. */
662+
return -1;
663+
ex->fixup = delta;
664+
ex->handler = (u8 *)ex_handler_bpf - (u8 *)&ex->handler;
665+
jit->excnt++;
666+
}
667+
return 0;
668+
}
669+
591670
/*
592671
* Compile one eBPF instruction into s390x code
593672
*
@@ -604,7 +683,14 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
604683
u32 *addrs = jit->addrs;
605684
s32 imm = insn->imm;
606685
s16 off = insn->off;
686+
int probe_prg = -1;
607687
unsigned int mask;
688+
int nop_prg;
689+
int err;
690+
691+
if (BPF_CLASS(insn->code) == BPF_LDX &&
692+
BPF_MODE(insn->code) == BPF_PROBE_MEM)
693+
probe_prg = jit->prg;
608694

609695
switch (insn->code) {
610696
/*
@@ -1119,27 +1205,31 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
11191205
* BPF_LDX
11201206
*/
11211207
case BPF_LDX | BPF_MEM | BPF_B: /* dst = *(u8 *)(ul) (src + off) */
1208+
case BPF_LDX | BPF_PROBE_MEM | BPF_B:
11221209
/* llgc %dst,0(off,%src) */
11231210
EMIT6_DISP_LH(0xe3000000, 0x0090, dst_reg, src_reg, REG_0, off);
11241211
jit->seen |= SEEN_MEM;
11251212
if (insn_is_zext(&insn[1]))
11261213
insn_count = 2;
11271214
break;
11281215
case BPF_LDX | BPF_MEM | BPF_H: /* dst = *(u16 *)(ul) (src + off) */
1216+
case BPF_LDX | BPF_PROBE_MEM | BPF_H:
11291217
/* llgh %dst,0(off,%src) */
11301218
EMIT6_DISP_LH(0xe3000000, 0x0091, dst_reg, src_reg, REG_0, off);
11311219
jit->seen |= SEEN_MEM;
11321220
if (insn_is_zext(&insn[1]))
11331221
insn_count = 2;
11341222
break;
11351223
case BPF_LDX | BPF_MEM | BPF_W: /* dst = *(u32 *)(ul) (src + off) */
1224+
case BPF_LDX | BPF_PROBE_MEM | BPF_W:
11361225
/* llgf %dst,off(%src) */
11371226
jit->seen |= SEEN_MEM;
11381227
EMIT6_DISP_LH(0xe3000000, 0x0016, dst_reg, src_reg, REG_0, off);
11391228
if (insn_is_zext(&insn[1]))
11401229
insn_count = 2;
11411230
break;
11421231
case BPF_LDX | BPF_MEM | BPF_DW: /* dst = *(u64 *)(ul) (src + off) */
1232+
case BPF_LDX | BPF_PROBE_MEM | BPF_DW:
11431233
/* lg %dst,0(off,%src) */
11441234
jit->seen |= SEEN_MEM;
11451235
EMIT6_DISP_LH(0xe3000000, 0x0004, dst_reg, src_reg, REG_0, off);
@@ -1485,6 +1575,23 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
14851575
pr_err("Unknown opcode %02x\n", insn->code);
14861576
return -1;
14871577
}
1578+
1579+
if (probe_prg != -1) {
1580+
/*
1581+
* Handlers of certain exceptions leave psw.addr pointing to
1582+
* the instruction directly after the failing one. Therefore,
1583+
* create two exception table entries and also add a nop in
1584+
* case two probing instructions come directly after each
1585+
* other.
1586+
*/
1587+
nop_prg = jit->prg;
1588+
/* bcr 0,%0 */
1589+
_EMIT2(0x0700);
1590+
err = bpf_jit_probe_mem(jit, fp, probe_prg, nop_prg);
1591+
if (err < 0)
1592+
return err;
1593+
}
1594+
14881595
return insn_count;
14891596
}
14901597

@@ -1527,6 +1634,7 @@ static int bpf_jit_prog(struct bpf_jit *jit, struct bpf_prog *fp,
15271634
jit->lit32 = jit->lit32_start;
15281635
jit->lit64 = jit->lit64_start;
15291636
jit->prg = 0;
1637+
jit->excnt = 0;
15301638

15311639
bpf_jit_prologue(jit, stack_depth);
15321640
if (bpf_set_addr(jit, 0) < 0)
@@ -1551,6 +1659,12 @@ static int bpf_jit_prog(struct bpf_jit *jit, struct bpf_prog *fp,
15511659
jit->lit64_start = ALIGN(jit->lit64_start, 8);
15521660
jit->size = jit->lit64_start + lit64_size;
15531661
jit->size_prg = jit->prg;
1662+
1663+
if (WARN_ON_ONCE(fp->aux->extable &&
1664+
jit->excnt != fp->aux->num_exentries))
1665+
/* Verifier bug - too many entries. */
1666+
return -1;
1667+
15541668
return 0;
15551669
}
15561670

@@ -1565,6 +1679,29 @@ struct s390_jit_data {
15651679
int pass;
15661680
};
15671681

1682+
static struct bpf_binary_header *bpf_jit_alloc(struct bpf_jit *jit,
1683+
struct bpf_prog *fp)
1684+
{
1685+
struct bpf_binary_header *header;
1686+
u32 extable_size;
1687+
u32 code_size;
1688+
1689+
/* We need two entries per insn. */
1690+
fp->aux->num_exentries *= 2;
1691+
1692+
code_size = roundup(jit->size,
1693+
__alignof__(struct exception_table_entry));
1694+
extable_size = fp->aux->num_exentries *
1695+
sizeof(struct exception_table_entry);
1696+
header = bpf_jit_binary_alloc(code_size + extable_size, &jit->prg_buf,
1697+
8, jit_fill_hole);
1698+
if (!header)
1699+
return NULL;
1700+
fp->aux->extable = (struct exception_table_entry *)
1701+
(jit->prg_buf + code_size);
1702+
return header;
1703+
}
1704+
15681705
/*
15691706
* Compile eBPF program "fp"
15701707
*/
@@ -1631,7 +1768,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
16311768
/*
16321769
* Final pass: Allocate and generate program
16331770
*/
1634-
header = bpf_jit_binary_alloc(jit.size, &jit.prg_buf, 8, jit_fill_hole);
1771+
header = bpf_jit_alloc(&jit, fp);
16351772
if (!header) {
16361773
fp = orig_fp;
16371774
goto free_addrs;

0 commit comments

Comments
 (0)