Skip to content

Commit de95b8d

Browse files
iii-ikernel-patches-bot
authored andcommitted
In order to branch around tail calls (due to out-of-bounds index,
exceeding tail call count or missing tail call target), JIT uses label[0] field, which contains the address of the instruction following the tail call. When there are multiple tail calls, label[0] value comes from handling of a previous tail call, which is incorrect. Fix by getting rid of label array and resolving the label address locally: for all 3 branches that jump to it, emit 0 offsets at the beginning, and then backpatch them with the correct value. Also, do not use the long jump infrastructure: the tail call sequence is known to be short, so make all 3 jumps short. Fixes: 6651ee0 ("s390/bpf: implement bpf_tail_call() helper") Signed-off-by: Ilya Leoshkevich <[email protected]> --- arch/s390/net/bpf_jit_comp.c | 61 ++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 34 deletions(-)
1 parent 725e097 commit de95b8d

File tree

1 file changed

+27
-34
lines changed

1 file changed

+27
-34
lines changed

arch/s390/net/bpf_jit_comp.c

Lines changed: 27 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ struct bpf_jit {
5050
int r14_thunk_ip; /* Address of expoline thunk for 'br %r14' */
5151
int tail_call_start; /* Tail call start offset */
5252
int excnt; /* Number of exception table entries */
53-
int labels[1]; /* Labels for local jumps */
5453
};
5554

5655
#define SEEN_MEM BIT(0) /* use mem[] for temporary storage */
@@ -229,18 +228,18 @@ static inline void reg_set_seen(struct bpf_jit *jit, u32 b1)
229228
REG_SET_SEEN(b3); \
230229
})
231230

232-
#define EMIT6_PCREL_LABEL(op1, op2, b1, b2, label, mask) \
231+
#define EMIT6_PCREL_RIEB(op1, op2, b1, b2, mask, target) \
233232
({ \
234-
int rel = (jit->labels[label] - jit->prg) >> 1; \
233+
unsigned int rel = (int)((target) - jit->prg) / 2; \
235234
_EMIT6((op1) | reg(b1, b2) << 16 | (rel & 0xffff), \
236235
(op2) | (mask) << 12); \
237236
REG_SET_SEEN(b1); \
238237
REG_SET_SEEN(b2); \
239238
})
240239

241-
#define EMIT6_PCREL_IMM_LABEL(op1, op2, b1, imm, label, mask) \
240+
#define EMIT6_PCREL_RIEC(op1, op2, b1, imm, mask, target) \
242241
({ \
243-
int rel = (jit->labels[label] - jit->prg) >> 1; \
242+
unsigned int rel = (int)((target) - jit->prg) / 2; \
244243
_EMIT6((op1) | (reg_high(b1) | (mask)) << 16 | \
245244
(rel & 0xffff), (op2) | ((imm) & 0xff) << 8); \
246245
REG_SET_SEEN(b1); \
@@ -1282,7 +1281,9 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
12821281
EMIT4(0xb9040000, BPF_REG_0, REG_2);
12831282
break;
12841283
}
1285-
case BPF_JMP | BPF_TAIL_CALL:
1284+
case BPF_JMP | BPF_TAIL_CALL: {
1285+
int patch_1_clrj, patch_2_clij, patch_3_brc;
1286+
12861287
/*
12871288
* Implicit input:
12881289
* B1: pointer to ctx
@@ -1300,16 +1301,10 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
13001301
EMIT6_DISP_LH(0xe3000000, 0x0016, REG_W1, REG_0, BPF_REG_2,
13011302
offsetof(struct bpf_array, map.max_entries));
13021303
/* if ((u32)%b3 >= (u32)%w1) goto out; */
1303-
if (!is_first_pass(jit) && can_use_rel(jit, jit->labels[0])) {
1304-
/* clrj %b3,%w1,0xa,label0 */
1305-
EMIT6_PCREL_LABEL(0xec000000, 0x0077, BPF_REG_3,
1306-
REG_W1, 0, 0xa);
1307-
} else {
1308-
/* clr %b3,%w1 */
1309-
EMIT2(0x1500, BPF_REG_3, REG_W1);
1310-
/* brcl 0xa,label0 */
1311-
EMIT6_PCREL_RILC(0xc0040000, 0xa, jit->labels[0]);
1312-
}
1304+
/* clrj %b3,%w1,0xa,out */
1305+
patch_1_clrj = jit->prg;
1306+
EMIT6_PCREL_RIEB(0xec000000, 0x0077, BPF_REG_3, REG_W1, 0xa,
1307+
jit->prg);
13131308

13141309
/*
13151310
* if (tail_call_cnt++ > MAX_TAIL_CALL_CNT)
@@ -1324,16 +1319,10 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
13241319
EMIT4_IMM(0xa7080000, REG_W0, 1);
13251320
/* laal %w1,%w0,off(%r15) */
13261321
EMIT6_DISP_LH(0xeb000000, 0x00fa, REG_W1, REG_W0, REG_15, off);
1327-
if (!is_first_pass(jit) && can_use_rel(jit, jit->labels[0])) {
1328-
/* clij %w1,MAX_TAIL_CALL_CNT,0x2,label0 */
1329-
EMIT6_PCREL_IMM_LABEL(0xec000000, 0x007f, REG_W1,
1330-
MAX_TAIL_CALL_CNT, 0, 0x2);
1331-
} else {
1332-
/* clfi %w1,MAX_TAIL_CALL_CNT */
1333-
EMIT6_IMM(0xc20f0000, REG_W1, MAX_TAIL_CALL_CNT);
1334-
/* brcl 0x2,label0 */
1335-
EMIT6_PCREL_RILC(0xc0040000, 0x2, jit->labels[0]);
1336-
}
1322+
/* clij %w1,MAX_TAIL_CALL_CNT,0x2,out */
1323+
patch_2_clij = jit->prg;
1324+
EMIT6_PCREL_RIEC(0xec000000, 0x007f, REG_W1, MAX_TAIL_CALL_CNT,
1325+
2, jit->prg);
13371326

13381327
/*
13391328
* prog = array->ptrs[index];
@@ -1348,13 +1337,9 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
13481337
/* ltg %r1,prog(%b2,%r1) */
13491338
EMIT6_DISP_LH(0xe3000000, 0x0002, REG_1, BPF_REG_2,
13501339
REG_1, offsetof(struct bpf_array, ptrs));
1351-
if (!is_first_pass(jit) && can_use_rel(jit, jit->labels[0])) {
1352-
/* brc 0x8,label0 */
1353-
EMIT4_PCREL_RIC(0xa7040000, 0x8, jit->labels[0]);
1354-
} else {
1355-
/* brcl 0x8,label0 */
1356-
EMIT6_PCREL_RILC(0xc0040000, 0x8, jit->labels[0]);
1357-
}
1340+
/* brc 0x8,out */
1341+
patch_3_brc = jit->prg;
1342+
EMIT4_PCREL_RIC(0xa7040000, 8, jit->prg);
13581343

13591344
/*
13601345
* Restore registers before calling function
@@ -1371,8 +1356,16 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
13711356
/* bc 0xf,tail_call_start(%r1) */
13721357
_EMIT4(0x47f01000 + jit->tail_call_start);
13731358
/* out: */
1374-
jit->labels[0] = jit->prg;
1359+
if (jit->prg_buf) {
1360+
*(u16 *)(jit->prg_buf + patch_1_clrj + 2) =
1361+
(jit->prg - patch_1_clrj) >> 1;
1362+
*(u16 *)(jit->prg_buf + patch_2_clij + 2) =
1363+
(jit->prg - patch_2_clij) >> 1;
1364+
*(u16 *)(jit->prg_buf + patch_3_brc + 2) =
1365+
(jit->prg - patch_3_brc) >> 1;
1366+
}
13751367
break;
1368+
}
13761369
case BPF_JMP | BPF_EXIT: /* return b0 */
13771370
last = (i == fp->len - 1) ? 1 : 0;
13781371
if (last)

0 commit comments

Comments
 (0)