1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/bpf.h>
3 #include <linux/filter.h>
4 #include <linux/kmod.h>
5 #include <linux/module.h>
6 #include <linux/netfilter.h>
7 
8 #include <net/netfilter/nf_bpf_link.h>
9 #include <uapi/linux/netfilter_ipv4.h>
10 
nf_hook_run_bpf(void * bpf_prog,struct sk_buff * skb,const struct nf_hook_state * s)11 static unsigned int nf_hook_run_bpf(void *bpf_prog, struct sk_buff *skb,
12 				    const struct nf_hook_state *s)
13 {
14 	const struct bpf_prog *prog = bpf_prog;
15 	struct bpf_nf_ctx ctx = {
16 		.state = s,
17 		.skb = skb,
18 	};
19 
20 	return bpf_prog_run(prog, &ctx);
21 }
22 
23 struct bpf_nf_link {
24 	struct bpf_link link;
25 	struct nf_hook_ops hook_ops;
26 	netns_tracker ns_tracker;
27 	struct net *net;
28 	u32 dead;
29 	const struct nf_defrag_hook *defrag_hook;
30 };
31 
32 #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV4) || IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
33 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)34 get_proto_defrag_hook(struct bpf_nf_link *link,
35 		      const struct nf_defrag_hook __rcu **ptr_global_hook,
36 		      const char *mod)
37 {
38 	const struct nf_defrag_hook *hook;
39 	int err;
40 
41 	/* RCU protects us from races against module unloading */
42 	rcu_read_lock();
43 	hook = rcu_dereference(*ptr_global_hook);
44 	if (!hook) {
45 		rcu_read_unlock();
46 		err = request_module(mod);
47 		if (err)
48 			return ERR_PTR(err < 0 ? err : -EINVAL);
49 
50 		rcu_read_lock();
51 		hook = rcu_dereference(*ptr_global_hook);
52 	}
53 
54 	if (hook && try_module_get(hook->owner)) {
55 		/* Once we have a refcnt on the module, we no longer need RCU */
56 		hook = rcu_pointer_handoff(hook);
57 	} else {
58 		WARN_ONCE(!hook, "%s has bad registration", mod);
59 		hook = ERR_PTR(-ENOENT);
60 	}
61 	rcu_read_unlock();
62 
63 	if (!IS_ERR(hook)) {
64 		err = hook->enable(link->net);
65 		if (err) {
66 			module_put(hook->owner);
67 			hook = ERR_PTR(err);
68 		}
69 	}
70 
71 	return hook;
72 }
73 #endif
74 
bpf_nf_enable_defrag(struct bpf_nf_link * link)75 static int bpf_nf_enable_defrag(struct bpf_nf_link *link)
76 {
77 	const struct nf_defrag_hook __maybe_unused *hook;
78 
79 	switch (link->hook_ops.pf) {
80 #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV4)
81 	case NFPROTO_IPV4:
82 		hook = get_proto_defrag_hook(link, &nf_defrag_v4_hook, "nf_defrag_ipv4");
83 		if (IS_ERR(hook))
84 			return PTR_ERR(hook);
85 
86 		link->defrag_hook = hook;
87 		return 0;
88 #endif
89 #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
90 	case NFPROTO_IPV6:
91 		hook = get_proto_defrag_hook(link, &nf_defrag_v6_hook, "nf_defrag_ipv6");
92 		if (IS_ERR(hook))
93 			return PTR_ERR(hook);
94 
95 		link->defrag_hook = hook;
96 		return 0;
97 #endif
98 	default:
99 		return -EAFNOSUPPORT;
100 	}
101 }
102 
bpf_nf_disable_defrag(struct bpf_nf_link * link)103 static void bpf_nf_disable_defrag(struct bpf_nf_link *link)
104 {
105 	const struct nf_defrag_hook *hook = link->defrag_hook;
106 
107 	if (!hook)
108 		return;
109 	hook->disable(link->net);
110 	module_put(hook->owner);
111 }
112 
bpf_nf_link_release(struct bpf_link * link)113 static void bpf_nf_link_release(struct bpf_link *link)
114 {
115 	struct bpf_nf_link *nf_link = container_of(link, struct bpf_nf_link, link);
116 
117 	if (nf_link->dead)
118 		return;
119 
120 	/* do not double release in case .detach was already called */
121 	if (!cmpxchg(&nf_link->dead, 0, 1)) {
122 		nf_unregister_net_hook(nf_link->net, &nf_link->hook_ops);
123 		bpf_nf_disable_defrag(nf_link);
124 		put_net_track(nf_link->net, &nf_link->ns_tracker);
125 	}
126 }
127 
bpf_nf_link_dealloc(struct bpf_link * link)128 static void bpf_nf_link_dealloc(struct bpf_link *link)
129 {
130 	struct bpf_nf_link *nf_link = container_of(link, struct bpf_nf_link, link);
131 
132 	kfree(nf_link);
133 }
134 
bpf_nf_link_detach(struct bpf_link * link)135 static int bpf_nf_link_detach(struct bpf_link *link)
136 {
137 	bpf_nf_link_release(link);
138 	return 0;
139 }
140 
bpf_nf_link_show_info(const struct bpf_link * link,struct seq_file * seq)141 static void bpf_nf_link_show_info(const struct bpf_link *link,
142 				  struct seq_file *seq)
143 {
144 	struct bpf_nf_link *nf_link = container_of(link, struct bpf_nf_link, link);
145 
146 	seq_printf(seq, "pf:\t%u\thooknum:\t%u\tprio:\t%d\n",
147 		   nf_link->hook_ops.pf, nf_link->hook_ops.hooknum,
148 		   nf_link->hook_ops.priority);
149 }
150 
bpf_nf_link_fill_link_info(const struct bpf_link * link,struct bpf_link_info * info)151 static int bpf_nf_link_fill_link_info(const struct bpf_link *link,
152 				      struct bpf_link_info *info)
153 {
154 	struct bpf_nf_link *nf_link = container_of(link, struct bpf_nf_link, link);
155 	const struct nf_defrag_hook *hook = nf_link->defrag_hook;
156 
157 	info->netfilter.pf = nf_link->hook_ops.pf;
158 	info->netfilter.hooknum = nf_link->hook_ops.hooknum;
159 	info->netfilter.priority = nf_link->hook_ops.priority;
160 	info->netfilter.flags = hook ? BPF_F_NETFILTER_IP_DEFRAG : 0;
161 
162 	return 0;
163 }
164 
bpf_nf_link_update(struct bpf_link * link,struct bpf_prog * new_prog,struct bpf_prog * old_prog)165 static int bpf_nf_link_update(struct bpf_link *link, struct bpf_prog *new_prog,
166 			      struct bpf_prog *old_prog)
167 {
168 	return -EOPNOTSUPP;
169 }
170 
171 static const struct bpf_link_ops bpf_nf_link_lops = {
172 	.release = bpf_nf_link_release,
173 	.dealloc = bpf_nf_link_dealloc,
174 	.detach = bpf_nf_link_detach,
175 	.show_fdinfo = bpf_nf_link_show_info,
176 	.fill_link_info = bpf_nf_link_fill_link_info,
177 	.update_prog = bpf_nf_link_update,
178 };
179 
bpf_nf_check_pf_and_hooks(const union bpf_attr * attr)180 static int bpf_nf_check_pf_and_hooks(const union bpf_attr *attr)
181 {
182 	int prio;
183 
184 	switch (attr->link_create.netfilter.pf) {
185 	case NFPROTO_IPV4:
186 	case NFPROTO_IPV6:
187 		if (attr->link_create.netfilter.hooknum >= NF_INET_NUMHOOKS)
188 			return -EPROTO;
189 		break;
190 	default:
191 		return -EAFNOSUPPORT;
192 	}
193 
194 	if (attr->link_create.netfilter.flags & ~BPF_F_NETFILTER_IP_DEFRAG)
195 		return -EOPNOTSUPP;
196 
197 	/* make sure conntrack confirm is always last */
198 	prio = attr->link_create.netfilter.priority;
199 	if (prio == NF_IP_PRI_FIRST)
200 		return -ERANGE;  /* sabotage_in and other warts */
201 	else if (prio == NF_IP_PRI_LAST)
202 		return -ERANGE;  /* e.g. conntrack confirm */
203 	else if ((attr->link_create.netfilter.flags & BPF_F_NETFILTER_IP_DEFRAG) &&
204 		 prio <= NF_IP_PRI_CONNTRACK_DEFRAG)
205 		return -ERANGE;  /* cannot use defrag if prog runs before nf_defrag */
206 
207 	return 0;
208 }
209 
bpf_nf_link_attach(const union bpf_attr * attr,struct bpf_prog * prog)210 int bpf_nf_link_attach(const union bpf_attr *attr, struct bpf_prog *prog)
211 {
212 	struct net *net = current->nsproxy->net_ns;
213 	struct bpf_link_primer link_primer;
214 	struct bpf_nf_link *link;
215 	int err;
216 
217 	if (attr->link_create.flags)
218 		return -EINVAL;
219 
220 	err = bpf_nf_check_pf_and_hooks(attr);
221 	if (err)
222 		return err;
223 
224 	link = kzalloc(sizeof(*link), GFP_USER);
225 	if (!link)
226 		return -ENOMEM;
227 
228 	bpf_link_init(&link->link, BPF_LINK_TYPE_NETFILTER, &bpf_nf_link_lops, prog);
229 
230 	link->hook_ops.hook = nf_hook_run_bpf;
231 	link->hook_ops.hook_ops_type = NF_HOOK_OP_BPF;
232 	link->hook_ops.priv = prog;
233 
234 	link->hook_ops.pf = attr->link_create.netfilter.pf;
235 	link->hook_ops.priority = attr->link_create.netfilter.priority;
236 	link->hook_ops.hooknum = attr->link_create.netfilter.hooknum;
237 
238 	link->net = net;
239 	link->dead = false;
240 	link->defrag_hook = NULL;
241 
242 	err = bpf_link_prime(&link->link, &link_primer);
243 	if (err) {
244 		kfree(link);
245 		return err;
246 	}
247 
248 	if (attr->link_create.netfilter.flags & BPF_F_NETFILTER_IP_DEFRAG) {
249 		err = bpf_nf_enable_defrag(link);
250 		if (err) {
251 			bpf_link_cleanup(&link_primer);
252 			return err;
253 		}
254 	}
255 
256 	err = nf_register_net_hook(net, &link->hook_ops);
257 	if (err) {
258 		bpf_nf_disable_defrag(link);
259 		bpf_link_cleanup(&link_primer);
260 		return err;
261 	}
262 
263 	get_net_track(net, &link->ns_tracker, GFP_KERNEL);
264 
265 	return bpf_link_settle(&link_primer);
266 }
267 
268 const struct bpf_prog_ops netfilter_prog_ops = {
269 	.test_run = bpf_prog_test_run_nf,
270 };
271 
nf_ptr_to_btf_id(struct bpf_insn_access_aux * info,const char * name)272 static bool nf_ptr_to_btf_id(struct bpf_insn_access_aux *info, const char *name)
273 {
274 	struct btf *btf;
275 	s32 type_id;
276 
277 	btf = bpf_get_btf_vmlinux();
278 	if (IS_ERR_OR_NULL(btf))
279 		return false;
280 
281 	type_id = btf_find_by_name_kind(btf, name, BTF_KIND_STRUCT);
282 	if (WARN_ON_ONCE(type_id < 0))
283 		return false;
284 
285 	info->btf = btf;
286 	info->btf_id = type_id;
287 	info->reg_type = PTR_TO_BTF_ID | PTR_TRUSTED;
288 	return true;
289 }
290 
nf_is_valid_access(int off,int size,enum bpf_access_type type,const struct bpf_prog * prog,struct bpf_insn_access_aux * info)291 static bool nf_is_valid_access(int off, int size, enum bpf_access_type type,
292 			       const struct bpf_prog *prog,
293 			       struct bpf_insn_access_aux *info)
294 {
295 	if (off < 0 || off >= sizeof(struct bpf_nf_ctx))
296 		return false;
297 
298 	if (type == BPF_WRITE)
299 		return false;
300 
301 	switch (off) {
302 	case bpf_ctx_range(struct bpf_nf_ctx, skb):
303 		if (size != sizeof_field(struct bpf_nf_ctx, skb))
304 			return false;
305 
306 		return nf_ptr_to_btf_id(info, "sk_buff");
307 	case bpf_ctx_range(struct bpf_nf_ctx, state):
308 		if (size != sizeof_field(struct bpf_nf_ctx, state))
309 			return false;
310 
311 		return nf_ptr_to_btf_id(info, "nf_hook_state");
312 	default:
313 		return false;
314 	}
315 
316 	return false;
317 }
318 
319 static const struct bpf_func_proto *
bpf_nf_func_proto(enum bpf_func_id func_id,const struct bpf_prog * prog)320 bpf_nf_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
321 {
322 	return bpf_base_func_proto(func_id, prog);
323 }
324 
325 const struct bpf_verifier_ops netfilter_verifier_ops = {
326 	.is_valid_access	= nf_is_valid_access,
327 	.get_func_proto		= bpf_nf_func_proto,
328 };
329