Merge tag 'pci-v4.18-fixes-2' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaa...
[linux-2.6-microblaze.git] / net / netfilter / xt_osf.c
1 /*
2  * Copyright (c) 2003+ Evgeniy Polyakov <zbr@ioremap.net>
3  *
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, see <http://www.gnu.org/licenses/>.
17  */
18 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19 #include <linux/module.h>
20 #include <linux/kernel.h>
21
22 #include <linux/capability.h>
23 #include <linux/if.h>
24 #include <linux/inetdevice.h>
25 #include <linux/ip.h>
26 #include <linux/list.h>
27 #include <linux/rculist.h>
28 #include <linux/skbuff.h>
29 #include <linux/slab.h>
30 #include <linux/tcp.h>
31
32 #include <net/ip.h>
33 #include <net/tcp.h>
34
35 #include <linux/netfilter/nfnetlink.h>
36 #include <linux/netfilter/x_tables.h>
37 #include <net/netfilter/nf_log.h>
38 #include <linux/netfilter/xt_osf.h>
39
40 /*
41  * Indexed by dont-fragment bit.
42  * It is the only constant value in the fingerprint.
43  */
44 static struct list_head xt_osf_fingers[2];
45
46 static const struct nla_policy xt_osf_policy[OSF_ATTR_MAX + 1] = {
47         [OSF_ATTR_FINGER]       = { .len = sizeof(struct xt_osf_user_finger) },
48 };
49
50 static int xt_osf_add_callback(struct net *net, struct sock *ctnl,
51                                struct sk_buff *skb, const struct nlmsghdr *nlh,
52                                const struct nlattr * const osf_attrs[],
53                                struct netlink_ext_ack *extack)
54 {
55         struct xt_osf_user_finger *f;
56         struct xt_osf_finger *kf = NULL, *sf;
57         int err = 0;
58
59         if (!capable(CAP_NET_ADMIN))
60                 return -EPERM;
61
62         if (!osf_attrs[OSF_ATTR_FINGER])
63                 return -EINVAL;
64
65         if (!(nlh->nlmsg_flags & NLM_F_CREATE))
66                 return -EINVAL;
67
68         f = nla_data(osf_attrs[OSF_ATTR_FINGER]);
69
70         kf = kmalloc(sizeof(struct xt_osf_finger), GFP_KERNEL);
71         if (!kf)
72                 return -ENOMEM;
73
74         memcpy(&kf->finger, f, sizeof(struct xt_osf_user_finger));
75
76         list_for_each_entry(sf, &xt_osf_fingers[!!f->df], finger_entry) {
77                 if (memcmp(&sf->finger, f, sizeof(struct xt_osf_user_finger)))
78                         continue;
79
80                 kfree(kf);
81                 kf = NULL;
82
83                 if (nlh->nlmsg_flags & NLM_F_EXCL)
84                         err = -EEXIST;
85                 break;
86         }
87
88         /*
89          * We are protected by nfnl mutex.
90          */
91         if (kf)
92                 list_add_tail_rcu(&kf->finger_entry, &xt_osf_fingers[!!f->df]);
93
94         return err;
95 }
96
97 static int xt_osf_remove_callback(struct net *net, struct sock *ctnl,
98                                   struct sk_buff *skb,
99                                   const struct nlmsghdr *nlh,
100                                   const struct nlattr * const osf_attrs[],
101                                   struct netlink_ext_ack *extack)
102 {
103         struct xt_osf_user_finger *f;
104         struct xt_osf_finger *sf;
105         int err = -ENOENT;
106
107         if (!capable(CAP_NET_ADMIN))
108                 return -EPERM;
109
110         if (!osf_attrs[OSF_ATTR_FINGER])
111                 return -EINVAL;
112
113         f = nla_data(osf_attrs[OSF_ATTR_FINGER]);
114
115         list_for_each_entry(sf, &xt_osf_fingers[!!f->df], finger_entry) {
116                 if (memcmp(&sf->finger, f, sizeof(struct xt_osf_user_finger)))
117                         continue;
118
119                 /*
120                  * We are protected by nfnl mutex.
121                  */
122                 list_del_rcu(&sf->finger_entry);
123                 kfree_rcu(sf, rcu_head);
124
125                 err = 0;
126                 break;
127         }
128
129         return err;
130 }
131
132 static const struct nfnl_callback xt_osf_nfnetlink_callbacks[OSF_MSG_MAX] = {
133         [OSF_MSG_ADD]   = {
134                 .call           = xt_osf_add_callback,
135                 .attr_count     = OSF_ATTR_MAX,
136                 .policy         = xt_osf_policy,
137         },
138         [OSF_MSG_REMOVE]        = {
139                 .call           = xt_osf_remove_callback,
140                 .attr_count     = OSF_ATTR_MAX,
141                 .policy         = xt_osf_policy,
142         },
143 };
144
145 static const struct nfnetlink_subsystem xt_osf_nfnetlink = {
146         .name                   = "osf",
147         .subsys_id              = NFNL_SUBSYS_OSF,
148         .cb_count               = OSF_MSG_MAX,
149         .cb                     = xt_osf_nfnetlink_callbacks,
150 };
151
152 static bool
153 xt_osf_match_packet(const struct sk_buff *skb, struct xt_action_param *p)
154 {
155         const struct xt_osf_info *info = p->matchinfo;
156         struct net *net = xt_net(p);
157
158         if (!info)
159                 return false;
160
161         return nf_osf_match(skb, xt_family(p), xt_hooknum(p), xt_in(p),
162                             xt_out(p), info, net, xt_osf_fingers);
163 }
164
165 static struct xt_match xt_osf_match = {
166         .name           = "osf",
167         .revision       = 0,
168         .family         = NFPROTO_IPV4,
169         .proto          = IPPROTO_TCP,
170         .hooks          = (1 << NF_INET_LOCAL_IN) |
171                                 (1 << NF_INET_PRE_ROUTING) |
172                                 (1 << NF_INET_FORWARD),
173         .match          = xt_osf_match_packet,
174         .matchsize      = sizeof(struct xt_osf_info),
175         .me             = THIS_MODULE,
176 };
177
178 static int __init xt_osf_init(void)
179 {
180         int err = -EINVAL;
181         int i;
182
183         for (i=0; i<ARRAY_SIZE(xt_osf_fingers); ++i)
184                 INIT_LIST_HEAD(&xt_osf_fingers[i]);
185
186         err = nfnetlink_subsys_register(&xt_osf_nfnetlink);
187         if (err < 0) {
188                 pr_err("Failed to register OSF nsfnetlink helper (%d)\n", err);
189                 goto err_out_exit;
190         }
191
192         err = xt_register_match(&xt_osf_match);
193         if (err) {
194                 pr_err("Failed to register OS fingerprint "
195                        "matching module (%d)\n", err);
196                 goto err_out_remove;
197         }
198
199         return 0;
200
201 err_out_remove:
202         nfnetlink_subsys_unregister(&xt_osf_nfnetlink);
203 err_out_exit:
204         return err;
205 }
206
207 static void __exit xt_osf_fini(void)
208 {
209         struct xt_osf_finger *f;
210         int i;
211
212         nfnetlink_subsys_unregister(&xt_osf_nfnetlink);
213         xt_unregister_match(&xt_osf_match);
214
215         rcu_read_lock();
216         for (i=0; i<ARRAY_SIZE(xt_osf_fingers); ++i) {
217
218                 list_for_each_entry_rcu(f, &xt_osf_fingers[i], finger_entry) {
219                         list_del_rcu(&f->finger_entry);
220                         kfree_rcu(f, rcu_head);
221                 }
222         }
223         rcu_read_unlock();
224
225         rcu_barrier();
226 }
227
228 module_init(xt_osf_init);
229 module_exit(xt_osf_fini);
230
231 MODULE_LICENSE("GPL");
232 MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
233 MODULE_DESCRIPTION("Passive OS fingerprint matching.");
234 MODULE_ALIAS("ipt_osf");
235 MODULE_ALIAS("ip6t_osf");
236 MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_OSF);