x86: Fix typo s/ECLR/ELCR/ for the PIC register
[linux-2.6-microblaze.git] / net / netfilter / nfnetlink_hook.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2021 Red Hat GmbH
4  *
5  * Author: Florian Westphal <fw@strlen.de>
6  */
7
8 #include <linux/module.h>
9 #include <linux/kernel.h>
10 #include <linux/types.h>
11 #include <linux/skbuff.h>
12 #include <linux/errno.h>
13 #include <linux/netlink.h>
14 #include <linux/slab.h>
15
16 #include <linux/netfilter.h>
17
18 #include <linux/netfilter/nfnetlink.h>
19 #include <linux/netfilter/nfnetlink_hook.h>
20
21 #include <net/netfilter/nf_tables.h>
22 #include <net/sock.h>
23
24 static const struct nla_policy nfnl_hook_nla_policy[NFNLA_HOOK_MAX + 1] = {
25         [NFNLA_HOOK_HOOKNUM]    = { .type = NLA_U32 },
26         [NFNLA_HOOK_PRIORITY]   = { .type = NLA_U32 },
27         [NFNLA_HOOK_DEV]        = { .type = NLA_STRING,
28                                     .len = IFNAMSIZ - 1 },
29         [NFNLA_HOOK_FUNCTION_NAME] = { .type = NLA_NUL_STRING,
30                                        .len = KSYM_NAME_LEN, },
31         [NFNLA_HOOK_MODULE_NAME] = { .type = NLA_NUL_STRING,
32                                      .len = MODULE_NAME_LEN, },
33         [NFNLA_HOOK_CHAIN_INFO] = { .type = NLA_NESTED, },
34 };
35
36 static int nf_netlink_dump_start_rcu(struct sock *nlsk, struct sk_buff *skb,
37                                      const struct nlmsghdr *nlh,
38                                      struct netlink_dump_control *c)
39 {
40         int err;
41
42         if (!try_module_get(THIS_MODULE))
43                 return -EINVAL;
44
45         rcu_read_unlock();
46         err = netlink_dump_start(nlsk, skb, nlh, c);
47         rcu_read_lock();
48         module_put(THIS_MODULE);
49
50         return err;
51 }
52
53 struct nfnl_dump_hook_data {
54         char devname[IFNAMSIZ];
55         unsigned long headv;
56         u8 hook;
57 };
58
59 static int nfnl_hook_put_nft_chain_info(struct sk_buff *nlskb,
60                                         const struct nfnl_dump_hook_data *ctx,
61                                         unsigned int seq,
62                                         const struct nf_hook_ops *ops)
63 {
64         struct net *net = sock_net(nlskb->sk);
65         struct nlattr *nest, *nest2;
66         struct nft_chain *chain;
67         int ret = 0;
68
69         if (ops->hook_ops_type != NF_HOOK_OP_NF_TABLES)
70                 return 0;
71
72         chain = ops->priv;
73         if (WARN_ON_ONCE(!chain))
74                 return 0;
75
76         if (!nft_is_active(net, chain))
77                 return 0;
78
79         nest = nla_nest_start(nlskb, NFNLA_HOOK_CHAIN_INFO);
80         if (!nest)
81                 return -EMSGSIZE;
82
83         ret = nla_put_be32(nlskb, NFNLA_HOOK_INFO_TYPE,
84                            htonl(NFNL_HOOK_TYPE_NFTABLES));
85         if (ret)
86                 goto cancel_nest;
87
88         nest2 = nla_nest_start(nlskb, NFNLA_HOOK_INFO_DESC);
89         if (!nest2)
90                 goto cancel_nest;
91
92         ret = nla_put_string(nlskb, NFTA_CHAIN_TABLE, chain->table->name);
93         if (ret)
94                 goto cancel_nest;
95
96         ret = nla_put_string(nlskb, NFTA_CHAIN_NAME, chain->name);
97         if (ret)
98                 goto cancel_nest;
99
100         nla_nest_end(nlskb, nest2);
101         nla_nest_end(nlskb, nest);
102         return ret;
103
104 cancel_nest:
105         nla_nest_cancel(nlskb, nest);
106         return -EMSGSIZE;
107 }
108
109 static int nfnl_hook_dump_one(struct sk_buff *nlskb,
110                               const struct nfnl_dump_hook_data *ctx,
111                               const struct nf_hook_ops *ops,
112                               unsigned int seq)
113 {
114         u16 event = nfnl_msg_type(NFNL_SUBSYS_HOOK, NFNL_MSG_HOOK_GET);
115         unsigned int portid = NETLINK_CB(nlskb).portid;
116         struct nlmsghdr *nlh;
117         int ret = -EMSGSIZE;
118 #ifdef CONFIG_KALLSYMS
119         char sym[KSYM_SYMBOL_LEN];
120         char *module_name;
121 #endif
122         nlh = nfnl_msg_put(nlskb, portid, seq, event,
123                            NLM_F_MULTI, ops->pf, NFNETLINK_V0, 0);
124         if (!nlh)
125                 goto nla_put_failure;
126
127 #ifdef CONFIG_KALLSYMS
128         ret = snprintf(sym, sizeof(sym), "%ps", ops->hook);
129         if (ret >= sizeof(sym)) {
130                 ret = -EINVAL;
131                 goto nla_put_failure;
132         }
133
134         module_name = strstr(sym, " [");
135         if (module_name) {
136                 char *end;
137
138                 module_name += 2;
139                 end = strchr(module_name, ']');
140                 if (end) {
141                         *end = 0;
142
143                         ret = nla_put_string(nlskb, NFNLA_HOOK_MODULE_NAME, module_name);
144                         if (ret)
145                                 goto nla_put_failure;
146                 }
147         }
148
149         ret = nla_put_string(nlskb, NFNLA_HOOK_FUNCTION_NAME, sym);
150         if (ret)
151                 goto nla_put_failure;
152 #endif
153
154         ret = nla_put_be32(nlskb, NFNLA_HOOK_HOOKNUM, htonl(ops->hooknum));
155         if (ret)
156                 goto nla_put_failure;
157
158         ret = nla_put_be32(nlskb, NFNLA_HOOK_PRIORITY, htonl(ops->priority));
159         if (ret)
160                 goto nla_put_failure;
161
162         ret = nfnl_hook_put_nft_chain_info(nlskb, ctx, seq, ops);
163         if (ret)
164                 goto nla_put_failure;
165
166         nlmsg_end(nlskb, nlh);
167         return 0;
168 nla_put_failure:
169         nlmsg_trim(nlskb, nlh);
170         return ret;
171 }
172
173 static const struct nf_hook_entries *
174 nfnl_hook_entries_head(u8 pf, unsigned int hook, struct net *net, const char *dev)
175 {
176         const struct nf_hook_entries *hook_head = NULL;
177 #ifdef CONFIG_NETFILTER_INGRESS
178         struct net_device *netdev;
179 #endif
180
181         switch (pf) {
182         case NFPROTO_IPV4:
183                 if (hook >= ARRAY_SIZE(net->nf.hooks_ipv4))
184                         return ERR_PTR(-EINVAL);
185                 hook_head = rcu_dereference(net->nf.hooks_ipv4[hook]);
186                 break;
187         case NFPROTO_IPV6:
188                 if (hook >= ARRAY_SIZE(net->nf.hooks_ipv6))
189                         return ERR_PTR(-EINVAL);
190                 hook_head = rcu_dereference(net->nf.hooks_ipv6[hook]);
191                 break;
192         case NFPROTO_ARP:
193 #ifdef CONFIG_NETFILTER_FAMILY_ARP
194                 if (hook >= ARRAY_SIZE(net->nf.hooks_arp))
195                         return ERR_PTR(-EINVAL);
196                 hook_head = rcu_dereference(net->nf.hooks_arp[hook]);
197 #endif
198                 break;
199         case NFPROTO_BRIDGE:
200 #ifdef CONFIG_NETFILTER_FAMILY_BRIDGE
201                 if (hook >= ARRAY_SIZE(net->nf.hooks_bridge))
202                         return ERR_PTR(-EINVAL);
203                 hook_head = rcu_dereference(net->nf.hooks_bridge[hook]);
204 #endif
205                 break;
206 #if IS_ENABLED(CONFIG_DECNET)
207         case NFPROTO_DECNET:
208                 if (hook >= ARRAY_SIZE(net->nf.hooks_decnet))
209                         return ERR_PTR(-EINVAL);
210                 hook_head = rcu_dereference(net->nf.hooks_decnet[hook]);
211                 break;
212 #endif
213 #ifdef CONFIG_NETFILTER_INGRESS
214         case NFPROTO_NETDEV:
215                 if (hook != NF_NETDEV_INGRESS)
216                         return ERR_PTR(-EOPNOTSUPP);
217
218                 if (!dev)
219                         return ERR_PTR(-ENODEV);
220
221                 netdev = dev_get_by_name_rcu(net, dev);
222                 if (!netdev)
223                         return ERR_PTR(-ENODEV);
224
225                 return rcu_dereference(netdev->nf_hooks_ingress);
226 #endif
227         default:
228                 return ERR_PTR(-EPROTONOSUPPORT);
229         }
230
231         return hook_head;
232 }
233
234 static int nfnl_hook_dump(struct sk_buff *nlskb,
235                           struct netlink_callback *cb)
236 {
237         struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
238         struct nfnl_dump_hook_data *ctx = cb->data;
239         int err, family = nfmsg->nfgen_family;
240         struct net *net = sock_net(nlskb->sk);
241         struct nf_hook_ops * const *ops;
242         const struct nf_hook_entries *e;
243         unsigned int i = cb->args[0];
244
245         rcu_read_lock();
246
247         e = nfnl_hook_entries_head(family, ctx->hook, net, ctx->devname);
248         if (!e)
249                 goto done;
250
251         if (IS_ERR(e)) {
252                 cb->seq++;
253                 goto done;
254         }
255
256         if ((unsigned long)e != ctx->headv || i >= e->num_hook_entries)
257                 cb->seq++;
258
259         ops = nf_hook_entries_get_hook_ops(e);
260
261         for (; i < e->num_hook_entries; i++) {
262                 err = nfnl_hook_dump_one(nlskb, ctx, ops[i], cb->seq);
263                 if (err)
264                         break;
265         }
266
267 done:
268         nl_dump_check_consistent(cb, nlmsg_hdr(nlskb));
269         rcu_read_unlock();
270         cb->args[0] = i;
271         return nlskb->len;
272 }
273
274 static int nfnl_hook_dump_start(struct netlink_callback *cb)
275 {
276         const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
277         const struct nlattr * const *nla = cb->data;
278         struct nfnl_dump_hook_data *ctx = NULL;
279         struct net *net = sock_net(cb->skb->sk);
280         u8 family = nfmsg->nfgen_family;
281         char name[IFNAMSIZ] = "";
282         const void *head;
283         u32 hooknum;
284
285         hooknum = ntohl(nla_get_be32(nla[NFNLA_HOOK_HOOKNUM]));
286         if (hooknum > 255)
287                 return -EINVAL;
288
289         if (family == NFPROTO_NETDEV) {
290                 if (!nla[NFNLA_HOOK_DEV])
291                         return -EINVAL;
292
293                 nla_strscpy(name, nla[NFNLA_HOOK_DEV], sizeof(name));
294         }
295
296         rcu_read_lock();
297         /* Not dereferenced; for consistency check only */
298         head = nfnl_hook_entries_head(family, hooknum, net, name);
299         rcu_read_unlock();
300
301         if (head && IS_ERR(head))
302                 return PTR_ERR(head);
303
304         ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
305         if (!ctx)
306                 return -ENOMEM;
307
308         strscpy(ctx->devname, name, sizeof(ctx->devname));
309         ctx->headv = (unsigned long)head;
310         ctx->hook = hooknum;
311
312         cb->seq = 1;
313         cb->data = ctx;
314
315         return 0;
316 }
317
318 static int nfnl_hook_dump_stop(struct netlink_callback *cb)
319 {
320         kfree(cb->data);
321         return 0;
322 }
323
324 static int nfnl_hook_get(struct sk_buff *skb,
325                          const struct nfnl_info *info,
326                          const struct nlattr * const nla[])
327 {
328         if (!nla[NFNLA_HOOK_HOOKNUM])
329                 return -EINVAL;
330
331         if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
332                 struct netlink_dump_control c = {
333                         .start = nfnl_hook_dump_start,
334                         .done = nfnl_hook_dump_stop,
335                         .dump = nfnl_hook_dump,
336                         .module = THIS_MODULE,
337                         .data = (void *)nla,
338                 };
339
340                 return nf_netlink_dump_start_rcu(info->sk, skb, info->nlh, &c);
341         }
342
343         return -EOPNOTSUPP;
344 }
345
346 static const struct nfnl_callback nfnl_hook_cb[NFNL_MSG_HOOK_MAX] = {
347         [NFNL_MSG_HOOK_GET] = {
348                 .call           = nfnl_hook_get,
349                 .type           = NFNL_CB_RCU,
350                 .attr_count     = NFNLA_HOOK_MAX,
351                 .policy         = nfnl_hook_nla_policy
352         },
353 };
354
355 static const struct nfnetlink_subsystem nfhook_subsys = {
356         .name                           = "nfhook",
357         .subsys_id                      = NFNL_SUBSYS_HOOK,
358         .cb_count                       = NFNL_MSG_HOOK_MAX,
359         .cb                             = nfnl_hook_cb,
360 };
361
362 MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_HOOK);
363
364 static int __init nfnetlink_hook_init(void)
365 {
366         return nfnetlink_subsys_register(&nfhook_subsys);
367 }
368
369 static void __exit nfnetlink_hook_exit(void)
370 {
371         nfnetlink_subsys_unregister(&nfhook_subsys);
372 }
373
374 module_init(nfnetlink_hook_init);
375 module_exit(nfnetlink_hook_exit);
376
377 MODULE_LICENSE("GPL");
378 MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
379 MODULE_DESCRIPTION("nfnetlink_hook: list registered netfilter hooks");