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

xt_CT.c (8967B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (c) 2010 Patrick McHardy <kaber@trash.net>
      4 */
      5#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
      6#include <linux/module.h>
      7#include <linux/gfp.h>
      8#include <linux/skbuff.h>
      9#include <linux/netfilter_ipv4/ip_tables.h>
     10#include <linux/netfilter_ipv6/ip6_tables.h>
     11#include <linux/netfilter/x_tables.h>
     12#include <linux/netfilter/xt_CT.h>
     13#include <net/netfilter/nf_conntrack.h>
     14#include <net/netfilter/nf_conntrack_l4proto.h>
     15#include <net/netfilter/nf_conntrack_helper.h>
     16#include <net/netfilter/nf_conntrack_ecache.h>
     17#include <net/netfilter/nf_conntrack_timeout.h>
     18#include <net/netfilter/nf_conntrack_zones.h>
     19
     20static inline int xt_ct_target(struct sk_buff *skb, struct nf_conn *ct)
     21{
     22	/* Previously seen (loopback)? Ignore. */
     23	if (skb->_nfct != 0)
     24		return XT_CONTINUE;
     25
     26	if (ct) {
     27		refcount_inc(&ct->ct_general.use);
     28		nf_ct_set(skb, ct, IP_CT_NEW);
     29	} else {
     30		nf_ct_set(skb, ct, IP_CT_UNTRACKED);
     31	}
     32
     33	return XT_CONTINUE;
     34}
     35
     36static unsigned int xt_ct_target_v0(struct sk_buff *skb,
     37				    const struct xt_action_param *par)
     38{
     39	const struct xt_ct_target_info *info = par->targinfo;
     40	struct nf_conn *ct = info->ct;
     41
     42	return xt_ct_target(skb, ct);
     43}
     44
     45static unsigned int xt_ct_target_v1(struct sk_buff *skb,
     46				    const struct xt_action_param *par)
     47{
     48	const struct xt_ct_target_info_v1 *info = par->targinfo;
     49	struct nf_conn *ct = info->ct;
     50
     51	return xt_ct_target(skb, ct);
     52}
     53
     54static u8 xt_ct_find_proto(const struct xt_tgchk_param *par)
     55{
     56	if (par->family == NFPROTO_IPV4) {
     57		const struct ipt_entry *e = par->entryinfo;
     58
     59		if (e->ip.invflags & IPT_INV_PROTO)
     60			return 0;
     61		return e->ip.proto;
     62	} else if (par->family == NFPROTO_IPV6) {
     63		const struct ip6t_entry *e = par->entryinfo;
     64
     65		if (e->ipv6.invflags & IP6T_INV_PROTO)
     66			return 0;
     67		return e->ipv6.proto;
     68	} else
     69		return 0;
     70}
     71
     72static int
     73xt_ct_set_helper(struct nf_conn *ct, const char *helper_name,
     74		 const struct xt_tgchk_param *par)
     75{
     76	struct nf_conntrack_helper *helper;
     77	struct nf_conn_help *help;
     78	u8 proto;
     79
     80	proto = xt_ct_find_proto(par);
     81	if (!proto) {
     82		pr_info_ratelimited("You must specify a L4 protocol and not use inversions on it\n");
     83		return -ENOENT;
     84	}
     85
     86	helper = nf_conntrack_helper_try_module_get(helper_name, par->family,
     87						    proto);
     88	if (helper == NULL) {
     89		pr_info_ratelimited("No such helper \"%s\"\n", helper_name);
     90		return -ENOENT;
     91	}
     92
     93	help = nf_ct_helper_ext_add(ct, GFP_KERNEL);
     94	if (help == NULL) {
     95		nf_conntrack_helper_put(helper);
     96		return -ENOMEM;
     97	}
     98
     99	help->helper = helper;
    100	return 0;
    101}
    102
    103static int
    104xt_ct_set_timeout(struct nf_conn *ct, const struct xt_tgchk_param *par,
    105		  const char *timeout_name)
    106{
    107#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
    108	const struct nf_conntrack_l4proto *l4proto;
    109	u8 proto;
    110
    111	proto = xt_ct_find_proto(par);
    112	if (!proto) {
    113		pr_info_ratelimited("You must specify a L4 protocol and not "
    114				    "use inversions on it");
    115		return -EINVAL;
    116	}
    117	l4proto = nf_ct_l4proto_find(proto);
    118	return nf_ct_set_timeout(par->net, ct, par->family, l4proto->l4proto,
    119				 timeout_name);
    120
    121#else
    122	return -EOPNOTSUPP;
    123#endif
    124}
    125
    126static u16 xt_ct_flags_to_dir(const struct xt_ct_target_info_v1 *info)
    127{
    128	switch (info->flags & (XT_CT_ZONE_DIR_ORIG |
    129			       XT_CT_ZONE_DIR_REPL)) {
    130	case XT_CT_ZONE_DIR_ORIG:
    131		return NF_CT_ZONE_DIR_ORIG;
    132	case XT_CT_ZONE_DIR_REPL:
    133		return NF_CT_ZONE_DIR_REPL;
    134	default:
    135		return NF_CT_DEFAULT_ZONE_DIR;
    136	}
    137}
    138
    139static int xt_ct_tg_check(const struct xt_tgchk_param *par,
    140			  struct xt_ct_target_info_v1 *info)
    141{
    142	struct nf_conntrack_zone zone;
    143	struct nf_conn_help *help;
    144	struct nf_conn *ct;
    145	int ret = -EOPNOTSUPP;
    146
    147	if (info->flags & XT_CT_NOTRACK) {
    148		ct = NULL;
    149		goto out;
    150	}
    151
    152#ifndef CONFIG_NF_CONNTRACK_ZONES
    153	if (info->zone || info->flags & (XT_CT_ZONE_DIR_ORIG |
    154					 XT_CT_ZONE_DIR_REPL |
    155					 XT_CT_ZONE_MARK))
    156		goto err1;
    157#endif
    158
    159	ret = nf_ct_netns_get(par->net, par->family);
    160	if (ret < 0)
    161		goto err1;
    162
    163	memset(&zone, 0, sizeof(zone));
    164	zone.id = info->zone;
    165	zone.dir = xt_ct_flags_to_dir(info);
    166	if (info->flags & XT_CT_ZONE_MARK)
    167		zone.flags |= NF_CT_FLAG_MARK;
    168
    169	ct = nf_ct_tmpl_alloc(par->net, &zone, GFP_KERNEL);
    170	if (!ct) {
    171		ret = -ENOMEM;
    172		goto err2;
    173	}
    174
    175	if ((info->ct_events || info->exp_events) &&
    176	    !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events,
    177				  GFP_KERNEL)) {
    178		ret = -EINVAL;
    179		goto err3;
    180	}
    181
    182	if (info->helper[0]) {
    183		if (strnlen(info->helper, sizeof(info->helper)) == sizeof(info->helper)) {
    184			ret = -ENAMETOOLONG;
    185			goto err3;
    186		}
    187
    188		ret = xt_ct_set_helper(ct, info->helper, par);
    189		if (ret < 0)
    190			goto err3;
    191	}
    192
    193	if (info->timeout[0]) {
    194		if (strnlen(info->timeout, sizeof(info->timeout)) == sizeof(info->timeout)) {
    195			ret = -ENAMETOOLONG;
    196			goto err4;
    197		}
    198
    199		ret = xt_ct_set_timeout(ct, par, info->timeout);
    200		if (ret < 0)
    201			goto err4;
    202	}
    203	__set_bit(IPS_CONFIRMED_BIT, &ct->status);
    204out:
    205	info->ct = ct;
    206	return 0;
    207
    208err4:
    209	help = nfct_help(ct);
    210	if (help)
    211		nf_conntrack_helper_put(help->helper);
    212err3:
    213	nf_ct_tmpl_free(ct);
    214err2:
    215	nf_ct_netns_put(par->net, par->family);
    216err1:
    217	return ret;
    218}
    219
    220static int xt_ct_tg_check_v0(const struct xt_tgchk_param *par)
    221{
    222	struct xt_ct_target_info *info = par->targinfo;
    223	struct xt_ct_target_info_v1 info_v1 = {
    224		.flags 		= info->flags,
    225		.zone		= info->zone,
    226		.ct_events	= info->ct_events,
    227		.exp_events	= info->exp_events,
    228	};
    229	int ret;
    230
    231	if (info->flags & ~XT_CT_NOTRACK)
    232		return -EINVAL;
    233
    234	memcpy(info_v1.helper, info->helper, sizeof(info->helper));
    235
    236	ret = xt_ct_tg_check(par, &info_v1);
    237	if (ret < 0)
    238		return ret;
    239
    240	info->ct = info_v1.ct;
    241
    242	return ret;
    243}
    244
    245static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
    246{
    247	struct xt_ct_target_info_v1 *info = par->targinfo;
    248
    249	if (info->flags & ~XT_CT_NOTRACK)
    250		return -EINVAL;
    251
    252	return xt_ct_tg_check(par, par->targinfo);
    253}
    254
    255static int xt_ct_tg_check_v2(const struct xt_tgchk_param *par)
    256{
    257	struct xt_ct_target_info_v1 *info = par->targinfo;
    258
    259	if (info->flags & ~XT_CT_MASK)
    260		return -EINVAL;
    261
    262	return xt_ct_tg_check(par, par->targinfo);
    263}
    264
    265static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par,
    266			     struct xt_ct_target_info_v1 *info)
    267{
    268	struct nf_conn *ct = info->ct;
    269	struct nf_conn_help *help;
    270
    271	if (ct) {
    272		help = nfct_help(ct);
    273		if (help)
    274			nf_conntrack_helper_put(help->helper);
    275
    276		nf_ct_netns_put(par->net, par->family);
    277
    278		nf_ct_destroy_timeout(ct);
    279		nf_ct_put(info->ct);
    280	}
    281}
    282
    283static void xt_ct_tg_destroy_v0(const struct xt_tgdtor_param *par)
    284{
    285	struct xt_ct_target_info *info = par->targinfo;
    286	struct xt_ct_target_info_v1 info_v1 = {
    287		.flags 		= info->flags,
    288		.zone		= info->zone,
    289		.ct_events	= info->ct_events,
    290		.exp_events	= info->exp_events,
    291		.ct		= info->ct,
    292	};
    293	memcpy(info_v1.helper, info->helper, sizeof(info->helper));
    294
    295	xt_ct_tg_destroy(par, &info_v1);
    296}
    297
    298static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par)
    299{
    300	xt_ct_tg_destroy(par, par->targinfo);
    301}
    302
    303static struct xt_target xt_ct_tg_reg[] __read_mostly = {
    304	{
    305		.name		= "CT",
    306		.family		= NFPROTO_UNSPEC,
    307		.targetsize	= sizeof(struct xt_ct_target_info),
    308		.usersize	= offsetof(struct xt_ct_target_info, ct),
    309		.checkentry	= xt_ct_tg_check_v0,
    310		.destroy	= xt_ct_tg_destroy_v0,
    311		.target		= xt_ct_target_v0,
    312		.table		= "raw",
    313		.me		= THIS_MODULE,
    314	},
    315	{
    316		.name		= "CT",
    317		.family		= NFPROTO_UNSPEC,
    318		.revision	= 1,
    319		.targetsize	= sizeof(struct xt_ct_target_info_v1),
    320		.usersize	= offsetof(struct xt_ct_target_info, ct),
    321		.checkentry	= xt_ct_tg_check_v1,
    322		.destroy	= xt_ct_tg_destroy_v1,
    323		.target		= xt_ct_target_v1,
    324		.table		= "raw",
    325		.me		= THIS_MODULE,
    326	},
    327	{
    328		.name		= "CT",
    329		.family		= NFPROTO_UNSPEC,
    330		.revision	= 2,
    331		.targetsize	= sizeof(struct xt_ct_target_info_v1),
    332		.usersize	= offsetof(struct xt_ct_target_info, ct),
    333		.checkentry	= xt_ct_tg_check_v2,
    334		.destroy	= xt_ct_tg_destroy_v1,
    335		.target		= xt_ct_target_v1,
    336		.table		= "raw",
    337		.me		= THIS_MODULE,
    338	},
    339};
    340
    341static unsigned int
    342notrack_tg(struct sk_buff *skb, const struct xt_action_param *par)
    343{
    344	/* Previously seen (loopback)? Ignore. */
    345	if (skb->_nfct != 0)
    346		return XT_CONTINUE;
    347
    348	nf_ct_set(skb, NULL, IP_CT_UNTRACKED);
    349
    350	return XT_CONTINUE;
    351}
    352
    353static struct xt_target notrack_tg_reg __read_mostly = {
    354	.name		= "NOTRACK",
    355	.revision	= 0,
    356	.family		= NFPROTO_UNSPEC,
    357	.target		= notrack_tg,
    358	.table		= "raw",
    359	.me		= THIS_MODULE,
    360};
    361
    362static int __init xt_ct_tg_init(void)
    363{
    364	int ret;
    365
    366	ret = xt_register_target(&notrack_tg_reg);
    367	if (ret < 0)
    368		return ret;
    369
    370	ret = xt_register_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg));
    371	if (ret < 0) {
    372		xt_unregister_target(&notrack_tg_reg);
    373		return ret;
    374	}
    375	return 0;
    376}
    377
    378static void __exit xt_ct_tg_exit(void)
    379{
    380	xt_unregister_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg));
    381	xt_unregister_target(&notrack_tg_reg);
    382}
    383
    384module_init(xt_ct_tg_init);
    385module_exit(xt_ct_tg_exit);
    386
    387MODULE_LICENSE("GPL");
    388MODULE_DESCRIPTION("Xtables: connection tracking target");
    389MODULE_ALIAS("ipt_CT");
    390MODULE_ALIAS("ip6t_CT");
    391MODULE_ALIAS("ipt_NOTRACK");
    392MODULE_ALIAS("ip6t_NOTRACK");