xref: /openbmc/linux/net/netfilter/nf_log.c (revision 87832e937c808a7ebc41254b408362e3255c87c9)
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  		if (loggers[pf][i] == NULL)
35  			continue;
36  
37  		log = nft_log_dereference(loggers[pf][i]);
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 == NFPROTO_INET) {
160  		ret = nf_logger_find_get(NFPROTO_IPV4, type);
161  		if (ret < 0)
162  			return ret;
163  
164  		ret = nf_logger_find_get(NFPROTO_IPV6, type);
165  		if (ret < 0) {
166  			nf_logger_put(NFPROTO_IPV4, type);
167  			return ret;
168  		}
169  
170  		return 0;
171  	}
172  
173  	rcu_read_lock();
174  	logger = rcu_dereference(loggers[pf][type]);
175  	if (logger == NULL)
176  		goto out;
177  
178  	if (try_module_get(logger->me))
179  		ret = 0;
180  out:
181  	rcu_read_unlock();
182  	return ret;
183  }
184  EXPORT_SYMBOL_GPL(nf_logger_find_get);
185  
nf_logger_put(int pf,enum nf_log_type type)186  void nf_logger_put(int pf, enum nf_log_type type)
187  {
188  	struct nf_logger *logger;
189  
190  	if (pf == NFPROTO_INET) {
191  		nf_logger_put(NFPROTO_IPV4, type);
192  		nf_logger_put(NFPROTO_IPV6, type);
193  		return;
194  	}
195  
196  	rcu_read_lock();
197  	logger = rcu_dereference(loggers[pf][type]);
198  	if (!logger)
199  		WARN_ON_ONCE(1);
200  	else
201  		module_put(logger->me);
202  	rcu_read_unlock();
203  }
204  EXPORT_SYMBOL_GPL(nf_logger_put);
205  
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,...)206  void nf_log_packet(struct net *net,
207  		   u_int8_t pf,
208  		   unsigned int hooknum,
209  		   const struct sk_buff *skb,
210  		   const struct net_device *in,
211  		   const struct net_device *out,
212  		   const struct nf_loginfo *loginfo,
213  		   const char *fmt, ...)
214  {
215  	va_list args;
216  	char prefix[NF_LOG_PREFIXLEN];
217  	const struct nf_logger *logger;
218  
219  	rcu_read_lock();
220  	if (loginfo != NULL)
221  		logger = rcu_dereference(loggers[pf][loginfo->type]);
222  	else
223  		logger = rcu_dereference(net->nf.nf_loggers[pf]);
224  
225  	if (logger) {
226  		va_start(args, fmt);
227  		vsnprintf(prefix, sizeof(prefix), fmt, args);
228  		va_end(args);
229  		logger->logfn(net, pf, hooknum, skb, in, out, loginfo, prefix);
230  	}
231  	rcu_read_unlock();
232  }
233  EXPORT_SYMBOL(nf_log_packet);
234  
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,...)235  void nf_log_trace(struct net *net,
236  		  u_int8_t pf,
237  		  unsigned int hooknum,
238  		  const struct sk_buff *skb,
239  		  const struct net_device *in,
240  		  const struct net_device *out,
241  		  const struct nf_loginfo *loginfo, const char *fmt, ...)
242  {
243  	va_list args;
244  	char prefix[NF_LOG_PREFIXLEN];
245  	const struct nf_logger *logger;
246  
247  	rcu_read_lock();
248  	logger = rcu_dereference(net->nf.nf_loggers[pf]);
249  	if (logger) {
250  		va_start(args, fmt);
251  		vsnprintf(prefix, sizeof(prefix), fmt, args);
252  		va_end(args);
253  		logger->logfn(net, pf, hooknum, skb, in, out, loginfo, prefix);
254  	}
255  	rcu_read_unlock();
256  }
257  EXPORT_SYMBOL(nf_log_trace);
258  
259  #define S_SIZE (1024 - (sizeof(unsigned int) + 1))
260  
261  struct nf_log_buf {
262  	unsigned int	count;
263  	char		buf[S_SIZE + 1];
264  };
265  static struct nf_log_buf emergency, *emergency_ptr = &emergency;
266  
nf_log_buf_add(struct nf_log_buf * m,const char * f,...)267  __printf(2, 3) int nf_log_buf_add(struct nf_log_buf *m, const char *f, ...)
268  {
269  	va_list args;
270  	int len;
271  
272  	if (likely(m->count < S_SIZE)) {
273  		va_start(args, f);
274  		len = vsnprintf(m->buf + m->count, S_SIZE - m->count, f, args);
275  		va_end(args);
276  		if (likely(m->count + len < S_SIZE)) {
277  			m->count += len;
278  			return 0;
279  		}
280  	}
281  	m->count = S_SIZE;
282  	printk_once(KERN_ERR KBUILD_MODNAME " please increase S_SIZE\n");
283  	return -1;
284  }
285  EXPORT_SYMBOL_GPL(nf_log_buf_add);
286  
nf_log_buf_open(void)287  struct nf_log_buf *nf_log_buf_open(void)
288  {
289  	struct nf_log_buf *m = kmalloc(sizeof(*m), GFP_ATOMIC);
290  
291  	if (unlikely(!m)) {
292  		local_bh_disable();
293  		do {
294  			m = xchg(&emergency_ptr, NULL);
295  		} while (!m);
296  	}
297  	m->count = 0;
298  	return m;
299  }
300  EXPORT_SYMBOL_GPL(nf_log_buf_open);
301  
nf_log_buf_close(struct nf_log_buf * m)302  void nf_log_buf_close(struct nf_log_buf *m)
303  {
304  	m->buf[m->count] = 0;
305  	printk("%s\n", m->buf);
306  
307  	if (likely(m != &emergency))
308  		kfree(m);
309  	else {
310  		emergency_ptr = m;
311  		local_bh_enable();
312  	}
313  }
314  EXPORT_SYMBOL_GPL(nf_log_buf_close);
315  
316  #ifdef CONFIG_PROC_FS
seq_start(struct seq_file * seq,loff_t * pos)317  static void *seq_start(struct seq_file *seq, loff_t *pos)
318  {
319  	struct net *net = seq_file_net(seq);
320  
321  	mutex_lock(&nf_log_mutex);
322  
323  	if (*pos >= ARRAY_SIZE(net->nf.nf_loggers))
324  		return NULL;
325  
326  	return pos;
327  }
328  
seq_next(struct seq_file * s,void * v,loff_t * pos)329  static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
330  {
331  	struct net *net = seq_file_net(s);
332  
333  	(*pos)++;
334  
335  	if (*pos >= ARRAY_SIZE(net->nf.nf_loggers))
336  		return NULL;
337  
338  	return pos;
339  }
340  
seq_stop(struct seq_file * s,void * v)341  static void seq_stop(struct seq_file *s, void *v)
342  {
343  	mutex_unlock(&nf_log_mutex);
344  }
345  
seq_show(struct seq_file * s,void * v)346  static int seq_show(struct seq_file *s, void *v)
347  {
348  	loff_t *pos = v;
349  	const struct nf_logger *logger;
350  	int i;
351  	struct net *net = seq_file_net(s);
352  
353  	logger = nft_log_dereference(net->nf.nf_loggers[*pos]);
354  
355  	if (!logger)
356  		seq_printf(s, "%2lld NONE (", *pos);
357  	else
358  		seq_printf(s, "%2lld %s (", *pos, logger->name);
359  
360  	if (seq_has_overflowed(s))
361  		return -ENOSPC;
362  
363  	for (i = 0; i < NF_LOG_TYPE_MAX; i++) {
364  		if (loggers[*pos][i] == NULL)
365  			continue;
366  
367  		logger = nft_log_dereference(loggers[*pos][i]);
368  		seq_puts(s, logger->name);
369  		if (i == 0 && loggers[*pos][i + 1] != NULL)
370  			seq_puts(s, ",");
371  
372  		if (seq_has_overflowed(s))
373  			return -ENOSPC;
374  	}
375  
376  	seq_puts(s, ")\n");
377  
378  	if (seq_has_overflowed(s))
379  		return -ENOSPC;
380  	return 0;
381  }
382  
383  static const struct seq_operations nflog_seq_ops = {
384  	.start	= seq_start,
385  	.next	= seq_next,
386  	.stop	= seq_stop,
387  	.show	= seq_show,
388  };
389  #endif /* PROC_FS */
390  
391  #ifdef CONFIG_SYSCTL
392  static char nf_log_sysctl_fnames[NFPROTO_NUMPROTO-NFPROTO_UNSPEC][3];
393  static struct ctl_table nf_log_sysctl_table[NFPROTO_NUMPROTO+1];
394  static struct ctl_table_header *nf_log_sysctl_fhdr;
395  
396  static struct ctl_table nf_log_sysctl_ftable[] = {
397  	{
398  		.procname	= "nf_log_all_netns",
399  		.data		= &sysctl_nf_log_all_netns,
400  		.maxlen		= sizeof(sysctl_nf_log_all_netns),
401  		.mode		= 0644,
402  		.proc_handler	= proc_dointvec,
403  	},
404  	{ }
405  };
406  
nf_log_proc_dostring(struct ctl_table * table,int write,void * buffer,size_t * lenp,loff_t * ppos)407  static int nf_log_proc_dostring(struct ctl_table *table, int write,
408  			 void *buffer, size_t *lenp, loff_t *ppos)
409  {
410  	const struct nf_logger *logger;
411  	char buf[NFLOGGER_NAME_LEN];
412  	int r = 0;
413  	int tindex = (unsigned long)table->extra1;
414  	struct net *net = table->extra2;
415  
416  	if (write) {
417  		struct ctl_table tmp = *table;
418  
419  		/* proc_dostring() can append to existing strings, so we need to
420  		 * initialize it as an empty string.
421  		 */
422  		buf[0] = '\0';
423  		tmp.data = buf;
424  		r = proc_dostring(&tmp, write, buffer, lenp, ppos);
425  		if (r)
426  			return r;
427  
428  		if (!strcmp(buf, "NONE")) {
429  			nf_log_unbind_pf(net, tindex);
430  			return 0;
431  		}
432  		mutex_lock(&nf_log_mutex);
433  		logger = __find_logger(tindex, buf);
434  		if (logger == NULL) {
435  			mutex_unlock(&nf_log_mutex);
436  			return -ENOENT;
437  		}
438  		rcu_assign_pointer(net->nf.nf_loggers[tindex], logger);
439  		mutex_unlock(&nf_log_mutex);
440  	} else {
441  		struct ctl_table tmp = *table;
442  
443  		tmp.data = buf;
444  		mutex_lock(&nf_log_mutex);
445  		logger = nft_log_dereference(net->nf.nf_loggers[tindex]);
446  		if (!logger)
447  			strscpy(buf, "NONE", sizeof(buf));
448  		else
449  			strscpy(buf, logger->name, sizeof(buf));
450  		mutex_unlock(&nf_log_mutex);
451  		r = proc_dostring(&tmp, write, buffer, lenp, ppos);
452  	}
453  
454  	return r;
455  }
456  
netfilter_log_sysctl_init(struct net * net)457  static int netfilter_log_sysctl_init(struct net *net)
458  {
459  	int i;
460  	struct ctl_table *table;
461  
462  	table = nf_log_sysctl_table;
463  	if (!net_eq(net, &init_net)) {
464  		table = kmemdup(nf_log_sysctl_table,
465  				 sizeof(nf_log_sysctl_table),
466  				 GFP_KERNEL);
467  		if (!table)
468  			goto err_alloc;
469  	} else {
470  		for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) {
471  			snprintf(nf_log_sysctl_fnames[i],
472  				 3, "%d", i);
473  			nf_log_sysctl_table[i].procname	=
474  				nf_log_sysctl_fnames[i];
475  			nf_log_sysctl_table[i].maxlen = NFLOGGER_NAME_LEN;
476  			nf_log_sysctl_table[i].mode = 0644;
477  			nf_log_sysctl_table[i].proc_handler =
478  				nf_log_proc_dostring;
479  			nf_log_sysctl_table[i].extra1 =
480  				(void *)(unsigned long) i;
481  		}
482  		nf_log_sysctl_fhdr = register_net_sysctl(net, "net/netfilter",
483  							 nf_log_sysctl_ftable);
484  		if (!nf_log_sysctl_fhdr)
485  			goto err_freg;
486  	}
487  
488  	for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++)
489  		table[i].extra2 = net;
490  
491  	net->nf.nf_log_dir_header = register_net_sysctl_sz(net,
492  							   "net/netfilter/nf_log",
493  							   table,
494  							   ARRAY_SIZE(nf_log_sysctl_table));
495  	if (!net->nf.nf_log_dir_header)
496  		goto err_reg;
497  
498  	return 0;
499  
500  err_reg:
501  	if (!net_eq(net, &init_net))
502  		kfree(table);
503  	else
504  		unregister_net_sysctl_table(nf_log_sysctl_fhdr);
505  err_freg:
506  err_alloc:
507  	return -ENOMEM;
508  }
509  
netfilter_log_sysctl_exit(struct net * net)510  static void netfilter_log_sysctl_exit(struct net *net)
511  {
512  	struct ctl_table *table;
513  
514  	table = net->nf.nf_log_dir_header->ctl_table_arg;
515  	unregister_net_sysctl_table(net->nf.nf_log_dir_header);
516  	if (!net_eq(net, &init_net))
517  		kfree(table);
518  	else
519  		unregister_net_sysctl_table(nf_log_sysctl_fhdr);
520  }
521  #else
netfilter_log_sysctl_init(struct net * net)522  static int netfilter_log_sysctl_init(struct net *net)
523  {
524  	return 0;
525  }
526  
netfilter_log_sysctl_exit(struct net * net)527  static void netfilter_log_sysctl_exit(struct net *net)
528  {
529  }
530  #endif /* CONFIG_SYSCTL */
531  
nf_log_net_init(struct net * net)532  static int __net_init nf_log_net_init(struct net *net)
533  {
534  	int ret = -ENOMEM;
535  
536  #ifdef CONFIG_PROC_FS
537  	if (!proc_create_net("nf_log", 0444, net->nf.proc_netfilter,
538  			&nflog_seq_ops, sizeof(struct seq_net_private)))
539  		return ret;
540  #endif
541  	ret = netfilter_log_sysctl_init(net);
542  	if (ret < 0)
543  		goto out_sysctl;
544  
545  	return 0;
546  
547  out_sysctl:
548  #ifdef CONFIG_PROC_FS
549  	remove_proc_entry("nf_log", net->nf.proc_netfilter);
550  #endif
551  	return ret;
552  }
553  
nf_log_net_exit(struct net * net)554  static void __net_exit nf_log_net_exit(struct net *net)
555  {
556  	netfilter_log_sysctl_exit(net);
557  #ifdef CONFIG_PROC_FS
558  	remove_proc_entry("nf_log", net->nf.proc_netfilter);
559  #endif
560  }
561  
562  static struct pernet_operations nf_log_net_ops = {
563  	.init = nf_log_net_init,
564  	.exit = nf_log_net_exit,
565  };
566  
netfilter_log_init(void)567  int __init netfilter_log_init(void)
568  {
569  	return register_pernet_subsys(&nf_log_net_ops);
570  }
571