mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-16 17:57:38 -04:00
bpf: Restrict JIT predictor flush to cBPF
Currently predictor flush on memory reuse is done for all BPF JIT allocations, but only cBPF programs can be loaded by an unprivileged user. eBPF is privileged by default, and flushing predictors for all CPUs on every eBPF reuse penalizes the common case for no security benefit. eBPF allocations can be frequent on busy systems, only flush predictors for cBPF programs. Trampoline and dispatcher allocations also skip the flush as they are eBPF-only. Signed-off-by: Pawan Gupta <pawan.kumar.gupta@linux.intel.com> Acked-by: Daniel Borkmann <daniel@iogearbox.net> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
This commit is contained in:
committed by
Daniel Borkmann
parent
a3af84b0fa
commit
0bb99f2cfa
@@ -2177,7 +2177,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr
|
||||
image_size = extable_offset + extable_size;
|
||||
ro_header = bpf_jit_binary_pack_alloc(image_size, &ro_image_ptr,
|
||||
sizeof(u64), &header, &image_ptr,
|
||||
jit_fill_hole);
|
||||
jit_fill_hole, was_classic);
|
||||
if (!ro_header)
|
||||
goto out_off;
|
||||
|
||||
@@ -2870,7 +2870,7 @@ int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags,
|
||||
|
||||
void *arch_alloc_bpf_trampoline(unsigned int size)
|
||||
{
|
||||
return bpf_prog_pack_alloc(size, jit_fill_hole);
|
||||
return bpf_prog_pack_alloc(size, jit_fill_hole, false);
|
||||
}
|
||||
|
||||
void arch_free_bpf_trampoline(void *image, unsigned int size)
|
||||
|
||||
@@ -1762,7 +1762,7 @@ static int invoke_bpf(struct jit_ctx *ctx, struct bpf_tramp_nodes *tn,
|
||||
|
||||
void *arch_alloc_bpf_trampoline(unsigned int size)
|
||||
{
|
||||
return bpf_prog_pack_alloc(size, jit_fill_hole);
|
||||
return bpf_prog_pack_alloc(size, jit_fill_hole, false);
|
||||
}
|
||||
|
||||
void arch_free_bpf_trampoline(void *image, unsigned int size)
|
||||
@@ -2228,7 +2228,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr
|
||||
image_size = prog_size + extable_size;
|
||||
/* Now we know the size of the structure to make */
|
||||
ro_header = bpf_jit_binary_pack_alloc(image_size, &ro_image_ptr, sizeof(u32),
|
||||
&header, &image_ptr, jit_fill_hole);
|
||||
&header, &image_ptr, jit_fill_hole,
|
||||
bpf_prog_was_classic(prog));
|
||||
if (!ro_header)
|
||||
goto out_offset;
|
||||
|
||||
|
||||
@@ -295,7 +295,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr
|
||||
alloclen = proglen + FUNCTION_DESCR_SIZE + fixup_len + extable_len;
|
||||
|
||||
fhdr = bpf_jit_binary_pack_alloc(alloclen, &fimage, 4, &hdr, &image,
|
||||
bpf_jit_fill_ill_insns);
|
||||
bpf_jit_fill_ill_insns, bpf_prog_was_classic(fp));
|
||||
if (!fhdr)
|
||||
goto out_err;
|
||||
|
||||
@@ -588,7 +588,7 @@ bool bpf_jit_inlines_helper_call(s32 imm)
|
||||
|
||||
void *arch_alloc_bpf_trampoline(unsigned int size)
|
||||
{
|
||||
return bpf_prog_pack_alloc(size, bpf_jit_fill_ill_insns);
|
||||
return bpf_prog_pack_alloc(size, bpf_jit_fill_ill_insns, false);
|
||||
}
|
||||
|
||||
void arch_free_bpf_trampoline(void *image, unsigned int size)
|
||||
|
||||
@@ -1321,7 +1321,7 @@ int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags,
|
||||
|
||||
void *arch_alloc_bpf_trampoline(unsigned int size)
|
||||
{
|
||||
return bpf_prog_pack_alloc(size, bpf_fill_ill_insns);
|
||||
return bpf_prog_pack_alloc(size, bpf_fill_ill_insns, false);
|
||||
}
|
||||
|
||||
void arch_free_bpf_trampoline(void *image, unsigned int size)
|
||||
|
||||
@@ -109,7 +109,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr
|
||||
bpf_jit_binary_pack_alloc(prog_size + extable_size,
|
||||
&jit_data->ro_image, sizeof(u32),
|
||||
&jit_data->header, &jit_data->image,
|
||||
bpf_fill_ill_insns);
|
||||
bpf_fill_ill_insns,
|
||||
bpf_prog_was_classic(prog));
|
||||
if (!jit_data->ro_header)
|
||||
goto out_offset;
|
||||
|
||||
|
||||
@@ -3653,7 +3653,7 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im
|
||||
|
||||
void *arch_alloc_bpf_trampoline(unsigned int size)
|
||||
{
|
||||
return bpf_prog_pack_alloc(size, jit_fill_hole);
|
||||
return bpf_prog_pack_alloc(size, jit_fill_hole, false);
|
||||
}
|
||||
|
||||
void arch_free_bpf_trampoline(void *image, unsigned int size)
|
||||
@@ -3965,7 +3965,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr
|
||||
/* allocate module memory for x86 insns and extable */
|
||||
header = bpf_jit_binary_pack_alloc(roundup(proglen, align) + extable_size,
|
||||
&image, align, &rw_header, &rw_image,
|
||||
jit_fill_hole);
|
||||
jit_fill_hole,
|
||||
bpf_prog_was_classic(prog));
|
||||
if (!header)
|
||||
goto out_addrs;
|
||||
prog->aux->extable = (void *) image + roundup(proglen, align);
|
||||
|
||||
@@ -1338,7 +1338,7 @@ void bpf_jit_free(struct bpf_prog *fp);
|
||||
struct bpf_binary_header *
|
||||
bpf_jit_binary_pack_hdr(const struct bpf_prog *fp);
|
||||
|
||||
void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns);
|
||||
void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns, bool was_classic);
|
||||
void bpf_prog_pack_free(void *ptr, u32 size);
|
||||
|
||||
static inline bool bpf_prog_kallsyms_verify_off(const struct bpf_prog *fp)
|
||||
@@ -1352,7 +1352,8 @@ bpf_jit_binary_pack_alloc(unsigned int proglen, u8 **ro_image,
|
||||
unsigned int alignment,
|
||||
struct bpf_binary_header **rw_hdr,
|
||||
u8 **rw_image,
|
||||
bpf_jit_fill_hole_t bpf_fill_ill_insns);
|
||||
bpf_jit_fill_hole_t bpf_fill_ill_insns,
|
||||
bool was_classic);
|
||||
int bpf_jit_binary_pack_finalize(struct bpf_binary_header *ro_header,
|
||||
struct bpf_binary_header *rw_header);
|
||||
void bpf_jit_binary_pack_free(struct bpf_binary_header *ro_header,
|
||||
|
||||
@@ -942,7 +942,7 @@ static struct bpf_prog_pack *alloc_new_pack(bpf_jit_fill_hole_t bpf_fill_ill_ins
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns)
|
||||
void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns, bool was_classic)
|
||||
{
|
||||
unsigned int nbits = BPF_PROG_SIZE_TO_NBITS(size);
|
||||
struct bpf_prog_pack *pack;
|
||||
@@ -957,7 +957,7 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns)
|
||||
* safe because cBPF programs (the unprivileged attack surface)
|
||||
* are bounded well below a pack size.
|
||||
*/
|
||||
if (static_branch_unlikely(&bpf_pred_flush_enabled))
|
||||
if (was_classic && static_branch_unlikely(&bpf_pred_flush_enabled))
|
||||
pr_warn_once("BPF: Predictors not flushed for allocations greater than BPF_PROG_PACK_SIZE\n");
|
||||
size = round_up(size, PAGE_SIZE);
|
||||
ptr = bpf_jit_alloc_exec(size);
|
||||
@@ -989,7 +989,9 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns)
|
||||
pos = 0;
|
||||
|
||||
found_free_area:
|
||||
static_call_cond(bpf_arch_pred_flush)();
|
||||
/* Flush only for cBPF as it may contain a crafted gadget */
|
||||
if (static_branch_unlikely(&bpf_pred_flush_enabled) && was_classic)
|
||||
static_call_cond(bpf_arch_pred_flush)();
|
||||
bitmap_set(pack->bitmap, pos, nbits);
|
||||
ptr = (void *)(pack->ptr) + (pos << BPF_PROG_CHUNK_SHIFT);
|
||||
|
||||
@@ -1149,7 +1151,8 @@ bpf_jit_binary_pack_alloc(unsigned int proglen, u8 **image_ptr,
|
||||
unsigned int alignment,
|
||||
struct bpf_binary_header **rw_header,
|
||||
u8 **rw_image,
|
||||
bpf_jit_fill_hole_t bpf_fill_ill_insns)
|
||||
bpf_jit_fill_hole_t bpf_fill_ill_insns,
|
||||
bool was_classic)
|
||||
{
|
||||
struct bpf_binary_header *ro_header;
|
||||
u32 size, hole, start;
|
||||
@@ -1162,7 +1165,7 @@ bpf_jit_binary_pack_alloc(unsigned int proglen, u8 **image_ptr,
|
||||
|
||||
if (bpf_jit_charge_modmem(size))
|
||||
return NULL;
|
||||
ro_header = bpf_prog_pack_alloc(size, bpf_fill_ill_insns);
|
||||
ro_header = bpf_prog_pack_alloc(size, bpf_fill_ill_insns, was_classic);
|
||||
if (!ro_header) {
|
||||
bpf_jit_uncharge_modmem(size);
|
||||
return NULL;
|
||||
|
||||
@@ -145,7 +145,7 @@ void bpf_dispatcher_change_prog(struct bpf_dispatcher *d, struct bpf_prog *from,
|
||||
|
||||
mutex_lock(&d->mutex);
|
||||
if (!d->image) {
|
||||
d->image = bpf_prog_pack_alloc(PAGE_SIZE, bpf_jit_fill_hole_with_zero);
|
||||
d->image = bpf_prog_pack_alloc(PAGE_SIZE, bpf_jit_fill_hole_with_zero, false);
|
||||
if (!d->image)
|
||||
goto out;
|
||||
d->rw_image = bpf_jit_alloc_exec(PAGE_SIZE);
|
||||
|
||||
Reference in New Issue
Block a user