Skip to content

Commit 35cf8d9

Browse files
committed
bpf, arm64: JIT support for private stack
Private stack is allocated in bpf_int_jit_compile() with an alignment of 16. Private stack allocation size includes the stack size determined by verifier and additional space to protect stack overflow and underflow. See below an illustration: ---> memory address increasing [16 bytes to protect overflow] [normal stack] [16 bytes to protect underflow] If overflow/underflow is detected, kernel messages will be emited in dmesg like BPF private stack overflow/underflow detected for prog Fx BPF Private stack overflow/underflow detected for prog bpf_prog_a41699c234a1567a_subprog1x After commit bd737fc ("bpf, arm64: Get rid of fpb"), Jited BPF programs use the stack in two ways: 1. Via the BPF frame pointer (top of stack), using negative offsets. 2. Via the stack pointer (bottom of stack), using positive offsets in LDR/STR instructions. When a private stack is used, ARM64 callee-saved register x27 replaces the stack pointer. The frame pointer usage remains unchanged; but it now points to the top of the private stack. Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
1 parent 42be23e commit 35cf8d9

File tree

4 files changed

+132
-19
lines changed

4 files changed

+132
-19
lines changed

arch/arm64/net/bpf_jit_comp.c

Lines changed: 122 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#define TMP_REG_2 (MAX_BPF_JIT_REG + 1)
3131
#define TCCNT_PTR (MAX_BPF_JIT_REG + 2)
3232
#define TMP_REG_3 (MAX_BPF_JIT_REG + 3)
33+
#define PRIVATE_SP (MAX_BPF_JIT_REG + 4)
3334
#define ARENA_VM_START (MAX_BPF_JIT_REG + 5)
3435

3536
#define check_imm(bits, imm) do { \
@@ -68,6 +69,8 @@ static const int bpf2a64[] = {
6869
[TCCNT_PTR] = A64_R(26),
6970
/* temporary register for blinding constants */
7071
[BPF_REG_AX] = A64_R(9),
72+
/* callee saved register for private stack pointer */
73+
[PRIVATE_SP] = A64_R(27),
7174
/* callee saved register for kern_vm_start address */
7275
[ARENA_VM_START] = A64_R(28),
7376
};
@@ -86,6 +89,7 @@ struct jit_ctx {
8689
u64 user_vm_start;
8790
u64 arena_vm_start;
8891
bool fp_used;
92+
bool priv_sp_used;
8993
bool write;
9094
};
9195

@@ -98,6 +102,10 @@ struct bpf_plt {
98102
#define PLT_TARGET_SIZE sizeof_field(struct bpf_plt, target)
99103
#define PLT_TARGET_OFFSET offsetof(struct bpf_plt, target)
100104

105+
/* Memory size/value to protect private stack overflow/underflow */
106+
#define PRIV_STACK_GUARD_SZ 16
107+
#define PRIV_STACK_GUARD_VAL 0xEB9F12345678eb9fULL
108+
101109
static inline void emit(const u32 insn, struct jit_ctx *ctx)
102110
{
103111
if (ctx->image != NULL && ctx->write)
@@ -387,8 +395,11 @@ static void find_used_callee_regs(struct jit_ctx *ctx)
387395
if (reg_used & 8)
388396
ctx->used_callee_reg[i++] = bpf2a64[BPF_REG_9];
389397

390-
if (reg_used & 16)
398+
if (reg_used & 16) {
391399
ctx->used_callee_reg[i++] = bpf2a64[BPF_REG_FP];
400+
if (ctx->priv_sp_used)
401+
ctx->used_callee_reg[i++] = bpf2a64[PRIVATE_SP];
402+
}
392403

393404
if (ctx->arena_vm_start)
394405
ctx->used_callee_reg[i++] = bpf2a64[ARENA_VM_START];
@@ -461,6 +472,19 @@ static void pop_callee_regs(struct jit_ctx *ctx)
461472
}
462473
}
463474

475+
static void emit_percpu_ptr(const u8 dst_reg, void __percpu *ptr,
476+
struct jit_ctx *ctx)
477+
{
478+
const u8 tmp = bpf2a64[TMP_REG_1];
479+
480+
emit_a64_mov_i64(dst_reg, (__force const u64)ptr, ctx);
481+
if (cpus_have_cap(ARM64_HAS_VIRT_HOST_EXTN))
482+
emit(A64_MRS_TPIDR_EL2(tmp), ctx);
483+
else
484+
emit(A64_MRS_TPIDR_EL1(tmp), ctx);
485+
emit(A64_ADD(1, dst_reg, dst_reg, tmp), ctx);
486+
}
487+
464488
#define BTI_INSNS (IS_ENABLED(CONFIG_ARM64_BTI_KERNEL) ? 1 : 0)
465489
#define PAC_INSNS (IS_ENABLED(CONFIG_ARM64_PTR_AUTH_KERNEL) ? 1 : 0)
466490

@@ -476,6 +500,9 @@ static int build_prologue(struct jit_ctx *ctx, bool ebpf_from_cbpf)
476500
const bool is_main_prog = !bpf_is_subprog(prog);
477501
const u8 fp = bpf2a64[BPF_REG_FP];
478502
const u8 arena_vm_base = bpf2a64[ARENA_VM_START];
503+
const u8 priv_sp = bpf2a64[PRIVATE_SP];
504+
void __percpu *priv_stack_ptr;
505+
void __percpu *priv_frame_ptr;
479506
const int idx0 = ctx->idx;
480507
int cur_offset;
481508

@@ -551,15 +578,24 @@ static int build_prologue(struct jit_ctx *ctx, bool ebpf_from_cbpf)
551578
emit(A64_SUB_I(1, A64_SP, A64_FP, 96), ctx);
552579
}
553580

554-
if (ctx->fp_used)
555-
/* Set up BPF prog stack base register */
556-
emit(A64_MOV(1, fp, A64_SP), ctx);
557-
558581
/* Stack must be multiples of 16B */
559582
ctx->stack_size = round_up(prog->aux->stack_depth, 16);
560583

584+
if (ctx->fp_used) {
585+
if (ctx->priv_sp_used) {
586+
/* Set up private stack pointer */
587+
priv_stack_ptr = prog->aux->priv_stack_ptr + PRIV_STACK_GUARD_SZ;
588+
emit_percpu_ptr(priv_sp, priv_stack_ptr, ctx);
589+
priv_frame_ptr = priv_stack_ptr + ctx->stack_size;
590+
emit_percpu_ptr(fp, priv_frame_ptr, ctx);
591+
} else {
592+
/* Set up BPF prog stack base register */
593+
emit(A64_MOV(1, fp, A64_SP), ctx);
594+
}
595+
}
596+
561597
/* Set up function call stack */
562-
if (ctx->stack_size)
598+
if (ctx->stack_size && !ctx->priv_sp_used)
563599
emit(A64_SUB_I(1, A64_SP, A64_SP, ctx->stack_size), ctx);
564600

565601
if (ctx->arena_vm_start)
@@ -623,7 +659,7 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx)
623659
emit(A64_STR64I(tcc, ptr, 0), ctx);
624660

625661
/* restore SP */
626-
if (ctx->stack_size)
662+
if (ctx->stack_size && !ctx->priv_sp_used)
627663
emit(A64_ADD_I(1, A64_SP, A64_SP, ctx->stack_size), ctx);
628664

629665
pop_callee_regs(ctx);
@@ -991,7 +1027,7 @@ static void build_epilogue(struct jit_ctx *ctx, bool was_classic)
9911027
const u8 ptr = bpf2a64[TCCNT_PTR];
9921028

9931029
/* We're done with BPF stack */
994-
if (ctx->stack_size)
1030+
if (ctx->stack_size && !ctx->priv_sp_used)
9951031
emit(A64_ADD_I(1, A64_SP, A64_SP, ctx->stack_size), ctx);
9961032

9971033
pop_callee_regs(ctx);
@@ -1120,6 +1156,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
11201156
const u8 tmp2 = bpf2a64[TMP_REG_2];
11211157
const u8 fp = bpf2a64[BPF_REG_FP];
11221158
const u8 arena_vm_base = bpf2a64[ARENA_VM_START];
1159+
const u8 priv_sp = bpf2a64[PRIVATE_SP];
11231160
const s16 off = insn->off;
11241161
const s32 imm = insn->imm;
11251162
const int i = insn - ctx->prog->insnsi;
@@ -1564,7 +1601,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
15641601
src = tmp2;
15651602
}
15661603
if (src == fp) {
1567-
src_adj = A64_SP;
1604+
src_adj = ctx->priv_sp_used ? priv_sp : A64_SP;
15681605
off_adj = off + ctx->stack_size;
15691606
} else {
15701607
src_adj = src;
@@ -1654,7 +1691,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
16541691
dst = tmp2;
16551692
}
16561693
if (dst == fp) {
1657-
dst_adj = A64_SP;
1694+
dst_adj = ctx->priv_sp_used ? priv_sp : A64_SP;
16581695
off_adj = off + ctx->stack_size;
16591696
} else {
16601697
dst_adj = dst;
@@ -1716,7 +1753,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
17161753
dst = tmp2;
17171754
}
17181755
if (dst == fp) {
1719-
dst_adj = A64_SP;
1756+
dst_adj = ctx->priv_sp_used ? priv_sp : A64_SP;
17201757
off_adj = off + ctx->stack_size;
17211758
} else {
17221759
dst_adj = dst;
@@ -1859,6 +1896,39 @@ static inline void bpf_flush_icache(void *start, void *end)
18591896
flush_icache_range((unsigned long)start, (unsigned long)end);
18601897
}
18611898

1899+
static void priv_stack_init_guard(void __percpu *priv_stack_ptr, int alloc_size)
1900+
{
1901+
int cpu, underflow_idx = (alloc_size - PRIV_STACK_GUARD_SZ) >> 3;
1902+
u64 *stack_ptr;
1903+
1904+
for_each_possible_cpu(cpu) {
1905+
stack_ptr = per_cpu_ptr(priv_stack_ptr, cpu);
1906+
stack_ptr[0] = PRIV_STACK_GUARD_VAL;
1907+
stack_ptr[1] = PRIV_STACK_GUARD_VAL;
1908+
stack_ptr[underflow_idx] = PRIV_STACK_GUARD_VAL;
1909+
stack_ptr[underflow_idx + 1] = PRIV_STACK_GUARD_VAL;
1910+
}
1911+
}
1912+
1913+
static void priv_stack_check_guard(void __percpu *priv_stack_ptr, int alloc_size,
1914+
struct bpf_prog *prog)
1915+
{
1916+
int cpu, underflow_idx = (alloc_size - PRIV_STACK_GUARD_SZ) >> 3;
1917+
u64 *stack_ptr;
1918+
1919+
for_each_possible_cpu(cpu) {
1920+
stack_ptr = per_cpu_ptr(priv_stack_ptr, cpu);
1921+
if (stack_ptr[0] != PRIV_STACK_GUARD_VAL ||
1922+
stack_ptr[1] != PRIV_STACK_GUARD_VAL ||
1923+
stack_ptr[underflow_idx] != PRIV_STACK_GUARD_VAL ||
1924+
stack_ptr[underflow_idx + 1] != PRIV_STACK_GUARD_VAL) {
1925+
pr_err("BPF private stack overflow/underflow detected for prog %sx\n",
1926+
bpf_jit_get_prog_name(prog));
1927+
break;
1928+
}
1929+
}
1930+
}
1931+
18621932
struct arm64_jit_data {
18631933
struct bpf_binary_header *header;
18641934
u8 *ro_image;
@@ -1873,7 +1943,9 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
18731943
struct bpf_binary_header *header;
18741944
struct bpf_binary_header *ro_header;
18751945
struct arm64_jit_data *jit_data;
1946+
void __percpu *priv_stack_ptr = NULL;
18761947
bool was_classic = bpf_prog_was_classic(prog);
1948+
int priv_stack_alloc_sz;
18771949
bool tmp_blinded = false;
18781950
bool extra_pass = false;
18791951
struct jit_ctx ctx;
@@ -1905,6 +1977,23 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
19051977
}
19061978
prog->aux->jit_data = jit_data;
19071979
}
1980+
priv_stack_ptr = prog->aux->priv_stack_ptr;
1981+
if (!priv_stack_ptr && prog->aux->jits_use_priv_stack) {
1982+
/* Allocate actual private stack size with verifier-calculated
1983+
* stack size plus two memory guards to protect overflow and
1984+
* underflow.
1985+
*/
1986+
priv_stack_alloc_sz = round_up(prog->aux->stack_depth, 16) +
1987+
2 * PRIV_STACK_GUARD_SZ;
1988+
priv_stack_ptr = __alloc_percpu_gfp(priv_stack_alloc_sz, 16, GFP_KERNEL);
1989+
if (!priv_stack_ptr) {
1990+
prog = orig_prog;
1991+
goto out_priv_stack;
1992+
}
1993+
1994+
priv_stack_init_guard(priv_stack_ptr, priv_stack_alloc_sz);
1995+
prog->aux->priv_stack_ptr = priv_stack_ptr;
1996+
}
19081997
if (jit_data->ctx.offset) {
19091998
ctx = jit_data->ctx;
19101999
ro_image_ptr = jit_data->ro_image;
@@ -1928,6 +2017,9 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
19282017
ctx.user_vm_start = bpf_arena_get_user_vm_start(prog->aux->arena);
19292018
ctx.arena_vm_start = bpf_arena_get_kern_vm_start(prog->aux->arena);
19302019

2020+
if (priv_stack_ptr)
2021+
ctx.priv_sp_used = true;
2022+
19312023
/* Pass 1: Estimate the maximum image size.
19322024
*
19332025
* BPF line info needs ctx->offset[i] to be the offset of
@@ -2067,7 +2159,12 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
20672159
ctx.offset[i] *= AARCH64_INSN_SIZE;
20682160
bpf_prog_fill_jited_linfo(prog, ctx.offset + 1);
20692161
out_off:
2162+
if (!ro_header && priv_stack_ptr) {
2163+
free_percpu(priv_stack_ptr);
2164+
prog->aux->priv_stack_ptr = NULL;
2165+
}
20702166
kvfree(ctx.offset);
2167+
out_priv_stack:
20712168
kfree(jit_data);
20722169
prog->aux->jit_data = NULL;
20732170
}
@@ -2086,6 +2183,11 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
20862183
goto out_off;
20872184
}
20882185

2186+
bool bpf_jit_supports_private_stack(void)
2187+
{
2188+
return true;
2189+
}
2190+
20892191
bool bpf_jit_supports_kfunc_call(void)
20902192
{
20912193
return true;
@@ -2931,6 +3033,8 @@ void bpf_jit_free(struct bpf_prog *prog)
29313033
if (prog->jited) {
29323034
struct arm64_jit_data *jit_data = prog->aux->jit_data;
29333035
struct bpf_binary_header *hdr;
3036+
void __percpu *priv_stack_ptr;
3037+
int priv_stack_alloc_sz;
29343038

29353039
/*
29363040
* If we fail the final pass of JIT (from jit_subprogs),
@@ -2944,6 +3048,13 @@ void bpf_jit_free(struct bpf_prog *prog)
29443048
}
29453049
hdr = bpf_jit_binary_pack_hdr(prog);
29463050
bpf_jit_binary_pack_free(hdr, NULL);
3051+
priv_stack_ptr = prog->aux->priv_stack_ptr;
3052+
if (priv_stack_ptr) {
3053+
priv_stack_alloc_sz = round_up(prog->aux->stack_depth, 16) +
3054+
2 * PRIV_STACK_GUARD_SZ;
3055+
priv_stack_check_guard(priv_stack_ptr, priv_stack_alloc_sz, prog);
3056+
free_percpu(prog->aux->priv_stack_ptr);
3057+
}
29473058
WARN_ON_ONCE(!bpf_prog_kallsyms_verify_off(prog));
29483059
}
29493060

arch/x86/net/bpf_jit_comp.c

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3501,13 +3501,6 @@ int arch_prepare_bpf_dispatcher(void *image, void *buf, s64 *funcs, int num_func
35013501
return emit_bpf_dispatcher(&prog, 0, num_funcs - 1, funcs, image, buf);
35023502
}
35033503

3504-
static const char *bpf_get_prog_name(struct bpf_prog *prog)
3505-
{
3506-
if (prog->aux->ksym.prog)
3507-
return prog->aux->ksym.name;
3508-
return prog->aux->name;
3509-
}
3510-
35113504
static void priv_stack_init_guard(void __percpu *priv_stack_ptr, int alloc_size)
35123505
{
35133506
int cpu, underflow_idx = (alloc_size - PRIV_STACK_GUARD_SZ) >> 3;
@@ -3531,7 +3524,7 @@ static void priv_stack_check_guard(void __percpu *priv_stack_ptr, int alloc_size
35313524
if (stack_ptr[0] != PRIV_STACK_GUARD_VAL ||
35323525
stack_ptr[underflow_idx] != PRIV_STACK_GUARD_VAL) {
35333526
pr_err("BPF private stack overflow/underflow detected for prog %sx\n",
3534-
bpf_get_prog_name(prog));
3527+
bpf_jit_get_prog_name(prog));
35353528
break;
35363529
}
35373530
}

include/linux/filter.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,6 +1278,8 @@ int bpf_jit_get_func_addr(const struct bpf_prog *prog,
12781278
const struct bpf_insn *insn, bool extra_pass,
12791279
u64 *func_addr, bool *func_addr_fixed);
12801280

1281+
const char *bpf_jit_get_prog_name(struct bpf_prog *prog);
1282+
12811283
struct bpf_prog *bpf_jit_blind_constants(struct bpf_prog *fp);
12821284
void bpf_jit_prog_release_other(struct bpf_prog *fp, struct bpf_prog *fp_other);
12831285

kernel/bpf/core.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1297,6 +1297,13 @@ int bpf_jit_get_func_addr(const struct bpf_prog *prog,
12971297
return 0;
12981298
}
12991299

1300+
const char *bpf_jit_get_prog_name(struct bpf_prog *prog)
1301+
{
1302+
if (prog->aux->ksym.prog)
1303+
return prog->aux->ksym.name;
1304+
return prog->aux->name;
1305+
}
1306+
13001307
static int bpf_jit_blind_insn(const struct bpf_insn *from,
13011308
const struct bpf_insn *aux,
13021309
struct bpf_insn *to_buff,

0 commit comments

Comments
 (0)