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

em_ipt.c (6875B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * net/sched/em_ipt.c IPtables matches Ematch
      4 *
      5 * (c) 2018 Eyal Birger <eyal.birger@gmail.com>
      6 */
      7
      8#include <linux/gfp.h>
      9#include <linux/module.h>
     10#include <linux/types.h>
     11#include <linux/kernel.h>
     12#include <linux/string.h>
     13#include <linux/skbuff.h>
     14#include <linux/tc_ematch/tc_em_ipt.h>
     15#include <linux/netfilter.h>
     16#include <linux/netfilter/x_tables.h>
     17#include <linux/netfilter_ipv4/ip_tables.h>
     18#include <linux/netfilter_ipv6/ip6_tables.h>
     19#include <net/pkt_cls.h>
     20
     21struct em_ipt_match {
     22	const struct xt_match *match;
     23	u32 hook;
     24	u8 nfproto;
     25	u8 match_data[] __aligned(8);
     26};
     27
     28struct em_ipt_xt_match {
     29	char *match_name;
     30	int (*validate_match_data)(struct nlattr **tb, u8 mrev);
     31};
     32
     33static const struct nla_policy em_ipt_policy[TCA_EM_IPT_MAX + 1] = {
     34	[TCA_EM_IPT_MATCH_NAME]		= { .type = NLA_STRING,
     35					    .len = XT_EXTENSION_MAXNAMELEN },
     36	[TCA_EM_IPT_MATCH_REVISION]	= { .type = NLA_U8 },
     37	[TCA_EM_IPT_HOOK]		= { .type = NLA_U32 },
     38	[TCA_EM_IPT_NFPROTO]		= { .type = NLA_U8 },
     39	[TCA_EM_IPT_MATCH_DATA]		= { .type = NLA_UNSPEC },
     40};
     41
     42static int check_match(struct net *net, struct em_ipt_match *im, int mdata_len)
     43{
     44	struct xt_mtchk_param mtpar = {};
     45	union {
     46		struct ipt_entry e4;
     47		struct ip6t_entry e6;
     48	} e = {};
     49
     50	mtpar.net	= net;
     51	mtpar.table	= "filter";
     52	mtpar.hook_mask	= 1 << im->hook;
     53	mtpar.family	= im->match->family;
     54	mtpar.match	= im->match;
     55	mtpar.entryinfo = &e;
     56	mtpar.matchinfo	= (void *)im->match_data;
     57	return xt_check_match(&mtpar, mdata_len, 0, 0);
     58}
     59
     60static int policy_validate_match_data(struct nlattr **tb, u8 mrev)
     61{
     62	if (mrev != 0) {
     63		pr_err("only policy match revision 0 supported");
     64		return -EINVAL;
     65	}
     66
     67	if (nla_get_u32(tb[TCA_EM_IPT_HOOK]) != NF_INET_PRE_ROUTING) {
     68		pr_err("policy can only be matched on NF_INET_PRE_ROUTING");
     69		return -EINVAL;
     70	}
     71
     72	return 0;
     73}
     74
     75static int addrtype_validate_match_data(struct nlattr **tb, u8 mrev)
     76{
     77	if (mrev != 1) {
     78		pr_err("only addrtype match revision 1 supported");
     79		return -EINVAL;
     80	}
     81
     82	return 0;
     83}
     84
     85static const struct em_ipt_xt_match em_ipt_xt_matches[] = {
     86	{
     87		.match_name = "policy",
     88		.validate_match_data = policy_validate_match_data
     89	},
     90	{
     91		.match_name = "addrtype",
     92		.validate_match_data = addrtype_validate_match_data
     93	},
     94	{}
     95};
     96
     97static struct xt_match *get_xt_match(struct nlattr **tb)
     98{
     99	const struct em_ipt_xt_match *m;
    100	struct nlattr *mname_attr;
    101	u8 nfproto, mrev = 0;
    102	int ret;
    103
    104	mname_attr = tb[TCA_EM_IPT_MATCH_NAME];
    105	for (m = em_ipt_xt_matches; m->match_name; m++) {
    106		if (!nla_strcmp(mname_attr, m->match_name))
    107			break;
    108	}
    109
    110	if (!m->match_name) {
    111		pr_err("Unsupported xt match");
    112		return ERR_PTR(-EINVAL);
    113	}
    114
    115	if (tb[TCA_EM_IPT_MATCH_REVISION])
    116		mrev = nla_get_u8(tb[TCA_EM_IPT_MATCH_REVISION]);
    117
    118	ret = m->validate_match_data(tb, mrev);
    119	if (ret < 0)
    120		return ERR_PTR(ret);
    121
    122	nfproto = nla_get_u8(tb[TCA_EM_IPT_NFPROTO]);
    123	return xt_request_find_match(nfproto, m->match_name, mrev);
    124}
    125
    126static int em_ipt_change(struct net *net, void *data, int data_len,
    127			 struct tcf_ematch *em)
    128{
    129	struct nlattr *tb[TCA_EM_IPT_MAX + 1];
    130	struct em_ipt_match *im = NULL;
    131	struct xt_match *match;
    132	int mdata_len, ret;
    133	u8 nfproto;
    134
    135	ret = nla_parse_deprecated(tb, TCA_EM_IPT_MAX, data, data_len,
    136				   em_ipt_policy, NULL);
    137	if (ret < 0)
    138		return ret;
    139
    140	if (!tb[TCA_EM_IPT_HOOK] || !tb[TCA_EM_IPT_MATCH_NAME] ||
    141	    !tb[TCA_EM_IPT_MATCH_DATA] || !tb[TCA_EM_IPT_NFPROTO])
    142		return -EINVAL;
    143
    144	nfproto = nla_get_u8(tb[TCA_EM_IPT_NFPROTO]);
    145	switch (nfproto) {
    146	case NFPROTO_IPV4:
    147	case NFPROTO_IPV6:
    148		break;
    149	default:
    150		return -EINVAL;
    151	}
    152
    153	match = get_xt_match(tb);
    154	if (IS_ERR(match)) {
    155		pr_err("unable to load match\n");
    156		return PTR_ERR(match);
    157	}
    158
    159	mdata_len = XT_ALIGN(nla_len(tb[TCA_EM_IPT_MATCH_DATA]));
    160	im = kzalloc(sizeof(*im) + mdata_len, GFP_KERNEL);
    161	if (!im) {
    162		ret = -ENOMEM;
    163		goto err;
    164	}
    165
    166	im->match = match;
    167	im->hook = nla_get_u32(tb[TCA_EM_IPT_HOOK]);
    168	im->nfproto = nfproto;
    169	nla_memcpy(im->match_data, tb[TCA_EM_IPT_MATCH_DATA], mdata_len);
    170
    171	ret = check_match(net, im, mdata_len);
    172	if (ret)
    173		goto err;
    174
    175	em->datalen = sizeof(*im) + mdata_len;
    176	em->data = (unsigned long)im;
    177	return 0;
    178
    179err:
    180	kfree(im);
    181	module_put(match->me);
    182	return ret;
    183}
    184
    185static void em_ipt_destroy(struct tcf_ematch *em)
    186{
    187	struct em_ipt_match *im = (void *)em->data;
    188
    189	if (!im)
    190		return;
    191
    192	if (im->match->destroy) {
    193		struct xt_mtdtor_param par = {
    194			.net = em->net,
    195			.match = im->match,
    196			.matchinfo = im->match_data,
    197			.family = im->match->family
    198		};
    199		im->match->destroy(&par);
    200	}
    201	module_put(im->match->me);
    202	kfree(im);
    203}
    204
    205static int em_ipt_match(struct sk_buff *skb, struct tcf_ematch *em,
    206			struct tcf_pkt_info *info)
    207{
    208	const struct em_ipt_match *im = (const void *)em->data;
    209	struct xt_action_param acpar = {};
    210	struct net_device *indev = NULL;
    211	u8 nfproto = im->match->family;
    212	struct nf_hook_state state;
    213	int ret;
    214
    215	switch (skb_protocol(skb, true)) {
    216	case htons(ETH_P_IP):
    217		if (!pskb_network_may_pull(skb, sizeof(struct iphdr)))
    218			return 0;
    219		if (nfproto == NFPROTO_UNSPEC)
    220			nfproto = NFPROTO_IPV4;
    221		break;
    222	case htons(ETH_P_IPV6):
    223		if (!pskb_network_may_pull(skb, sizeof(struct ipv6hdr)))
    224			return 0;
    225		if (nfproto == NFPROTO_UNSPEC)
    226			nfproto = NFPROTO_IPV6;
    227		break;
    228	default:
    229		return 0;
    230	}
    231
    232	rcu_read_lock();
    233
    234	if (skb->skb_iif)
    235		indev = dev_get_by_index_rcu(em->net, skb->skb_iif);
    236
    237	nf_hook_state_init(&state, im->hook, nfproto,
    238			   indev ?: skb->dev, skb->dev, NULL, em->net, NULL);
    239
    240	acpar.match = im->match;
    241	acpar.matchinfo = im->match_data;
    242	acpar.state = &state;
    243
    244	ret = im->match->match(skb, &acpar);
    245
    246	rcu_read_unlock();
    247	return ret;
    248}
    249
    250static int em_ipt_dump(struct sk_buff *skb, struct tcf_ematch *em)
    251{
    252	struct em_ipt_match *im = (void *)em->data;
    253
    254	if (nla_put_string(skb, TCA_EM_IPT_MATCH_NAME, im->match->name) < 0)
    255		return -EMSGSIZE;
    256	if (nla_put_u32(skb, TCA_EM_IPT_HOOK, im->hook) < 0)
    257		return -EMSGSIZE;
    258	if (nla_put_u8(skb, TCA_EM_IPT_MATCH_REVISION, im->match->revision) < 0)
    259		return -EMSGSIZE;
    260	if (nla_put_u8(skb, TCA_EM_IPT_NFPROTO, im->nfproto) < 0)
    261		return -EMSGSIZE;
    262	if (nla_put(skb, TCA_EM_IPT_MATCH_DATA,
    263		    im->match->usersize ?: im->match->matchsize,
    264		    im->match_data) < 0)
    265		return -EMSGSIZE;
    266
    267	return 0;
    268}
    269
    270static struct tcf_ematch_ops em_ipt_ops = {
    271	.kind	  = TCF_EM_IPT,
    272	.change	  = em_ipt_change,
    273	.destroy  = em_ipt_destroy,
    274	.match	  = em_ipt_match,
    275	.dump	  = em_ipt_dump,
    276	.owner	  = THIS_MODULE,
    277	.link	  = LIST_HEAD_INIT(em_ipt_ops.link)
    278};
    279
    280static int __init init_em_ipt(void)
    281{
    282	return tcf_em_register(&em_ipt_ops);
    283}
    284
    285static void __exit exit_em_ipt(void)
    286{
    287	tcf_em_unregister(&em_ipt_ops);
    288}
    289
    290MODULE_LICENSE("GPL");
    291MODULE_AUTHOR("Eyal Birger <eyal.birger@gmail.com>");
    292MODULE_DESCRIPTION("TC extended match for IPtables matches");
    293
    294module_init(init_em_ipt);
    295module_exit(exit_em_ipt);
    296
    297MODULE_ALIAS_TCF_EMATCH(TCF_EM_IPT);