[less-CONFIG_NET v2 1/8] net: reorder filter code
From: Norbert Manthey <hidden>
Date: 2018-06-28 12:46:29
Also in:
lkml
Subsystem:
bpf [general] (safe dynamic programs and tools), bpf [networking] (tcx & tc bpf, sock_addr), networking [general], the rest · Maintainers:
Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
This commit reorders the definition of functions and struct in the file filter.c, such that in the next step we can easily cut the file into a commonly used part, as well as a part that is only required in case CONFIG_NET is actually set. This is part of the effort to split CONFIG_SECCOMP_FILTER and CONFIG_NET. Signed-off-by: Norbert Manthey <redacted> --- net/core/filter.c | 330 +++++++++++++++++++++++++++--------------------------- 1 file changed, 165 insertions(+), 165 deletions(-)
diff --git a/net/core/filter.c b/net/core/filter.c
index e7f12e9..61c24c9 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c@@ -69,58 +69,6 @@ #include <net/seg6.h> #include <net/seg6_local.h> -/** - * sk_filter_trim_cap - run a packet through a socket filter - * @sk: sock associated with &sk_buff - * @skb: buffer to filter - * @cap: limit on how short the eBPF program may trim the packet - * - * Run the eBPF program and then cut skb->data to correct size returned by - * the program. If pkt_len is 0 we toss packet. If skb->len is smaller - * than pkt_len we keep whole skb->data. This is the socket level - * wrapper to BPF_PROG_RUN. It returns 0 if the packet should - * be accepted or -EPERM if the packet should be tossed. - * - */ -int sk_filter_trim_cap(struct sock *sk, struct sk_buff *skb, unsigned int cap) -{ - int err; - struct sk_filter *filter; - - /* - * If the skb was allocated from pfmemalloc reserves, only - * allow SOCK_MEMALLOC sockets to use it as this socket is - * helping free memory - */ - if (skb_pfmemalloc(skb) && !sock_flag(sk, SOCK_MEMALLOC)) { - NET_INC_STATS(sock_net(sk), LINUX_MIB_PFMEMALLOCDROP); - return -ENOMEM; - } - err = BPF_CGROUP_RUN_PROG_INET_INGRESS(sk, skb); - if (err) - return err; - - err = security_sock_rcv_skb(sk, skb); - if (err) - return err; - - rcu_read_lock(); - filter = rcu_dereference(sk->sk_filter); - if (filter) { - struct sock *save_sk = skb->sk; - unsigned int pkt_len; - - skb->sk = sk; - pkt_len = bpf_prog_run_save_cb(filter->prog, skb); - skb->sk = save_sk; - err = pkt_len ? pskb_trim(skb, max(cap, pkt_len)) : -EPERM; - } - rcu_read_unlock(); - - return err; -} -EXPORT_SYMBOL(sk_filter_trim_cap); - BPF_CALL_1(bpf_skb_get_pay_offset, struct sk_buff *, skb) { return skb_get_poff(skb);
@@ -256,12 +204,6 @@ BPF_CALL_0(bpf_get_raw_cpu_id) return raw_smp_processor_id(); } -static const struct bpf_func_proto bpf_get_raw_smp_processor_id_proto = { - .func = bpf_get_raw_cpu_id, - .gpl_only = false, - .ret_type = RET_INTEGER, -}; - static u32 convert_skb_access(int skb_field, int dst_reg, int src_reg, struct bpf_insn *insn_buf) {
@@ -1138,71 +1080,6 @@ static void __bpf_prog_release(struct bpf_prog *prog) } } -static void __sk_filter_release(struct sk_filter *fp) -{ - __bpf_prog_release(fp->prog); - kfree(fp); -} - -/** - * sk_filter_release_rcu - Release a socket filter by rcu_head - * @rcu: rcu_head that contains the sk_filter to free - */ -static void sk_filter_release_rcu(struct rcu_head *rcu) -{ - struct sk_filter *fp = container_of(rcu, struct sk_filter, rcu); - - __sk_filter_release(fp); -} - -/** - * sk_filter_release - release a socket filter - * @fp: filter to remove - * - * Remove a filter from a socket and release its resources. - */ -static void sk_filter_release(struct sk_filter *fp) -{ - if (refcount_dec_and_test(&fp->refcnt)) - call_rcu(&fp->rcu, sk_filter_release_rcu); -} - -void sk_filter_uncharge(struct sock *sk, struct sk_filter *fp) -{ - u32 filter_size = bpf_prog_size(fp->prog->len); - - atomic_sub(filter_size, &sk->sk_omem_alloc); - sk_filter_release(fp); -} - -/* try to charge the socket memory if there is space available - * return true on success - */ -static bool __sk_filter_charge(struct sock *sk, struct sk_filter *fp) -{ - u32 filter_size = bpf_prog_size(fp->prog->len); - - /* same check as in sock_kmalloc() */ - if (filter_size <= sysctl_optmem_max && - atomic_read(&sk->sk_omem_alloc) + filter_size < sysctl_optmem_max) { - atomic_add(filter_size, &sk->sk_omem_alloc); - return true; - } - return false; -} - -bool sk_filter_charge(struct sock *sk, struct sk_filter *fp) -{ - if (!refcount_inc_not_zero(&fp->refcnt)) - return false; - - if (!__sk_filter_charge(sk, fp)) { - sk_filter_release(fp); - return false; - } - return true; -} - static struct bpf_prog *bpf_migrate_filter(struct bpf_prog *fp) { struct sock_filter *old_prog;
@@ -1314,19 +1191,22 @@ static struct bpf_prog *bpf_prepare_filter(struct bpf_prog *fp, } /** - * bpf_prog_create - create an unattached filter + * bpf_prog_create_from_user - create an unattached filter from user buffer * @pfp: the unattached filter that is created * @fprog: the filter program + * @trans: post-classic verifier transformation handler + * @save_orig: save classic BPF program * - * Create a filter independent of any socket. We first run some - * sanity checks on it to make sure it does not explode on us later. - * If an error occurs or there is insufficient memory for the filter - * a negative errno code is returned. On success the return is zero. + * This function effectively does the same as bpf_prog_create(), only + * that it builds up its insns buffer from user space provided buffer. + * It also allows for passing a bpf_aux_classic_check_t handler. */ -int bpf_prog_create(struct bpf_prog **pfp, struct sock_fprog_kern *fprog) +int bpf_prog_create_from_user(struct bpf_prog **pfp, struct sock_fprog *fprog, + bpf_aux_classic_check_t trans, bool save_orig) { unsigned int fsize = bpf_classic_proglen(fprog); struct bpf_prog *fp; + int err; /* Make sure new filter is there and in the right amounts. */ if (!bpf_check_basics_ok(fprog->filter, fprog->len))
@@ -1336,44 +1216,177 @@ int bpf_prog_create(struct bpf_prog **pfp, struct sock_fprog_kern *fprog) if (!fp) return -ENOMEM; - memcpy(fp->insns, fprog->filter, fsize); + if (copy_from_user(fp->insns, fprog->filter, fsize)) { + __bpf_prog_free(fp); + return -EFAULT; + } fp->len = fprog->len; - /* Since unattached filters are not copied back to user - * space through sk_get_filter(), we do not need to hold - * a copy here, and can spare us the work. - */ fp->orig_prog = NULL; + if (save_orig) { + err = bpf_prog_store_orig_filter(fp, fprog); + if (err) { + __bpf_prog_free(fp); + return -ENOMEM; + } + } + /* bpf_prepare_filter() already takes care of freeing * memory in case something goes wrong. */ - fp = bpf_prepare_filter(fp, NULL); + fp = bpf_prepare_filter(fp, trans); if (IS_ERR(fp)) return PTR_ERR(fp); *pfp = fp; return 0; } -EXPORT_SYMBOL_GPL(bpf_prog_create); +EXPORT_SYMBOL_GPL(bpf_prog_create_from_user); + +void bpf_prog_destroy(struct bpf_prog *fp) +{ + __bpf_prog_release(fp); +} +EXPORT_SYMBOL_GPL(bpf_prog_destroy); /** - * bpf_prog_create_from_user - create an unattached filter from user buffer + * sk_filter_trim_cap - run a packet through a socket filter + * @sk: sock associated with &sk_buff + * @skb: buffer to filter + * @cap: limit on how short the eBPF program may trim the packet + * + * Run the eBPF program and then cut skb->data to correct size returned by + * the program. If pkt_len is 0 we toss packet. If skb->len is smaller + * than pkt_len we keep whole skb->data. This is the socket level + * wrapper to BPF_PROG_RUN. It returns 0 if the packet should + * be accepted or -EPERM if the packet should be tossed. + * + */ +int sk_filter_trim_cap(struct sock *sk, struct sk_buff *skb, unsigned int cap) +{ + int err; + struct sk_filter *filter; + + /* + * If the skb was allocated from pfmemalloc reserves, only + * allow SOCK_MEMALLOC sockets to use it as this socket is + * helping free memory + */ + if (skb_pfmemalloc(skb) && !sock_flag(sk, SOCK_MEMALLOC)) { + NET_INC_STATS(sock_net(sk), LINUX_MIB_PFMEMALLOCDROP); + return -ENOMEM; + } + err = BPF_CGROUP_RUN_PROG_INET_INGRESS(sk, skb); + if (err) + return err; + + err = security_sock_rcv_skb(sk, skb); + if (err) + return err; + + rcu_read_lock(); + filter = rcu_dereference(sk->sk_filter); + if (filter) { + struct sock *save_sk = skb->sk; + unsigned int pkt_len; + + skb->sk = sk; + pkt_len = bpf_prog_run_save_cb(filter->prog, skb); + skb->sk = save_sk; + err = pkt_len ? pskb_trim(skb, max(cap, pkt_len)) : -EPERM; + } + rcu_read_unlock(); + + return err; +} +EXPORT_SYMBOL(sk_filter_trim_cap); + +static const struct bpf_func_proto bpf_get_raw_smp_processor_id_proto = { + .func = bpf_get_raw_cpu_id, + .gpl_only = false, + .ret_type = RET_INTEGER, +}; + +static void __sk_filter_release(struct sk_filter *fp) +{ + __bpf_prog_release(fp->prog); + kfree(fp); +} + +/** + * sk_filter_release_rcu - Release a socket filter by rcu_head + * @rcu: rcu_head that contains the sk_filter to free + */ +static void sk_filter_release_rcu(struct rcu_head *rcu) +{ + struct sk_filter *fp = container_of(rcu, struct sk_filter, rcu); + + __sk_filter_release(fp); +} + +/** + * sk_filter_release - release a socket filter + * @fp: filter to remove + * + * Remove a filter from a socket and release its resources. + */ +static void sk_filter_release(struct sk_filter *fp) +{ + if (refcount_dec_and_test(&fp->refcnt)) + call_rcu(&fp->rcu, sk_filter_release_rcu); +} + +void sk_filter_uncharge(struct sock *sk, struct sk_filter *fp) +{ + u32 filter_size = bpf_prog_size(fp->prog->len); + + atomic_sub(filter_size, &sk->sk_omem_alloc); + sk_filter_release(fp); +} + +/* try to charge the socket memory if there is space available + * return true on success + */ +static bool __sk_filter_charge(struct sock *sk, struct sk_filter *fp) +{ + u32 filter_size = bpf_prog_size(fp->prog->len); + + /* same check as in sock_kmalloc() */ + if (filter_size <= sysctl_optmem_max && + atomic_read(&sk->sk_omem_alloc) + filter_size < sysctl_optmem_max) { + atomic_add(filter_size, &sk->sk_omem_alloc); + return true; + } + return false; +} + +bool sk_filter_charge(struct sock *sk, struct sk_filter *fp) +{ + if (!refcount_inc_not_zero(&fp->refcnt)) + return false; + + if (!__sk_filter_charge(sk, fp)) { + sk_filter_release(fp); + return false; + } + return true; +} + +/** + * bpf_prog_create - create an unattached filter * @pfp: the unattached filter that is created * @fprog: the filter program - * @trans: post-classic verifier transformation handler - * @save_orig: save classic BPF program * - * This function effectively does the same as bpf_prog_create(), only - * that it builds up its insns buffer from user space provided buffer. - * It also allows for passing a bpf_aux_classic_check_t handler. + * Create a filter independent of any socket. We first run some + * sanity checks on it to make sure it does not explode on us later. + * If an error occurs or there is insufficient memory for the filter + * a negative errno code is returned. On success the return is zero. */ -int bpf_prog_create_from_user(struct bpf_prog **pfp, struct sock_fprog *fprog, - bpf_aux_classic_check_t trans, bool save_orig) +int bpf_prog_create(struct bpf_prog **pfp, struct sock_fprog_kern *fprog) { unsigned int fsize = bpf_classic_proglen(fprog); struct bpf_prog *fp; - int err; /* Make sure new filter is there and in the right amounts. */ if (!bpf_check_basics_ok(fprog->filter, fprog->len))
@@ -1383,39 +1396,26 @@ int bpf_prog_create_from_user(struct bpf_prog **pfp, struct sock_fprog *fprog, if (!fp) return -ENOMEM; - if (copy_from_user(fp->insns, fprog->filter, fsize)) { - __bpf_prog_free(fp); - return -EFAULT; - } + memcpy(fp->insns, fprog->filter, fsize); fp->len = fprog->len; + /* Since unattached filters are not copied back to user + * space through sk_get_filter(), we do not need to hold + * a copy here, and can spare us the work. + */ fp->orig_prog = NULL; - if (save_orig) { - err = bpf_prog_store_orig_filter(fp, fprog); - if (err) { - __bpf_prog_free(fp); - return -ENOMEM; - } - } - /* bpf_prepare_filter() already takes care of freeing * memory in case something goes wrong. */ - fp = bpf_prepare_filter(fp, trans); + fp = bpf_prepare_filter(fp, NULL); if (IS_ERR(fp)) return PTR_ERR(fp); *pfp = fp; return 0; } -EXPORT_SYMBOL_GPL(bpf_prog_create_from_user); - -void bpf_prog_destroy(struct bpf_prog *fp) -{ - __bpf_prog_release(fp); -} -EXPORT_SYMBOL_GPL(bpf_prog_destroy); +EXPORT_SYMBOL_GPL(bpf_prog_create); static int __sk_attach_prog(struct bpf_prog *prog, struct sock *sk) {
--
2.7.4
Amazon Development Center Germany GmbH
Berlin - Dresden - Aachen
main office: Krausenstr. 38, 10117 Berlin
Geschaeftsfuehrer: Dr. Ralf Herbrich, Christian Schlaeger
Ust-ID: DE289237879
Eingetragen am Amtsgericht Charlottenburg HRB 149173 B