1  // SPDX-License-Identifier: GPL-2.0-only
2  #include <linux/kernel.h>
3  #include <linux/init.h>
4  #include <linux/module.h>
5  #include <linux/proc_fs.h>
6  #include <linux/skbuff.h>
7  #include <linux/netfilter.h>
8  #include <linux/seq_file.h>
9  #include <net/protocol.h>
10  #include <net/netfilter/nf_log.h>
11  
12  #include "nf_internals.h"
13  
14  /* Internal logging interface, which relies on the real
15     LOG target modules */
16  
17  #define NFLOGGER_NAME_LEN		64
18  
19  int sysctl_nf_log_all_netns __read_mostly;
20  EXPORT_SYMBOL(sysctl_nf_log_all_netns);
21  
22  static struct nf_logger __rcu *loggers[NFPROTO_NUMPROTO][NF_LOG_TYPE_MAX] __read_mostly;
23  static DEFINE_MUTEX(nf_log_mutex);
24  
25  #define nft_log_dereference(logger) \
26  	rcu_dereference_protected(logger, lockdep_is_held(&nf_log_mutex))
27  
__find_logger(int pf,const char * str_logger)28  static struct nf_logger *__find_logger(int pf, const char *str_logger)
29  {
30  	struct nf_logger *log;
31  	int i;
32  
33  	for (i = 0; i < NF_LOG_TYPE_MAX; i++) {
34  		log = nft_log_dereference(loggers[pf][i]);
35  		if (!log)
36  			continue;
37  
38  		if (!strncasecmp(str_logger, log->name, strlen(log->name)))
39  			return log;
40  	}
41  
42  	return NULL;
43  }
44  
nf_log_set(struct net * net,u_int8_t pf,const struct nf_logger * logger)45  int nf_log_set(struct net *net, u_int8_t pf, const struct nf_logger *logger)
46  {
47  	const struct nf_logger *log;
48  
49  	if (pf == NFPROTO_UNSPEC || pf >= ARRAY_SIZE(net->nf.nf_loggers))
50  		return -EOPNOTSUPP;
51  
52  	mutex_lock(&nf_log_mutex);
53  	log = nft_log_dereference(net->nf.nf_loggers[pf]);
54  	if (log == NULL)
55  		rcu_assign_pointer(net->nf.nf_loggers[pf], logger);
56  
57  	mutex_unlock(&nf_log_mutex);
58  
59  	return 0;
60  }
61  EXPORT_SYMBOL(nf_log_set);
62  
nf_log_unset(struct net * net,const struct nf_logger * logger)63  void nf_log_unset(struct net *net, const struct nf_logger *logger)
64  {
65  	int i;
66  	const struct nf_logger *log;
67  
68  	mutex_lock(&nf_log_mutex);
69  	for (i = 0; i < NFPROTO_NUMPROTO; i++) {
70  		log = nft_log_dereference(net->nf.nf_loggers[i]);
71  		if (log == logger)
72  			RCU_INIT_POINTER(net->nf.nf_loggers[i], NULL);
73  	}
74  	mutex_unlock(&nf_log_mutex);
75  }
76  EXPORT_SYMBOL(nf_log_unset);
77  
78  /* return EEXIST if the same logger is registered, 0 on success. */
nf_log_register(u_int8_t pf,struct nf_logger * logger)79  int nf_log_register(u_int8_t pf, struct nf_logger *logger)
80  {
81  	int i;
82  	int ret = 0;
83  
84  	if (pf >= ARRAY_SIZE(init_net.nf.nf_loggers))
85  		return -EINVAL;
86  
87  	mutex_lock(&nf_log_mutex);
88  
89  	if (pf == NFPROTO_UNSPEC) {
90  		for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) {
91  			if (rcu_access_pointer(loggers[i][logger->type])) {
92  				ret = -EEXIST;
93  				goto unlock;
94  			}
95  		}
96  		for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++)
97  			rcu_assign_pointer(loggers[i][logger->type], logger);
98  	} else {
99  		if (rcu_access_pointer(loggers[pf][logger->type])) {
100  			ret = -EEXIST;
101  			goto unlock;
102  		}
103  		rcu_assign_pointer(loggers[pf][logger->type], logger);
104  	}
105  
106  unlock:
107  	mutex_unlock(&nf_log_mutex);
108  	return ret;
109  }
110  EXPORT_SYMBOL(nf_log_register);
111  
nf_log_unregister(struct nf_logger * logger)112  void nf_log_unregister(struct nf_logger *logger)
113  {
114  	const struct nf_logger *log;
115  	int i;
116  
117  	mutex_lock(&nf_log_mutex);
118  	for (i = 0; i < NFPROTO_NUMPROTO; i++) {
119  		log = nft_log_dereference(loggers[i][logger->type]);
120  		if (log == logger)
121  			RCU_INIT_POINTER(loggers[i][logger->type], NULL);
122  	}
123  	mutex_unlock(&nf_log_mutex);
124  	synchronize_rcu();
125  }
126  EXPORT_SYMBOL(nf_log_unregister);
127  
nf_log_bind_pf(struct net * net,u_int8_t pf,const struct nf_logger * logger)128  int nf_log_bind_pf(struct net *net, u_int8_t pf,
129  		   const struct nf_logger *logger)
130  {
131  	if (pf >= ARRAY_SIZE(net->nf.nf_loggers))
132  		return -EINVAL;
133  	mutex_lock(&nf_log_mutex);
134  	if (__find_logger(pf, logger->name) == NULL) {
135  		mutex_unlock(&nf_log_mutex);
136  		return -ENOENT;
137  	}
138  	rcu_assign_pointer(net->nf.nf_loggers[pf], logger);
139  	mutex_unlock(&nf_log_mutex);
140  	return 0;
141  }
142  EXPORT_SYMBOL(nf_log_bind_pf);
143  
nf_log_unbind_pf(struct net * net,u_int8_t pf)144  void nf_log_unbind_pf(struct net *net, u_int8_t pf)
145  {
146  	if (pf >= ARRAY_SIZE(net->nf.nf_loggers))
147  		return;
148  	mutex_lock(&nf_log_mutex);
149  	RCU_INIT_POINTER(net->nf.nf_loggers[pf], NULL);
150  	mutex_unlock(&nf_log_mutex);
151  }
152  EXPORT_SYMBOL(nf_log_unbind_pf);
153  
nf_logger_find_get(int pf,enum nf_log_type type)154  int nf_logger_find_get(int pf, enum nf_log_type type)
155  {
156  	struct nf_logger *logger;
157  	int ret = -ENOENT;
158  
159  	if (pf >= ARRAY_SIZE(loggers))
160  		return -EINVAL;
161  	if (type >= NF_LOG_TYPE_MAX)
162  		return -EINVAL;
163  
164  	if (pf == NFPROTO_INET) {
165  		ret = nf_logger_find_get(NFPROTO_IPV4, type);
166  		if (ret < 0)
167  			return ret;
168  
169  		ret = nf_logger_find_get(NFPROTO_IPV6, type);
170  		if (ret < 0) {
171  			nf_logger_put(NFPROTO_IPV4, type);
172  			return ret;
173  		}
174  
175  		return 0;
176  	}
177  
178  	rcu_read_lock();
179  	logger = rcu_dereference(loggers[pf][type]);
180  	if (logger == NULL)
181  		goto out;
182  
183  	if (try_module_get(logger->me))
184  		ret = 0;
185  out:
186  	rcu_read_unlock();
187  	return ret;
188  }
189  EXPORT_SYMBOL_GPL(nf_logger_find_get);
190  
nf_logger_put(int pf,enum nf_log_type type)191  void nf_logger_put(int pf, enum nf_log_type type)
192  {
193  	struct nf_logger *logger;
194  
195  	if (pf == NFPROTO_INET) {
196  		nf_logger_put(NFPROTO_IPV4, type);
197  		nf_logger_put(NFPROTO_IPV6, type);
198  		return;
199  	}
200  
201  	rcu_read_lock();
202  	logger = rcu_dereference(loggers[pf][type]);
203  	if (!logger)
204  		WARN_ON_ONCE(1);
205  	else
206  		module_put(logger->me);
207  	rcu_read_unlock();
208  }
209  EXPORT_SYMBOL_GPL(nf_logger_put);
210  
nf_log_packet(struct net * net,u_int8_t pf,unsigned int hooknum,const struct sk_buff * skb,const struct net_device * in,const struct net_device * out,const struct nf_loginfo * loginfo,const char * fmt,...)211  void nf_log_packet(struct net *net,
212  		   u_int8_t pf,
213  		   unsigned int hooknum,
214  		   const struct sk_buff *skb,
215  		   const struct net_device *in,
216  		   const struct net_device *out,
217  		   const struct nf_loginfo *loginfo,
218  		   const char *fmt, ...)
219  {
220  	va_list args;
221  	char prefix[NF_LOG_PREFIXLEN];
222  	const struct nf_logger *logger;
223  
224  	rcu_read_lock();
225  	if (loginfo != NULL)
226  		logger = rcu_dereference(loggers[pf][loginfo->type]);
227  	else
228  		logger = rcu_dereference(net->nf.nf_loggers[pf]);
229  
230  	if (logger) {
231  		va_start(args, fmt);
232  		vsnprintf(prefix, sizeof(prefix), fmt, args);
233  		va_end(args);
234  		logger->logfn(net, pf, hooknum, skb, in, out, loginfo, prefix);
235  	}
236  	rcu_read_unlock();
237  }
238  EXPORT_SYMBOL(nf_log_packet);
239  
nf_log_trace(struct net * net,u_int8_t pf,unsigned int hooknum,const struct sk_buff * skb,const struct net_device * in,const struct net_device * out,const struct nf_loginfo * loginfo,const char * fmt,...)240  void nf_log_trace(struct net *net,
241  		  u_int8_t pf,
242  		  unsigned int hooknum,
243  		  const struct sk_buff *skb,
244  		  const struct net_device *in,
245  		  const struct net_device *out,
246  		  const struct nf_loginfo *loginfo, const char *fmt, ...)
247  {
248  	va_list args;
249  	char prefix[NF_LOG_PREFIXLEN];
250  	const struct nf_logger *logger;
251  
252  	rcu_read_lock();
253  	logger = rcu_dereference(net->nf.nf_loggers[pf]);
254  	if (logger) {
255  		va_start(args, fmt);
256  		vsnprintf(prefix, sizeof(prefix), fmt, args);
257  		va_end(args);
258  		logger->logfn(net, pf, hooknum, skb, in, out, loginfo, prefix);
259  	}
260  	rcu_read_unlock();
261  }
262  EXPORT_SYMBOL(nf_log_trace);
263  
264  #define S_SIZE (1024 - (sizeof(unsigned int) + 1))
265  
266  struct nf_log_buf {
267  	unsigned int	count;
268  	char		buf[S_SIZE + 1];
269  };
270  static struct nf_log_buf emergency, *emergency_ptr = &emergency;
271  
nf_log_buf_add(struct nf_log_buf * m,const char * f,...)272  __printf(2, 3) int nf_log_buf_add(struct nf_log_buf *m, const char *f, ...)
273  {
274  	va_list args;
275  	int len;
276  
277  	if (likely(m->count < S_SIZE)) {
278  		va_start(args, f);
279  		len = vsnprintf(m->buf + m->count, S_SIZE - m->count, f, args);
280  		va_end(args);
281  		if (likely(m->count + len < S_SIZE)) {
282  			m->count += len;
283  			return 0;
284  		}
285  	}
286  	m->count = S_SIZE;
287  	printk_once(KERN_ERR KBUILD_MODNAME " please increase S_SIZE\n");
288  	return -1;
289  }
290  EXPORT_SYMBOL_GPL(nf_log_buf_add);
291  
nf_log_buf_open(void)292  struct nf_log_buf *nf_log_buf_open(void)
293  {
294  	struct nf_log_buf *m = kmalloc(sizeof(*m), GFP_ATOMIC);
295  
296  	if (unlikely(!m)) {
297  		local_bh_disable();
298  		do {
299  			m = xchg(&emergency_ptr, NULL);
300  		} while (!m);
301  	}
302  	m->count = 0;
303  	return m;
304  }
305  EXPORT_SYMBOL_GPL(nf_log_buf_open);
306  
nf_log_buf_close(struct nf_log_buf * m)307  void nf_log_buf_close(struct nf_log_buf *m)
308  {
309  	m->buf[m->count] = 0;
310  	printk("%s\n", m->buf);
311  
312  	if (likely(m != &emergency))
313  		kfree(m);
314  	else {
315  		emergency_ptr = m;
316  		local_bh_enable();
317  	}
318  }
319  EXPORT_SYMBOL_GPL(nf_log_buf_close);
320  
321  #ifdef CONFIG_PROC_FS
seq_start(struct seq_file * seq,loff_t * pos)322  static void *seq_start(struct seq_file *seq, loff_t *pos)
323  {
324  	struct net *net = seq_file_net(seq);
325  
326  	mutex_lock(&nf_log_mutex);
327  
328  	if (*pos >= ARRAY_SIZE(net->nf.nf_loggers))
329  		return NULL;
330  
331  	return pos;
332  }
333  
seq_next(struct seq_file * s,void * v,loff_t * pos)334  static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
335  {
336  	struct net *net = seq_file_net(s);
337  
338  	(*pos)++;
339  
340  	if (*pos >= ARRAY_SIZE(net->nf.nf_loggers))
341  		return NULL;
342  
343  	return pos;
344  }
345  
seq_stop(struct seq_file * s,void * v)346  static void seq_stop(struct seq_file *s, void *v)
347  {
348  	mutex_unlock(&nf_log_mutex);
349  }
350  
seq_show(struct seq_file * s,void * v)351  static int seq_show(struct seq_file *s, void *v)
352  {
353  	loff_t *pos = v;
354  	const struct nf_logger *logger;
355  	int i;
356  	struct net *net = seq_file_net(s);
357  
358  	logger = nft_log_dereference(net->nf.nf_loggers[*pos]);
359  
360  	if (!logger)
361  		seq_printf(s, "%2lld NONE (", *pos);
362  	else
363  		seq_printf(s, "%2lld %s (", *pos, logger->name);
364  
365  	if (seq_has_overflowed(s))
366  		return -ENOSPC;
367  
368  	for (i = 0; i < NF_LOG_TYPE_MAX; i++) {
369  		if (loggers[*pos][i] == NULL)
370  			continue;
371  
372  		logger = nft_log_dereference(loggers[*pos][i]);
373  		seq_puts(s, logger->name);
374  		if (i == 0 && loggers[*pos][i + 1] != NULL)
375  			seq_puts(s, ",");
376  
377  		if (seq_has_overflowed(s))
378  			return -ENOSPC;
379  	}
380  
381  	seq_puts(s, ")\n");
382  
383  	if (seq_has_overflowed(s))
384  		return -ENOSPC;
385  	return 0;
386  }
387  
388  static const struct seq_operations nflog_seq_ops = {
389  	.start	= seq_start,
390  	.next	= seq_next,
391  	.stop	= seq_stop,
392  	.show	= seq_show,
393  };
394  #endif /* PROC_FS */
395  
396  #ifdef CONFIG_SYSCTL
397  static char nf_log_sysctl_fnames[NFPROTO_NUMPROTO-NFPROTO_UNSPEC][3];
398  static struct ctl_table nf_log_sysctl_table[NFPROTO_NUMPROTO];
399  static struct ctl_table_header *nf_log_sysctl_fhdr;
400  
401  static struct ctl_table nf_log_sysctl_ftable[] = {
402  	{
403  		.procname	= "nf_log_all_netns",
404  		.data		= &sysctl_nf_log_all_netns,
405  		.maxlen		= sizeof(sysctl_nf_log_all_netns),
406  		.mode		= 0644,
407  		.proc_handler	= proc_dointvec,
408  	},
409  };
410  
nf_log_proc_dostring(const struct ctl_table * table,int write,void * buffer,size_t * lenp,loff_t * ppos)411  static int nf_log_proc_dostring(const struct ctl_table *table, int write,
412  			 void *buffer, size_t *lenp, loff_t *ppos)
413  {
414  	const struct nf_logger *logger;
415  	char buf[NFLOGGER_NAME_LEN];
416  	int r = 0;
417  	int tindex = (unsigned long)table->extra1;
418  	struct net *net = table->extra2;
419  
420  	if (write) {
421  		struct ctl_table tmp = *table;
422  
423  		/* proc_dostring() can append to existing strings, so we need to
424  		 * initialize it as an empty string.
425  		 */
426  		buf[0] = '\0';
427  		tmp.data = buf;
428  		r = proc_dostring(&tmp, write, buffer, lenp, ppos);
429  		if (r)
430  			return r;
431  
432  		if (!strcmp(buf, "NONE")) {
433  			nf_log_unbind_pf(net, tindex);
434  			return 0;
435  		}
436  		mutex_lock(&nf_log_mutex);
437  		logger = __find_logger(tindex, buf);
438  		if (logger == NULL) {
439  			mutex_unlock(&nf_log_mutex);
440  			return -ENOENT;
441  		}
442  		rcu_assign_pointer(net->nf.nf_loggers[tindex], logger);
443  		mutex_unlock(&nf_log_mutex);
444  	} else {
445  		struct ctl_table tmp = *table;
446  
447  		tmp.data = buf;
448  		mutex_lock(&nf_log_mutex);
449  		logger = nft_log_dereference(net->nf.nf_loggers[tindex]);
450  		if (!logger)
451  			strscpy(buf, "NONE", sizeof(buf));
452  		else
453  			strscpy(buf, logger->name, sizeof(buf));
454  		mutex_unlock(&nf_log_mutex);
455  		r = proc_dostring(&tmp, write, buffer, lenp, ppos);
456  	}
457  
458  	return r;
459  }
460  
netfilter_log_sysctl_init(struct net * net)461  static int netfilter_log_sysctl_init(struct net *net)
462  {
463  	int i;
464  	struct ctl_table *table;
465  
466  	table = nf_log_sysctl_table;
467  	if (!net_eq(net, &init_net)) {
468  		table = kmemdup(nf_log_sysctl_table,
469  				 sizeof(nf_log_sysctl_table),
470  				 GFP_KERNEL);
471  		if (!table)
472  			goto err_alloc;
473  	} else {
474  		for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) {
475  			snprintf(nf_log_sysctl_fnames[i],
476  				 3, "%d", i);
477  			nf_log_sysctl_table[i].procname	=
478  				nf_log_sysctl_fnames[i];
479  			nf_log_sysctl_table[i].maxlen = NFLOGGER_NAME_LEN;
480  			nf_log_sysctl_table[i].mode = 0644;
481  			nf_log_sysctl_table[i].proc_handler =
482  				nf_log_proc_dostring;
483  			nf_log_sysctl_table[i].extra1 =
484  				(void *)(unsigned long) i;
485  		}
486  		nf_log_sysctl_fhdr = register_net_sysctl(net, "net/netfilter",
487  							 nf_log_sysctl_ftable);
488  		if (!nf_log_sysctl_fhdr)
489  			goto err_freg;
490  	}
491  
492  	for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++)
493  		table[i].extra2 = net;
494  
495  	net->nf.nf_log_dir_header = register_net_sysctl_sz(net,
496  							   "net/netfilter/nf_log",
497  							   table,
498  							   ARRAY_SIZE(nf_log_sysctl_table));
499  	if (!net->nf.nf_log_dir_header)
500  		goto err_reg;
501  
502  	return 0;
503  
504  err_reg:
505  	if (!net_eq(net, &init_net))
506  		kfree(table);
507  	else
508  		unregister_net_sysctl_table(nf_log_sysctl_fhdr);
509  err_freg:
510  err_alloc:
511  	return -ENOMEM;
512  }
513  
netfilter_log_sysctl_exit(struct net * net)514  static void netfilter_log_sysctl_exit(struct net *net)
515  {
516  	const struct ctl_table *table;
517  
518  	table = net->nf.nf_log_dir_header->ctl_table_arg;
519  	unregister_net_sysctl_table(net->nf.nf_log_dir_header);
520  	if (!net_eq(net, &init_net))
521  		kfree(table);
522  	else
523  		unregister_net_sysctl_table(nf_log_sysctl_fhdr);
524  }
525  #else
netfilter_log_sysctl_init(struct net * net)526  static int netfilter_log_sysctl_init(struct net *net)
527  {
528  	return 0;
529  }
530  
netfilter_log_sysctl_exit(struct net * net)531  static void netfilter_log_sysctl_exit(struct net *net)
532  {
533  }
534  #endif /* CONFIG_SYSCTL */
535  
nf_log_net_init(struct net * net)536  static int __net_init nf_log_net_init(struct net *net)
537  {
538  	int ret = -ENOMEM;
539  
540  #ifdef CONFIG_PROC_FS
541  	if (!proc_create_net("nf_log", 0444, net->nf.proc_netfilter,
542  			&nflog_seq_ops, sizeof(struct seq_net_private)))
543  		return ret;
544  #endif
545  	ret = netfilter_log_sysctl_init(net);
546  	if (ret < 0)
547  		goto out_sysctl;
548  
549  	return 0;
550  
551  out_sysctl:
552  #ifdef CONFIG_PROC_FS
553  	remove_proc_entry("nf_log", net->nf.proc_netfilter);
554  #endif
555  	return ret;
556  }
557  
nf_log_net_exit(struct net * net)558  static void __net_exit nf_log_net_exit(struct net *net)
559  {
560  	netfilter_log_sysctl_exit(net);
561  #ifdef CONFIG_PROC_FS
562  	remove_proc_entry("nf_log", net->nf.proc_netfilter);
563  #endif
564  }
565  
566  static struct pernet_operations nf_log_net_ops = {
567  	.init = nf_log_net_init,
568  	.exit = nf_log_net_exit,
569  };
570  
netfilter_log_init(void)571  int __init netfilter_log_init(void)
572  {
573  	return register_pernet_subsys(&nf_log_net_ops);
574  }
575