From: Ilya Leoshkevich <iii@linux.ibm.com>
Date: Tue, 2 Jun 2020 19:43:39 +0200
Subject: s390/bpf: Maintain 8-byte stack alignment
Git-commit: effe5be17706167ee968fa28afe40dec9c6f71db
Patch-mainline: v5.8 or v5.7-rc8 (next release)
References: bsc#1169194
Certain kernel functions (e.g. get_vtimer/set_vtimer) cause kernel
panic when the stack is not 8-byte aligned. Currently JITed BPF programs
may trigger this by allocating stack frames with non-rounded sizes and
then being interrupted. Fix by using rounded fp->aux->stack_depth.
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/bpf/20200602174339.2501066-1-iii@linux.ibm.com
Acked-by: Petr Tesarik <ptesarik@suse.com>
---
arch/s390/net/bpf_jit_comp.c | 21 ++++++++++++---------
1 file changed, 12 insertions(+), 9 deletions(-)
--- a/arch/s390/net/bpf_jit_comp.c
+++ b/arch/s390/net/bpf_jit_comp.c
@@ -532,7 +532,8 @@ static void bpf_jit_epilogue(struct bpf_
* NOTE: Use noinline because for gcov (-fprofile-arcs) gcc allocates a lot of
* stack space for the large switch statement.
*/
-static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, int i)
+static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
+ int i, u32 stack_depth)
{
struct bpf_insn *insn = &fp->insnsi[i];
int jmp_off, last, insn_count = 1;
@@ -1074,7 +1075,7 @@ static noinline int bpf_jit_insn(struct
*/
if (jit->seen & SEEN_STACK)
- off = STK_OFF_TCCNT + STK_OFF + fp->aux->stack_depth;
+ off = STK_OFF_TCCNT + STK_OFF + stack_depth;
else
off = STK_OFF_TCCNT;
/* lhi %w0,1 */
@@ -1104,7 +1105,7 @@ static noinline int bpf_jit_insn(struct
/*
* Restore registers before calling function
*/
- save_restore_regs(jit, REGS_RESTORE, fp->aux->stack_depth);
+ save_restore_regs(jit, REGS_RESTORE, stack_depth);
/*
* goto *(prog->bpf_func + tail_call_start);
@@ -1323,22 +1324,23 @@ call_fn:
/*
* Compile eBPF program into s390x code
*/
-static int bpf_jit_prog(struct bpf_jit *jit, struct bpf_prog *fp)
+static int bpf_jit_prog(struct bpf_jit *jit, struct bpf_prog *fp,
+ u32 stack_depth)
{
int i, insn_count;
jit->lit = jit->lit_start;
jit->prg = 0;
- bpf_jit_prologue(jit, fp->aux->stack_depth);
+ bpf_jit_prologue(jit, stack_depth);
for (i = 0; i < fp->len; i += insn_count) {
- insn_count = bpf_jit_insn(jit, fp, i);
+ insn_count = bpf_jit_insn(jit, fp, i, stack_depth);
if (insn_count < 0)
return -1;
/* Next instruction address */
jit->addrs[i + insn_count] = jit->prg;
}
- bpf_jit_epilogue(jit, fp->aux->stack_depth);
+ bpf_jit_epilogue(jit, stack_depth);
jit->lit_start = jit->prg;
jit->size = jit->lit;
@@ -1351,6 +1353,7 @@ static int bpf_jit_prog(struct bpf_jit *
*/
struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
{
+ u32 stack_depth = round_up(fp->aux->stack_depth, 8);
struct bpf_prog *tmp, *orig_fp = fp;
struct bpf_binary_header *header;
bool tmp_blinded = false;
@@ -1384,7 +1387,7 @@ struct bpf_prog *bpf_int_jit_compile(str
* - 3: Calculate program size and addrs arrray
*/
for (pass = 1; pass <= 3; pass++) {
- if (bpf_jit_prog(&jit, fp)) {
+ if (bpf_jit_prog(&jit, fp, stack_depth)) {
fp = orig_fp;
goto free_addrs;
}
@@ -1401,7 +1404,7 @@ struct bpf_prog *bpf_int_jit_compile(str
fp = orig_fp;
goto free_addrs;
}
- if (bpf_jit_prog(&jit, fp)) {
+ if (bpf_jit_prog(&jit, fp, stack_depth)) {
bpf_jit_binary_free(header);
fp = orig_fp;
goto free_addrs;