cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

nf_log.c (12656B)


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