diff options
Diffstat (limited to 'kernel/bpf/dispatcher.c')
| -rw-r--r-- | kernel/bpf/dispatcher.c | 27 | 
1 files changed, 21 insertions, 6 deletions
diff --git a/kernel/bpf/dispatcher.c b/kernel/bpf/dispatcher.c index 2444bd15cc2d..fa64b80b8bca 100644 --- a/kernel/bpf/dispatcher.c +++ b/kernel/bpf/dispatcher.c @@ -85,12 +85,12 @@ static bool bpf_dispatcher_remove_prog(struct bpf_dispatcher *d,  	return false;  } -int __weak arch_prepare_bpf_dispatcher(void *image, s64 *funcs, int num_funcs) +int __weak arch_prepare_bpf_dispatcher(void *image, void *buf, s64 *funcs, int num_funcs)  {  	return -ENOTSUPP;  } -static int bpf_dispatcher_prepare(struct bpf_dispatcher *d, void *image) +static int bpf_dispatcher_prepare(struct bpf_dispatcher *d, void *image, void *buf)  {  	s64 ips[BPF_DISPATCHER_MAX] = {}, *ipsp = &ips[0];  	int i; @@ -99,12 +99,12 @@ static int bpf_dispatcher_prepare(struct bpf_dispatcher *d, void *image)  		if (d->progs[i].prog)  			*ipsp++ = (s64)(uintptr_t)d->progs[i].prog->bpf_func;  	} -	return arch_prepare_bpf_dispatcher(image, &ips[0], d->num_progs); +	return arch_prepare_bpf_dispatcher(image, buf, &ips[0], d->num_progs);  }  static void bpf_dispatcher_update(struct bpf_dispatcher *d, int prev_num_progs)  { -	void *old, *new; +	void *old, *new, *tmp;  	u32 noff;  	int err; @@ -117,8 +117,14 @@ static void bpf_dispatcher_update(struct bpf_dispatcher *d, int prev_num_progs)  	}  	new = d->num_progs ? d->image + noff : NULL; +	tmp = d->num_progs ? d->rw_image + noff : NULL;  	if (new) { -		if (bpf_dispatcher_prepare(d, new)) +		/* Prepare the dispatcher in d->rw_image. Then use +		 * bpf_arch_text_copy to update d->image, which is RO+X. +		 */ +		if (bpf_dispatcher_prepare(d, new, tmp)) +			return; +		if (IS_ERR(bpf_arch_text_copy(new, tmp, PAGE_SIZE / 2)))  			return;  	} @@ -140,9 +146,18 @@ void bpf_dispatcher_change_prog(struct bpf_dispatcher *d, struct bpf_prog *from,  	mutex_lock(&d->mutex);  	if (!d->image) { -		d->image = bpf_jit_alloc_exec_page(); +		d->image = bpf_prog_pack_alloc(PAGE_SIZE, bpf_jit_fill_hole_with_zero);  		if (!d->image)  			goto out; +		d->rw_image = bpf_jit_alloc_exec(PAGE_SIZE); +		if (!d->rw_image) { +			u32 size = PAGE_SIZE; + +			bpf_arch_text_copy(d->image, &size, sizeof(size)); +			bpf_prog_pack_free((struct bpf_binary_header *)d->image); +			d->image = NULL; +			goto out; +		}  		bpf_image_ksym_add(d->image, &d->ksym);  	}  |