184601d6eSFlorian Westphal // SPDX-License-Identifier: GPL-2.0
284601d6eSFlorian Westphal #include <linux/bpf.h>
3fd9c663bSFlorian Westphal #include <linux/filter.h>
491721c2dSDaniel Xu #include <linux/kmod.h>
591721c2dSDaniel Xu #include <linux/module.h>
684601d6eSFlorian Westphal #include <linux/netfilter.h>
784601d6eSFlorian Westphal
884601d6eSFlorian Westphal #include <net/netfilter/nf_bpf_link.h>
984601d6eSFlorian Westphal #include <uapi/linux/netfilter_ipv4.h>
1084601d6eSFlorian Westphal
nf_hook_run_bpf(void * bpf_prog,struct sk_buff * skb,const struct nf_hook_state * s)1184601d6eSFlorian Westphal static unsigned int nf_hook_run_bpf(void *bpf_prog, struct sk_buff *skb,
1284601d6eSFlorian Westphal const struct nf_hook_state *s)
1384601d6eSFlorian Westphal {
14fd9c663bSFlorian Westphal const struct bpf_prog *prog = bpf_prog;
15fd9c663bSFlorian Westphal struct bpf_nf_ctx ctx = {
16fd9c663bSFlorian Westphal .state = s,
17fd9c663bSFlorian Westphal .skb = skb,
18fd9c663bSFlorian Westphal };
19fd9c663bSFlorian Westphal
20fd9c663bSFlorian Westphal return bpf_prog_run(prog, &ctx);
2184601d6eSFlorian Westphal }
2284601d6eSFlorian Westphal
2384601d6eSFlorian Westphal struct bpf_nf_link {
2484601d6eSFlorian Westphal struct bpf_link link;
2584601d6eSFlorian Westphal struct nf_hook_ops hook_ops;
2684601d6eSFlorian Westphal struct net *net;
2784601d6eSFlorian Westphal u32 dead;
2891721c2dSDaniel Xu const struct nf_defrag_hook *defrag_hook;
2984601d6eSFlorian Westphal };
3084601d6eSFlorian Westphal
3181584c23SDaniel Xu #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV4) || IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
3291721c2dSDaniel Xu static const struct nf_defrag_hook *
get_proto_defrag_hook(struct bpf_nf_link * link,const struct nf_defrag_hook __rcu ** ptr_global_hook,const char * mod)3391721c2dSDaniel Xu get_proto_defrag_hook(struct bpf_nf_link *link,
34*83e98637SD. Wythe const struct nf_defrag_hook __rcu **ptr_global_hook,
3591721c2dSDaniel Xu const char *mod)
3691721c2dSDaniel Xu {
3791721c2dSDaniel Xu const struct nf_defrag_hook *hook;
3891721c2dSDaniel Xu int err;
3991721c2dSDaniel Xu
4091721c2dSDaniel Xu /* RCU protects us from races against module unloading */
4191721c2dSDaniel Xu rcu_read_lock();
42*83e98637SD. Wythe hook = rcu_dereference(*ptr_global_hook);
4391721c2dSDaniel Xu if (!hook) {
4491721c2dSDaniel Xu rcu_read_unlock();
4591721c2dSDaniel Xu err = request_module(mod);
4691721c2dSDaniel Xu if (err)
4791721c2dSDaniel Xu return ERR_PTR(err < 0 ? err : -EINVAL);
4891721c2dSDaniel Xu
4991721c2dSDaniel Xu rcu_read_lock();
50*83e98637SD. Wythe hook = rcu_dereference(*ptr_global_hook);
5191721c2dSDaniel Xu }
5291721c2dSDaniel Xu
5391721c2dSDaniel Xu if (hook && try_module_get(hook->owner)) {
5491721c2dSDaniel Xu /* Once we have a refcnt on the module, we no longer need RCU */
5591721c2dSDaniel Xu hook = rcu_pointer_handoff(hook);
5691721c2dSDaniel Xu } else {
5791721c2dSDaniel Xu WARN_ONCE(!hook, "%s has bad registration", mod);
5891721c2dSDaniel Xu hook = ERR_PTR(-ENOENT);
5991721c2dSDaniel Xu }
6091721c2dSDaniel Xu rcu_read_unlock();
6191721c2dSDaniel Xu
6291721c2dSDaniel Xu if (!IS_ERR(hook)) {
6391721c2dSDaniel Xu err = hook->enable(link->net);
6491721c2dSDaniel Xu if (err) {
6591721c2dSDaniel Xu module_put(hook->owner);
6691721c2dSDaniel Xu hook = ERR_PTR(err);
6791721c2dSDaniel Xu }
6891721c2dSDaniel Xu }
6991721c2dSDaniel Xu
7091721c2dSDaniel Xu return hook;
7191721c2dSDaniel Xu }
7281584c23SDaniel Xu #endif
7391721c2dSDaniel Xu
bpf_nf_enable_defrag(struct bpf_nf_link * link)7491721c2dSDaniel Xu static int bpf_nf_enable_defrag(struct bpf_nf_link *link)
7591721c2dSDaniel Xu {
7691721c2dSDaniel Xu const struct nf_defrag_hook __maybe_unused *hook;
7791721c2dSDaniel Xu
7891721c2dSDaniel Xu switch (link->hook_ops.pf) {
7991721c2dSDaniel Xu #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV4)
8091721c2dSDaniel Xu case NFPROTO_IPV4:
81*83e98637SD. Wythe hook = get_proto_defrag_hook(link, &nf_defrag_v4_hook, "nf_defrag_ipv4");
8291721c2dSDaniel Xu if (IS_ERR(hook))
8391721c2dSDaniel Xu return PTR_ERR(hook);
8491721c2dSDaniel Xu
8591721c2dSDaniel Xu link->defrag_hook = hook;
8691721c2dSDaniel Xu return 0;
8791721c2dSDaniel Xu #endif
8891721c2dSDaniel Xu #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
8991721c2dSDaniel Xu case NFPROTO_IPV6:
90*83e98637SD. Wythe hook = get_proto_defrag_hook(link, &nf_defrag_v6_hook, "nf_defrag_ipv6");
9191721c2dSDaniel Xu if (IS_ERR(hook))
9291721c2dSDaniel Xu return PTR_ERR(hook);
9391721c2dSDaniel Xu
9491721c2dSDaniel Xu link->defrag_hook = hook;
9591721c2dSDaniel Xu return 0;
9691721c2dSDaniel Xu #endif
9791721c2dSDaniel Xu default:
9891721c2dSDaniel Xu return -EAFNOSUPPORT;
9991721c2dSDaniel Xu }
10091721c2dSDaniel Xu }
10191721c2dSDaniel Xu
bpf_nf_disable_defrag(struct bpf_nf_link * link)10291721c2dSDaniel Xu static void bpf_nf_disable_defrag(struct bpf_nf_link *link)
10391721c2dSDaniel Xu {
10491721c2dSDaniel Xu const struct nf_defrag_hook *hook = link->defrag_hook;
10591721c2dSDaniel Xu
10691721c2dSDaniel Xu if (!hook)
10791721c2dSDaniel Xu return;
10891721c2dSDaniel Xu hook->disable(link->net);
10991721c2dSDaniel Xu module_put(hook->owner);
11091721c2dSDaniel Xu }
11191721c2dSDaniel Xu
bpf_nf_link_release(struct bpf_link * link)11284601d6eSFlorian Westphal static void bpf_nf_link_release(struct bpf_link *link)
11384601d6eSFlorian Westphal {
11484601d6eSFlorian Westphal struct bpf_nf_link *nf_link = container_of(link, struct bpf_nf_link, link);
11584601d6eSFlorian Westphal
11684601d6eSFlorian Westphal if (nf_link->dead)
11784601d6eSFlorian Westphal return;
11884601d6eSFlorian Westphal
11991721c2dSDaniel Xu /* do not double release in case .detach was already called */
12091721c2dSDaniel Xu if (!cmpxchg(&nf_link->dead, 0, 1)) {
12184601d6eSFlorian Westphal nf_unregister_net_hook(nf_link->net, &nf_link->hook_ops);
12291721c2dSDaniel Xu bpf_nf_disable_defrag(nf_link);
12391721c2dSDaniel Xu }
12484601d6eSFlorian Westphal }
12584601d6eSFlorian Westphal
bpf_nf_link_dealloc(struct bpf_link * link)12684601d6eSFlorian Westphal static void bpf_nf_link_dealloc(struct bpf_link *link)
12784601d6eSFlorian Westphal {
12884601d6eSFlorian Westphal struct bpf_nf_link *nf_link = container_of(link, struct bpf_nf_link, link);
12984601d6eSFlorian Westphal
13084601d6eSFlorian Westphal kfree(nf_link);
13184601d6eSFlorian Westphal }
13284601d6eSFlorian Westphal
bpf_nf_link_detach(struct bpf_link * link)13384601d6eSFlorian Westphal static int bpf_nf_link_detach(struct bpf_link *link)
13484601d6eSFlorian Westphal {
13584601d6eSFlorian Westphal bpf_nf_link_release(link);
13684601d6eSFlorian Westphal return 0;
13784601d6eSFlorian Westphal }
13884601d6eSFlorian Westphal
bpf_nf_link_show_info(const struct bpf_link * link,struct seq_file * seq)13984601d6eSFlorian Westphal static void bpf_nf_link_show_info(const struct bpf_link *link,
14084601d6eSFlorian Westphal struct seq_file *seq)
14184601d6eSFlorian Westphal {
14284601d6eSFlorian Westphal struct bpf_nf_link *nf_link = container_of(link, struct bpf_nf_link, link);
14384601d6eSFlorian Westphal
14484601d6eSFlorian Westphal seq_printf(seq, "pf:\t%u\thooknum:\t%u\tprio:\t%d\n",
14584601d6eSFlorian Westphal nf_link->hook_ops.pf, nf_link->hook_ops.hooknum,
14684601d6eSFlorian Westphal nf_link->hook_ops.priority);
14784601d6eSFlorian Westphal }
14884601d6eSFlorian Westphal
bpf_nf_link_fill_link_info(const struct bpf_link * link,struct bpf_link_info * info)14984601d6eSFlorian Westphal static int bpf_nf_link_fill_link_info(const struct bpf_link *link,
15084601d6eSFlorian Westphal struct bpf_link_info *info)
15184601d6eSFlorian Westphal {
15284601d6eSFlorian Westphal struct bpf_nf_link *nf_link = container_of(link, struct bpf_nf_link, link);
15384601d6eSFlorian Westphal
15484601d6eSFlorian Westphal info->netfilter.pf = nf_link->hook_ops.pf;
15584601d6eSFlorian Westphal info->netfilter.hooknum = nf_link->hook_ops.hooknum;
15684601d6eSFlorian Westphal info->netfilter.priority = nf_link->hook_ops.priority;
15784601d6eSFlorian Westphal info->netfilter.flags = 0;
15884601d6eSFlorian Westphal
15984601d6eSFlorian Westphal return 0;
16084601d6eSFlorian Westphal }
16184601d6eSFlorian Westphal
bpf_nf_link_update(struct bpf_link * link,struct bpf_prog * new_prog,struct bpf_prog * old_prog)16284601d6eSFlorian Westphal static int bpf_nf_link_update(struct bpf_link *link, struct bpf_prog *new_prog,
16384601d6eSFlorian Westphal struct bpf_prog *old_prog)
16484601d6eSFlorian Westphal {
16584601d6eSFlorian Westphal return -EOPNOTSUPP;
16684601d6eSFlorian Westphal }
16784601d6eSFlorian Westphal
16884601d6eSFlorian Westphal static const struct bpf_link_ops bpf_nf_link_lops = {
16984601d6eSFlorian Westphal .release = bpf_nf_link_release,
17084601d6eSFlorian Westphal .dealloc = bpf_nf_link_dealloc,
17184601d6eSFlorian Westphal .detach = bpf_nf_link_detach,
17284601d6eSFlorian Westphal .show_fdinfo = bpf_nf_link_show_info,
17384601d6eSFlorian Westphal .fill_link_info = bpf_nf_link_fill_link_info,
17484601d6eSFlorian Westphal .update_prog = bpf_nf_link_update,
17584601d6eSFlorian Westphal };
17684601d6eSFlorian Westphal
bpf_nf_check_pf_and_hooks(const union bpf_attr * attr)17784601d6eSFlorian Westphal static int bpf_nf_check_pf_and_hooks(const union bpf_attr *attr)
17884601d6eSFlorian Westphal {
17991721c2dSDaniel Xu int prio;
18091721c2dSDaniel Xu
18184601d6eSFlorian Westphal switch (attr->link_create.netfilter.pf) {
18284601d6eSFlorian Westphal case NFPROTO_IPV4:
18384601d6eSFlorian Westphal case NFPROTO_IPV6:
18484601d6eSFlorian Westphal if (attr->link_create.netfilter.hooknum >= NF_INET_NUMHOOKS)
18584601d6eSFlorian Westphal return -EPROTO;
18684601d6eSFlorian Westphal break;
18784601d6eSFlorian Westphal default:
18884601d6eSFlorian Westphal return -EAFNOSUPPORT;
18984601d6eSFlorian Westphal }
19084601d6eSFlorian Westphal
19191721c2dSDaniel Xu if (attr->link_create.netfilter.flags & ~BPF_F_NETFILTER_IP_DEFRAG)
19284601d6eSFlorian Westphal return -EOPNOTSUPP;
19384601d6eSFlorian Westphal
19491721c2dSDaniel Xu /* make sure conntrack confirm is always last */
19591721c2dSDaniel Xu prio = attr->link_create.netfilter.priority;
19691721c2dSDaniel Xu if (prio == NF_IP_PRI_FIRST)
19791721c2dSDaniel Xu return -ERANGE; /* sabotage_in and other warts */
19891721c2dSDaniel Xu else if (prio == NF_IP_PRI_LAST)
19991721c2dSDaniel Xu return -ERANGE; /* e.g. conntrack confirm */
20091721c2dSDaniel Xu else if ((attr->link_create.netfilter.flags & BPF_F_NETFILTER_IP_DEFRAG) &&
20191721c2dSDaniel Xu prio <= NF_IP_PRI_CONNTRACK_DEFRAG)
20291721c2dSDaniel Xu return -ERANGE; /* cannot use defrag if prog runs before nf_defrag */
20384601d6eSFlorian Westphal
20484601d6eSFlorian Westphal return 0;
20584601d6eSFlorian Westphal }
20684601d6eSFlorian Westphal
bpf_nf_link_attach(const union bpf_attr * attr,struct bpf_prog * prog)20784601d6eSFlorian Westphal int bpf_nf_link_attach(const union bpf_attr *attr, struct bpf_prog *prog)
20884601d6eSFlorian Westphal {
20984601d6eSFlorian Westphal struct net *net = current->nsproxy->net_ns;
21084601d6eSFlorian Westphal struct bpf_link_primer link_primer;
21184601d6eSFlorian Westphal struct bpf_nf_link *link;
21284601d6eSFlorian Westphal int err;
21384601d6eSFlorian Westphal
21484601d6eSFlorian Westphal if (attr->link_create.flags)
21584601d6eSFlorian Westphal return -EINVAL;
21684601d6eSFlorian Westphal
21784601d6eSFlorian Westphal err = bpf_nf_check_pf_and_hooks(attr);
21884601d6eSFlorian Westphal if (err)
21984601d6eSFlorian Westphal return err;
22084601d6eSFlorian Westphal
22184601d6eSFlorian Westphal link = kzalloc(sizeof(*link), GFP_USER);
22284601d6eSFlorian Westphal if (!link)
22384601d6eSFlorian Westphal return -ENOMEM;
22484601d6eSFlorian Westphal
22584601d6eSFlorian Westphal bpf_link_init(&link->link, BPF_LINK_TYPE_NETFILTER, &bpf_nf_link_lops, prog);
22684601d6eSFlorian Westphal
22784601d6eSFlorian Westphal link->hook_ops.hook = nf_hook_run_bpf;
22884601d6eSFlorian Westphal link->hook_ops.hook_ops_type = NF_HOOK_OP_BPF;
22984601d6eSFlorian Westphal link->hook_ops.priv = prog;
23084601d6eSFlorian Westphal
23184601d6eSFlorian Westphal link->hook_ops.pf = attr->link_create.netfilter.pf;
23284601d6eSFlorian Westphal link->hook_ops.priority = attr->link_create.netfilter.priority;
23384601d6eSFlorian Westphal link->hook_ops.hooknum = attr->link_create.netfilter.hooknum;
23484601d6eSFlorian Westphal
23584601d6eSFlorian Westphal link->net = net;
23684601d6eSFlorian Westphal link->dead = false;
23791721c2dSDaniel Xu link->defrag_hook = NULL;
23884601d6eSFlorian Westphal
23984601d6eSFlorian Westphal err = bpf_link_prime(&link->link, &link_primer);
24084601d6eSFlorian Westphal if (err) {
24184601d6eSFlorian Westphal kfree(link);
24284601d6eSFlorian Westphal return err;
24384601d6eSFlorian Westphal }
24484601d6eSFlorian Westphal
24591721c2dSDaniel Xu if (attr->link_create.netfilter.flags & BPF_F_NETFILTER_IP_DEFRAG) {
24691721c2dSDaniel Xu err = bpf_nf_enable_defrag(link);
24791721c2dSDaniel Xu if (err) {
24891721c2dSDaniel Xu bpf_link_cleanup(&link_primer);
24991721c2dSDaniel Xu return err;
25091721c2dSDaniel Xu }
25191721c2dSDaniel Xu }
25291721c2dSDaniel Xu
25384601d6eSFlorian Westphal err = nf_register_net_hook(net, &link->hook_ops);
25484601d6eSFlorian Westphal if (err) {
25591721c2dSDaniel Xu bpf_nf_disable_defrag(link);
25684601d6eSFlorian Westphal bpf_link_cleanup(&link_primer);
25784601d6eSFlorian Westphal return err;
25884601d6eSFlorian Westphal }
25984601d6eSFlorian Westphal
26084601d6eSFlorian Westphal return bpf_link_settle(&link_primer);
26184601d6eSFlorian Westphal }
262fd9c663bSFlorian Westphal
263fd9c663bSFlorian Westphal const struct bpf_prog_ops netfilter_prog_ops = {
2642b99ef22SFlorian Westphal .test_run = bpf_prog_test_run_nf,
265fd9c663bSFlorian Westphal };
266fd9c663bSFlorian Westphal
nf_ptr_to_btf_id(struct bpf_insn_access_aux * info,const char * name)267fd9c663bSFlorian Westphal static bool nf_ptr_to_btf_id(struct bpf_insn_access_aux *info, const char *name)
268fd9c663bSFlorian Westphal {
269fd9c663bSFlorian Westphal struct btf *btf;
270fd9c663bSFlorian Westphal s32 type_id;
271fd9c663bSFlorian Westphal
272fd9c663bSFlorian Westphal btf = bpf_get_btf_vmlinux();
273fd9c663bSFlorian Westphal if (IS_ERR_OR_NULL(btf))
274fd9c663bSFlorian Westphal return false;
275fd9c663bSFlorian Westphal
276fd9c663bSFlorian Westphal type_id = btf_find_by_name_kind(btf, name, BTF_KIND_STRUCT);
277fd9c663bSFlorian Westphal if (WARN_ON_ONCE(type_id < 0))
278fd9c663bSFlorian Westphal return false;
279fd9c663bSFlorian Westphal
280fd9c663bSFlorian Westphal info->btf = btf;
281fd9c663bSFlorian Westphal info->btf_id = type_id;
282fd9c663bSFlorian Westphal info->reg_type = PTR_TO_BTF_ID | PTR_TRUSTED;
283fd9c663bSFlorian Westphal return true;
284fd9c663bSFlorian Westphal }
285fd9c663bSFlorian Westphal
nf_is_valid_access(int off,int size,enum bpf_access_type type,const struct bpf_prog * prog,struct bpf_insn_access_aux * info)286fd9c663bSFlorian Westphal static bool nf_is_valid_access(int off, int size, enum bpf_access_type type,
287fd9c663bSFlorian Westphal const struct bpf_prog *prog,
288fd9c663bSFlorian Westphal struct bpf_insn_access_aux *info)
289fd9c663bSFlorian Westphal {
290fd9c663bSFlorian Westphal if (off < 0 || off >= sizeof(struct bpf_nf_ctx))
291fd9c663bSFlorian Westphal return false;
292fd9c663bSFlorian Westphal
293fd9c663bSFlorian Westphal if (type == BPF_WRITE)
294fd9c663bSFlorian Westphal return false;
295fd9c663bSFlorian Westphal
296fd9c663bSFlorian Westphal switch (off) {
297fd9c663bSFlorian Westphal case bpf_ctx_range(struct bpf_nf_ctx, skb):
298fd9c663bSFlorian Westphal if (size != sizeof_field(struct bpf_nf_ctx, skb))
299fd9c663bSFlorian Westphal return false;
300fd9c663bSFlorian Westphal
301fd9c663bSFlorian Westphal return nf_ptr_to_btf_id(info, "sk_buff");
302fd9c663bSFlorian Westphal case bpf_ctx_range(struct bpf_nf_ctx, state):
303fd9c663bSFlorian Westphal if (size != sizeof_field(struct bpf_nf_ctx, state))
304fd9c663bSFlorian Westphal return false;
305fd9c663bSFlorian Westphal
306fd9c663bSFlorian Westphal return nf_ptr_to_btf_id(info, "nf_hook_state");
307fd9c663bSFlorian Westphal default:
308fd9c663bSFlorian Westphal return false;
309fd9c663bSFlorian Westphal }
310fd9c663bSFlorian Westphal
311fd9c663bSFlorian Westphal return false;
312fd9c663bSFlorian Westphal }
313fd9c663bSFlorian Westphal
314fd9c663bSFlorian Westphal static const struct bpf_func_proto *
bpf_nf_func_proto(enum bpf_func_id func_id,const struct bpf_prog * prog)315fd9c663bSFlorian Westphal bpf_nf_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
316fd9c663bSFlorian Westphal {
317fd9c663bSFlorian Westphal return bpf_base_func_proto(func_id);
318fd9c663bSFlorian Westphal }
319fd9c663bSFlorian Westphal
320fd9c663bSFlorian Westphal const struct bpf_verifier_ops netfilter_verifier_ops = {
321fd9c663bSFlorian Westphal .is_valid_access = nf_is_valid_access,
322fd9c663bSFlorian Westphal .get_func_proto = bpf_nf_func_proto,
323fd9c663bSFlorian Westphal };
324