Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0-only
2#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
3#include <linux/module.h>
4#include <linux/kernel.h>
5
6#include <linux/capability.h>
7#include <linux/if.h>
8#include <linux/inetdevice.h>
9#include <linux/ip.h>
10#include <linux/list.h>
11#include <linux/rculist.h>
12#include <linux/skbuff.h>
13#include <linux/slab.h>
14#include <linux/tcp.h>
15
16#include <net/ip.h>
17#include <net/tcp.h>
18
19#include <linux/netfilter/nfnetlink.h>
20#include <linux/netfilter/x_tables.h>
21#include <net/netfilter/nf_log.h>
22#include <linux/netfilter/nfnetlink_osf.h>
23
24/*
25 * Indexed by dont-fragment bit.
26 * It is the only constant value in the fingerprint.
27 */
28struct list_head nf_osf_fingers[2];
29EXPORT_SYMBOL_GPL(nf_osf_fingers);
30
31static inline int nf_osf_ttl(const struct sk_buff *skb,
32 int ttl_check, unsigned char f_ttl)
33{
34 const struct iphdr *ip = ip_hdr(skb);
35
36 switch (ttl_check) {
37 case NF_OSF_TTL_TRUE:
38 return ip->ttl == f_ttl;
39 break;
40 case NF_OSF_TTL_NOCHECK:
41 return 1;
42 case NF_OSF_TTL_LESS:
43 default:
44 return ip->ttl <= f_ttl;
45 }
46}
47
48struct nf_osf_hdr_ctx {
49 bool df;
50 u16 window;
51 u16 totlen;
52 const unsigned char *optp;
53 unsigned int optsize;
54};
55
56static bool nf_osf_match_one(const struct sk_buff *skb,
57 const struct nf_osf_user_finger *f,
58 int ttl_check,
59 const struct nf_osf_hdr_ctx *ctx)
60{
61 const __u8 *optp = ctx->optp;
62 unsigned int check_WSS = 0;
63 int fmatch = FMATCH_WRONG;
64 int foptsize, optnum;
65 u16 mss = 0;
66
67 if (ctx->totlen != f->ss || !nf_osf_ttl(skb, ttl_check, f->ttl))
68 return false;
69
70 /*
71 * Should not happen if userspace parser was written correctly.
72 */
73 if (f->wss.wc >= OSF_WSS_MAX)
74 return false;
75
76 /* Check options */
77
78 foptsize = 0;
79 for (optnum = 0; optnum < f->opt_num; ++optnum)
80 foptsize += f->opt[optnum].length;
81
82 if (foptsize > MAX_IPOPTLEN ||
83 ctx->optsize > MAX_IPOPTLEN ||
84 ctx->optsize != foptsize)
85 return false;
86
87 check_WSS = f->wss.wc;
88
89 for (optnum = 0; optnum < f->opt_num; ++optnum) {
90 if (f->opt[optnum].kind == *optp) {
91 __u32 len = f->opt[optnum].length;
92 const __u8 *optend = optp + len;
93
94 fmatch = FMATCH_OK;
95
96 switch (*optp) {
97 case OSFOPT_MSS:
98 mss = optp[3];
99 mss <<= 8;
100 mss |= optp[2];
101
102 mss = ntohs((__force __be16)mss);
103 break;
104 case OSFOPT_TS:
105 break;
106 }
107
108 optp = optend;
109 } else
110 fmatch = FMATCH_OPT_WRONG;
111
112 if (fmatch != FMATCH_OK)
113 break;
114 }
115
116 if (fmatch != FMATCH_OPT_WRONG) {
117 fmatch = FMATCH_WRONG;
118
119 switch (check_WSS) {
120 case OSF_WSS_PLAIN:
121 if (f->wss.val == 0 || ctx->window == f->wss.val)
122 fmatch = FMATCH_OK;
123 break;
124 case OSF_WSS_MSS:
125 /*
126 * Some smart modems decrease mangle MSS to
127 * SMART_MSS_2, so we check standard, decreased
128 * and the one provided in the fingerprint MSS
129 * values.
130 */
131#define SMART_MSS_1 1460
132#define SMART_MSS_2 1448
133 if (ctx->window == f->wss.val * mss ||
134 ctx->window == f->wss.val * SMART_MSS_1 ||
135 ctx->window == f->wss.val * SMART_MSS_2)
136 fmatch = FMATCH_OK;
137 break;
138 case OSF_WSS_MTU:
139 if (ctx->window == f->wss.val * (mss + 40) ||
140 ctx->window == f->wss.val * (SMART_MSS_1 + 40) ||
141 ctx->window == f->wss.val * (SMART_MSS_2 + 40))
142 fmatch = FMATCH_OK;
143 break;
144 case OSF_WSS_MODULO:
145 if ((ctx->window % f->wss.val) == 0)
146 fmatch = FMATCH_OK;
147 break;
148 }
149 }
150
151 return fmatch == FMATCH_OK;
152}
153
154static const struct tcphdr *nf_osf_hdr_ctx_init(struct nf_osf_hdr_ctx *ctx,
155 const struct sk_buff *skb,
156 const struct iphdr *ip,
157 unsigned char *opts,
158 struct tcphdr *_tcph)
159{
160 const struct tcphdr *tcp;
161
162 tcp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(struct tcphdr), _tcph);
163 if (!tcp)
164 return NULL;
165
166 if (!tcp->syn)
167 return NULL;
168
169 ctx->totlen = ntohs(ip->tot_len);
170 ctx->df = ntohs(ip->frag_off) & IP_DF;
171 ctx->window = ntohs(tcp->window);
172
173 if (tcp->doff * 4 > sizeof(struct tcphdr)) {
174 ctx->optsize = tcp->doff * 4 - sizeof(struct tcphdr);
175
176 ctx->optp = skb_header_pointer(skb, ip_hdrlen(skb) +
177 sizeof(struct tcphdr), ctx->optsize, opts);
178 if (!ctx->optp)
179 return NULL;
180 }
181
182 return tcp;
183}
184
185bool
186nf_osf_match(const struct sk_buff *skb, u_int8_t family,
187 int hooknum, struct net_device *in, struct net_device *out,
188 const struct nf_osf_info *info, struct net *net,
189 const struct list_head *nf_osf_fingers)
190{
191 const struct iphdr *ip = ip_hdr(skb);
192 const struct nf_osf_user_finger *f;
193 unsigned char opts[MAX_IPOPTLEN];
194 const struct nf_osf_finger *kf;
195 int fcount = 0, ttl_check;
196 int fmatch = FMATCH_WRONG;
197 struct nf_osf_hdr_ctx ctx;
198 const struct tcphdr *tcp;
199 struct tcphdr _tcph;
200
201 memset(&ctx, 0, sizeof(ctx));
202
203 tcp = nf_osf_hdr_ctx_init(&ctx, skb, ip, opts, &_tcph);
204 if (!tcp)
205 return false;
206
207 ttl_check = (info->flags & NF_OSF_TTL) ? info->ttl : 0;
208
209 list_for_each_entry_rcu(kf, &nf_osf_fingers[ctx.df], finger_entry) {
210
211 f = &kf->finger;
212
213 if (!(info->flags & NF_OSF_LOG) && strcmp(info->genre, f->genre))
214 continue;
215
216 if (!nf_osf_match_one(skb, f, ttl_check, &ctx))
217 continue;
218
219 fmatch = FMATCH_OK;
220
221 fcount++;
222
223 if (info->flags & NF_OSF_LOG)
224 nf_log_packet(net, family, hooknum, skb,
225 in, out, NULL,
226 "%s [%s:%s] : %pI4:%d -> %pI4:%d hops=%d\n",
227 f->genre, f->version, f->subtype,
228 &ip->saddr, ntohs(tcp->source),
229 &ip->daddr, ntohs(tcp->dest),
230 f->ttl - ip->ttl);
231
232 if ((info->flags & NF_OSF_LOG) &&
233 info->loglevel == NF_OSF_LOGLEVEL_FIRST)
234 break;
235 }
236
237 if (!fcount && (info->flags & NF_OSF_LOG))
238 nf_log_packet(net, family, hooknum, skb, in, out, NULL,
239 "Remote OS is not known: %pI4:%u -> %pI4:%u\n",
240 &ip->saddr, ntohs(tcp->source),
241 &ip->daddr, ntohs(tcp->dest));
242
243 if (fcount)
244 fmatch = FMATCH_OK;
245
246 return fmatch == FMATCH_OK;
247}
248EXPORT_SYMBOL_GPL(nf_osf_match);
249
250bool nf_osf_find(const struct sk_buff *skb,
251 const struct list_head *nf_osf_fingers,
252 const int ttl_check, struct nf_osf_data *data)
253{
254 const struct iphdr *ip = ip_hdr(skb);
255 const struct nf_osf_user_finger *f;
256 unsigned char opts[MAX_IPOPTLEN];
257 const struct nf_osf_finger *kf;
258 struct nf_osf_hdr_ctx ctx;
259 const struct tcphdr *tcp;
260 struct tcphdr _tcph;
261 bool found = false;
262
263 memset(&ctx, 0, sizeof(ctx));
264
265 tcp = nf_osf_hdr_ctx_init(&ctx, skb, ip, opts, &_tcph);
266 if (!tcp)
267 return false;
268
269 list_for_each_entry_rcu(kf, &nf_osf_fingers[ctx.df], finger_entry) {
270 f = &kf->finger;
271 if (!nf_osf_match_one(skb, f, ttl_check, &ctx))
272 continue;
273
274 data->genre = f->genre;
275 data->version = f->version;
276 found = true;
277 break;
278 }
279
280 return found;
281}
282EXPORT_SYMBOL_GPL(nf_osf_find);
283
284static const struct nla_policy nfnl_osf_policy[OSF_ATTR_MAX + 1] = {
285 [OSF_ATTR_FINGER] = NLA_POLICY_EXACT_LEN(sizeof(struct nf_osf_user_finger)),
286};
287
288static int nfnl_osf_add_callback(struct sk_buff *skb,
289 const struct nfnl_info *info,
290 const struct nlattr * const osf_attrs[])
291{
292 struct nf_osf_user_finger *f;
293 struct nf_osf_finger *kf = NULL, *sf;
294 unsigned int tot_opt_len = 0;
295 int err = 0;
296 int i;
297
298 if (!capable(CAP_NET_ADMIN))
299 return -EPERM;
300
301 if (!osf_attrs[OSF_ATTR_FINGER])
302 return -EINVAL;
303
304 if (!(info->nlh->nlmsg_flags & NLM_F_CREATE))
305 return -EINVAL;
306
307 f = nla_data(osf_attrs[OSF_ATTR_FINGER]);
308
309 if (f->opt_num > ARRAY_SIZE(f->opt))
310 return -EINVAL;
311
312 if (f->wss.wc >= OSF_WSS_MAX ||
313 (f->wss.wc == OSF_WSS_MODULO && f->wss.val == 0))
314 return -EINVAL;
315
316 for (i = 0; i < f->opt_num; i++) {
317 if (!f->opt[i].length || f->opt[i].length > MAX_IPOPTLEN)
318 return -EINVAL;
319 if (f->opt[i].kind == OSFOPT_MSS && f->opt[i].length < 4)
320 return -EINVAL;
321
322 tot_opt_len += f->opt[i].length;
323 if (tot_opt_len > MAX_IPOPTLEN)
324 return -EINVAL;
325 }
326
327 if (!memchr(f->genre, 0, MAXGENRELEN) ||
328 !memchr(f->subtype, 0, MAXGENRELEN) ||
329 !memchr(f->version, 0, MAXGENRELEN))
330 return -EINVAL;
331
332 kf = kmalloc_obj(struct nf_osf_finger);
333 if (!kf)
334 return -ENOMEM;
335
336 memcpy(&kf->finger, f, sizeof(struct nf_osf_user_finger));
337
338 list_for_each_entry(sf, &nf_osf_fingers[!!f->df], finger_entry) {
339 if (memcmp(&sf->finger, f, sizeof(struct nf_osf_user_finger)))
340 continue;
341
342 kfree(kf);
343 kf = NULL;
344
345 if (info->nlh->nlmsg_flags & NLM_F_EXCL)
346 err = -EEXIST;
347 break;
348 }
349
350 /*
351 * We are protected by nfnl mutex.
352 */
353 if (kf)
354 list_add_tail_rcu(&kf->finger_entry, &nf_osf_fingers[!!f->df]);
355
356 return err;
357}
358
359static int nfnl_osf_remove_callback(struct sk_buff *skb,
360 const struct nfnl_info *info,
361 const struct nlattr * const osf_attrs[])
362{
363 struct nf_osf_user_finger *f;
364 struct nf_osf_finger *sf;
365 int err = -ENOENT;
366
367 if (!capable(CAP_NET_ADMIN))
368 return -EPERM;
369
370 if (!osf_attrs[OSF_ATTR_FINGER])
371 return -EINVAL;
372
373 f = nla_data(osf_attrs[OSF_ATTR_FINGER]);
374
375 list_for_each_entry(sf, &nf_osf_fingers[!!f->df], finger_entry) {
376 if (memcmp(&sf->finger, f, sizeof(struct nf_osf_user_finger)))
377 continue;
378
379 /*
380 * We are protected by nfnl mutex.
381 */
382 list_del_rcu(&sf->finger_entry);
383 kfree_rcu(sf, rcu_head);
384
385 err = 0;
386 break;
387 }
388
389 return err;
390}
391
392static const struct nfnl_callback nfnl_osf_callbacks[OSF_MSG_MAX] = {
393 [OSF_MSG_ADD] = {
394 .call = nfnl_osf_add_callback,
395 .type = NFNL_CB_MUTEX,
396 .attr_count = OSF_ATTR_MAX,
397 .policy = nfnl_osf_policy,
398 },
399 [OSF_MSG_REMOVE] = {
400 .call = nfnl_osf_remove_callback,
401 .type = NFNL_CB_MUTEX,
402 .attr_count = OSF_ATTR_MAX,
403 .policy = nfnl_osf_policy,
404 },
405};
406
407static const struct nfnetlink_subsystem nfnl_osf_subsys = {
408 .name = "osf",
409 .subsys_id = NFNL_SUBSYS_OSF,
410 .cb_count = OSF_MSG_MAX,
411 .cb = nfnl_osf_callbacks,
412};
413
414static int __init nfnl_osf_init(void)
415{
416 int err = -EINVAL;
417 int i;
418
419 for (i = 0; i < ARRAY_SIZE(nf_osf_fingers); ++i)
420 INIT_LIST_HEAD(&nf_osf_fingers[i]);
421
422 err = nfnetlink_subsys_register(&nfnl_osf_subsys);
423 if (err < 0) {
424 pr_err("Failed to register OSF nsfnetlink helper (%d)\n", err);
425 goto err_out_exit;
426 }
427 return 0;
428
429err_out_exit:
430 return err;
431}
432
433static void __exit nfnl_osf_fini(void)
434{
435 struct nf_osf_finger *f;
436 int i;
437
438 nfnetlink_subsys_unregister(&nfnl_osf_subsys);
439
440 rcu_read_lock();
441 for (i = 0; i < ARRAY_SIZE(nf_osf_fingers); ++i) {
442 list_for_each_entry_rcu(f, &nf_osf_fingers[i], finger_entry) {
443 list_del_rcu(&f->finger_entry);
444 kfree_rcu(f, rcu_head);
445 }
446 }
447 rcu_read_unlock();
448
449 rcu_barrier();
450}
451
452module_init(nfnl_osf_init);
453module_exit(nfnl_osf_fini);
454
455MODULE_LICENSE("GPL");
456MODULE_DESCRIPTION("Passive OS fingerprint matching");
457MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_OSF);