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

ematch.c (14829B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * net/sched/ematch.c		Extended Match API
      4 *
      5 * Authors:	Thomas Graf <tgraf@suug.ch>
      6 *
      7 * ==========================================================================
      8 *
      9 * An extended match (ematch) is a small classification tool not worth
     10 * writing a full classifier for. Ematches can be interconnected to form
     11 * a logic expression and get attached to classifiers to extend their
     12 * functionatlity.
     13 *
     14 * The userspace part transforms the logic expressions into an array
     15 * consisting of multiple sequences of interconnected ematches separated
     16 * by markers. Precedence is implemented by a special ematch kind
     17 * referencing a sequence beyond the marker of the current sequence
     18 * causing the current position in the sequence to be pushed onto a stack
     19 * to allow the current position to be overwritten by the position referenced
     20 * in the special ematch. Matching continues in the new sequence until a
     21 * marker is reached causing the position to be restored from the stack.
     22 *
     23 * Example:
     24 *          A AND (B1 OR B2) AND C AND D
     25 *
     26 *              ------->-PUSH-------
     27 *    -->--    /         -->--      \   -->--
     28 *   /     \  /         /     \      \ /     \
     29 * +-------+-------+-------+-------+-------+--------+
     30 * | A AND | B AND | C AND | D END | B1 OR | B2 END |
     31 * +-------+-------+-------+-------+-------+--------+
     32 *                    \                      /
     33 *                     --------<-POP---------
     34 *
     35 * where B is a virtual ematch referencing to sequence starting with B1.
     36 *
     37 * ==========================================================================
     38 *
     39 * How to write an ematch in 60 seconds
     40 * ------------------------------------
     41 *
     42 *   1) Provide a matcher function:
     43 *      static int my_match(struct sk_buff *skb, struct tcf_ematch *m,
     44 *                          struct tcf_pkt_info *info)
     45 *      {
     46 *      	struct mydata *d = (struct mydata *) m->data;
     47 *
     48 *      	if (...matching goes here...)
     49 *      		return 1;
     50 *      	else
     51 *      		return 0;
     52 *      }
     53 *
     54 *   2) Fill out a struct tcf_ematch_ops:
     55 *      static struct tcf_ematch_ops my_ops = {
     56 *      	.kind = unique id,
     57 *      	.datalen = sizeof(struct mydata),
     58 *      	.match = my_match,
     59 *      	.owner = THIS_MODULE,
     60 *      };
     61 *
     62 *   3) Register/Unregister your ematch:
     63 *      static int __init init_my_ematch(void)
     64 *      {
     65 *      	return tcf_em_register(&my_ops);
     66 *      }
     67 *
     68 *      static void __exit exit_my_ematch(void)
     69 *      {
     70 *      	tcf_em_unregister(&my_ops);
     71 *      }
     72 *
     73 *      module_init(init_my_ematch);
     74 *      module_exit(exit_my_ematch);
     75 *
     76 *   4) By now you should have two more seconds left, barely enough to
     77 *      open up a beer to watch the compilation going.
     78 */
     79
     80#include <linux/module.h>
     81#include <linux/slab.h>
     82#include <linux/types.h>
     83#include <linux/kernel.h>
     84#include <linux/errno.h>
     85#include <linux/rtnetlink.h>
     86#include <linux/skbuff.h>
     87#include <net/pkt_cls.h>
     88
     89static LIST_HEAD(ematch_ops);
     90static DEFINE_RWLOCK(ematch_mod_lock);
     91
     92static struct tcf_ematch_ops *tcf_em_lookup(u16 kind)
     93{
     94	struct tcf_ematch_ops *e = NULL;
     95
     96	read_lock(&ematch_mod_lock);
     97	list_for_each_entry(e, &ematch_ops, link) {
     98		if (kind == e->kind) {
     99			if (!try_module_get(e->owner))
    100				e = NULL;
    101			read_unlock(&ematch_mod_lock);
    102			return e;
    103		}
    104	}
    105	read_unlock(&ematch_mod_lock);
    106
    107	return NULL;
    108}
    109
    110/**
    111 * tcf_em_register - register an extended match
    112 *
    113 * @ops: ematch operations lookup table
    114 *
    115 * This function must be called by ematches to announce their presence.
    116 * The given @ops must have kind set to a unique identifier and the
    117 * callback match() must be implemented. All other callbacks are optional
    118 * and a fallback implementation is used instead.
    119 *
    120 * Returns -EEXISTS if an ematch of the same kind has already registered.
    121 */
    122int tcf_em_register(struct tcf_ematch_ops *ops)
    123{
    124	int err = -EEXIST;
    125	struct tcf_ematch_ops *e;
    126
    127	if (ops->match == NULL)
    128		return -EINVAL;
    129
    130	write_lock(&ematch_mod_lock);
    131	list_for_each_entry(e, &ematch_ops, link)
    132		if (ops->kind == e->kind)
    133			goto errout;
    134
    135	list_add_tail(&ops->link, &ematch_ops);
    136	err = 0;
    137errout:
    138	write_unlock(&ematch_mod_lock);
    139	return err;
    140}
    141EXPORT_SYMBOL(tcf_em_register);
    142
    143/**
    144 * tcf_em_unregister - unregister and extended match
    145 *
    146 * @ops: ematch operations lookup table
    147 *
    148 * This function must be called by ematches to announce their disappearance
    149 * for examples when the module gets unloaded. The @ops parameter must be
    150 * the same as the one used for registration.
    151 *
    152 * Returns -ENOENT if no matching ematch was found.
    153 */
    154void tcf_em_unregister(struct tcf_ematch_ops *ops)
    155{
    156	write_lock(&ematch_mod_lock);
    157	list_del(&ops->link);
    158	write_unlock(&ematch_mod_lock);
    159}
    160EXPORT_SYMBOL(tcf_em_unregister);
    161
    162static inline struct tcf_ematch *tcf_em_get_match(struct tcf_ematch_tree *tree,
    163						  int index)
    164{
    165	return &tree->matches[index];
    166}
    167
    168
    169static int tcf_em_validate(struct tcf_proto *tp,
    170			   struct tcf_ematch_tree_hdr *tree_hdr,
    171			   struct tcf_ematch *em, struct nlattr *nla, int idx)
    172{
    173	int err = -EINVAL;
    174	struct tcf_ematch_hdr *em_hdr = nla_data(nla);
    175	int data_len = nla_len(nla) - sizeof(*em_hdr);
    176	void *data = (void *) em_hdr + sizeof(*em_hdr);
    177	struct net *net = tp->chain->block->net;
    178
    179	if (!TCF_EM_REL_VALID(em_hdr->flags))
    180		goto errout;
    181
    182	if (em_hdr->kind == TCF_EM_CONTAINER) {
    183		/* Special ematch called "container", carries an index
    184		 * referencing an external ematch sequence.
    185		 */
    186		u32 ref;
    187
    188		if (data_len < sizeof(ref))
    189			goto errout;
    190		ref = *(u32 *) data;
    191
    192		if (ref >= tree_hdr->nmatches)
    193			goto errout;
    194
    195		/* We do not allow backward jumps to avoid loops and jumps
    196		 * to our own position are of course illegal.
    197		 */
    198		if (ref <= idx)
    199			goto errout;
    200
    201
    202		em->data = ref;
    203	} else {
    204		/* Note: This lookup will increase the module refcnt
    205		 * of the ematch module referenced. In case of a failure,
    206		 * a destroy function is called by the underlying layer
    207		 * which automatically releases the reference again, therefore
    208		 * the module MUST not be given back under any circumstances
    209		 * here. Be aware, the destroy function assumes that the
    210		 * module is held if the ops field is non zero.
    211		 */
    212		em->ops = tcf_em_lookup(em_hdr->kind);
    213
    214		if (em->ops == NULL) {
    215			err = -ENOENT;
    216#ifdef CONFIG_MODULES
    217			__rtnl_unlock();
    218			request_module("ematch-kind-%u", em_hdr->kind);
    219			rtnl_lock();
    220			em->ops = tcf_em_lookup(em_hdr->kind);
    221			if (em->ops) {
    222				/* We dropped the RTNL mutex in order to
    223				 * perform the module load. Tell the caller
    224				 * to replay the request.
    225				 */
    226				module_put(em->ops->owner);
    227				em->ops = NULL;
    228				err = -EAGAIN;
    229			}
    230#endif
    231			goto errout;
    232		}
    233
    234		/* ematch module provides expected length of data, so we
    235		 * can do a basic sanity check.
    236		 */
    237		if (em->ops->datalen && data_len < em->ops->datalen)
    238			goto errout;
    239
    240		if (em->ops->change) {
    241			err = -EINVAL;
    242			if (em_hdr->flags & TCF_EM_SIMPLE)
    243				goto errout;
    244			err = em->ops->change(net, data, data_len, em);
    245			if (err < 0)
    246				goto errout;
    247		} else if (data_len > 0) {
    248			/* ematch module doesn't provide an own change
    249			 * procedure and expects us to allocate and copy
    250			 * the ematch data.
    251			 *
    252			 * TCF_EM_SIMPLE may be specified stating that the
    253			 * data only consists of a u32 integer and the module
    254			 * does not expected a memory reference but rather
    255			 * the value carried.
    256			 */
    257			if (em_hdr->flags & TCF_EM_SIMPLE) {
    258				if (data_len < sizeof(u32))
    259					goto errout;
    260				em->data = *(u32 *) data;
    261			} else {
    262				void *v = kmemdup(data, data_len, GFP_KERNEL);
    263				if (v == NULL) {
    264					err = -ENOBUFS;
    265					goto errout;
    266				}
    267				em->data = (unsigned long) v;
    268			}
    269			em->datalen = data_len;
    270		}
    271	}
    272
    273	em->matchid = em_hdr->matchid;
    274	em->flags = em_hdr->flags;
    275	em->net = net;
    276
    277	err = 0;
    278errout:
    279	return err;
    280}
    281
    282static const struct nla_policy em_policy[TCA_EMATCH_TREE_MAX + 1] = {
    283	[TCA_EMATCH_TREE_HDR]	= { .len = sizeof(struct tcf_ematch_tree_hdr) },
    284	[TCA_EMATCH_TREE_LIST]	= { .type = NLA_NESTED },
    285};
    286
    287/**
    288 * tcf_em_tree_validate - validate ematch config TLV and build ematch tree
    289 *
    290 * @tp: classifier kind handle
    291 * @nla: ematch tree configuration TLV
    292 * @tree: destination ematch tree variable to store the resulting
    293 *        ematch tree.
    294 *
    295 * This function validates the given configuration TLV @nla and builds an
    296 * ematch tree in @tree. The resulting tree must later be copied into
    297 * the private classifier data using tcf_em_tree_change(). You MUST NOT
    298 * provide the ematch tree variable of the private classifier data directly,
    299 * the changes would not be locked properly.
    300 *
    301 * Returns a negative error code if the configuration TLV contains errors.
    302 */
    303int tcf_em_tree_validate(struct tcf_proto *tp, struct nlattr *nla,
    304			 struct tcf_ematch_tree *tree)
    305{
    306	int idx, list_len, matches_len, err;
    307	struct nlattr *tb[TCA_EMATCH_TREE_MAX + 1];
    308	struct nlattr *rt_match, *rt_hdr, *rt_list;
    309	struct tcf_ematch_tree_hdr *tree_hdr;
    310	struct tcf_ematch *em;
    311
    312	memset(tree, 0, sizeof(*tree));
    313	if (!nla)
    314		return 0;
    315
    316	err = nla_parse_nested_deprecated(tb, TCA_EMATCH_TREE_MAX, nla,
    317					  em_policy, NULL);
    318	if (err < 0)
    319		goto errout;
    320
    321	err = -EINVAL;
    322	rt_hdr = tb[TCA_EMATCH_TREE_HDR];
    323	rt_list = tb[TCA_EMATCH_TREE_LIST];
    324
    325	if (rt_hdr == NULL || rt_list == NULL)
    326		goto errout;
    327
    328	tree_hdr = nla_data(rt_hdr);
    329	memcpy(&tree->hdr, tree_hdr, sizeof(*tree_hdr));
    330
    331	rt_match = nla_data(rt_list);
    332	list_len = nla_len(rt_list);
    333	matches_len = tree_hdr->nmatches * sizeof(*em);
    334
    335	tree->matches = kzalloc(matches_len, GFP_KERNEL);
    336	if (tree->matches == NULL)
    337		goto errout;
    338
    339	/* We do not use nla_parse_nested here because the maximum
    340	 * number of attributes is unknown. This saves us the allocation
    341	 * for a tb buffer which would serve no purpose at all.
    342	 *
    343	 * The array of rt attributes is parsed in the order as they are
    344	 * provided, their type must be incremental from 1 to n. Even
    345	 * if it does not serve any real purpose, a failure of sticking
    346	 * to this policy will result in parsing failure.
    347	 */
    348	for (idx = 0; nla_ok(rt_match, list_len); idx++) {
    349		err = -EINVAL;
    350
    351		if (rt_match->nla_type != (idx + 1))
    352			goto errout_abort;
    353
    354		if (idx >= tree_hdr->nmatches)
    355			goto errout_abort;
    356
    357		if (nla_len(rt_match) < sizeof(struct tcf_ematch_hdr))
    358			goto errout_abort;
    359
    360		em = tcf_em_get_match(tree, idx);
    361
    362		err = tcf_em_validate(tp, tree_hdr, em, rt_match, idx);
    363		if (err < 0)
    364			goto errout_abort;
    365
    366		rt_match = nla_next(rt_match, &list_len);
    367	}
    368
    369	/* Check if the number of matches provided by userspace actually
    370	 * complies with the array of matches. The number was used for
    371	 * the validation of references and a mismatch could lead to
    372	 * undefined references during the matching process.
    373	 */
    374	if (idx != tree_hdr->nmatches) {
    375		err = -EINVAL;
    376		goto errout_abort;
    377	}
    378
    379	err = 0;
    380errout:
    381	return err;
    382
    383errout_abort:
    384	tcf_em_tree_destroy(tree);
    385	return err;
    386}
    387EXPORT_SYMBOL(tcf_em_tree_validate);
    388
    389/**
    390 * tcf_em_tree_destroy - destroy an ematch tree
    391 *
    392 * @tree: ematch tree to be deleted
    393 *
    394 * This functions destroys an ematch tree previously created by
    395 * tcf_em_tree_validate()/tcf_em_tree_change(). You must ensure that
    396 * the ematch tree is not in use before calling this function.
    397 */
    398void tcf_em_tree_destroy(struct tcf_ematch_tree *tree)
    399{
    400	int i;
    401
    402	if (tree->matches == NULL)
    403		return;
    404
    405	for (i = 0; i < tree->hdr.nmatches; i++) {
    406		struct tcf_ematch *em = tcf_em_get_match(tree, i);
    407
    408		if (em->ops) {
    409			if (em->ops->destroy)
    410				em->ops->destroy(em);
    411			else if (!tcf_em_is_simple(em))
    412				kfree((void *) em->data);
    413			module_put(em->ops->owner);
    414		}
    415	}
    416
    417	tree->hdr.nmatches = 0;
    418	kfree(tree->matches);
    419	tree->matches = NULL;
    420}
    421EXPORT_SYMBOL(tcf_em_tree_destroy);
    422
    423/**
    424 * tcf_em_tree_dump - dump ematch tree into a rtnl message
    425 *
    426 * @skb: skb holding the rtnl message
    427 * @tree: ematch tree to be dumped
    428 * @tlv: TLV type to be used to encapsulate the tree
    429 *
    430 * This function dumps a ematch tree into a rtnl message. It is valid to
    431 * call this function while the ematch tree is in use.
    432 *
    433 * Returns -1 if the skb tailroom is insufficient.
    434 */
    435int tcf_em_tree_dump(struct sk_buff *skb, struct tcf_ematch_tree *tree, int tlv)
    436{
    437	int i;
    438	u8 *tail;
    439	struct nlattr *top_start;
    440	struct nlattr *list_start;
    441
    442	top_start = nla_nest_start_noflag(skb, tlv);
    443	if (top_start == NULL)
    444		goto nla_put_failure;
    445
    446	if (nla_put(skb, TCA_EMATCH_TREE_HDR, sizeof(tree->hdr), &tree->hdr))
    447		goto nla_put_failure;
    448
    449	list_start = nla_nest_start_noflag(skb, TCA_EMATCH_TREE_LIST);
    450	if (list_start == NULL)
    451		goto nla_put_failure;
    452
    453	tail = skb_tail_pointer(skb);
    454	for (i = 0; i < tree->hdr.nmatches; i++) {
    455		struct nlattr *match_start = (struct nlattr *)tail;
    456		struct tcf_ematch *em = tcf_em_get_match(tree, i);
    457		struct tcf_ematch_hdr em_hdr = {
    458			.kind = em->ops ? em->ops->kind : TCF_EM_CONTAINER,
    459			.matchid = em->matchid,
    460			.flags = em->flags
    461		};
    462
    463		if (nla_put(skb, i + 1, sizeof(em_hdr), &em_hdr))
    464			goto nla_put_failure;
    465
    466		if (em->ops && em->ops->dump) {
    467			if (em->ops->dump(skb, em) < 0)
    468				goto nla_put_failure;
    469		} else if (tcf_em_is_container(em) || tcf_em_is_simple(em)) {
    470			u32 u = em->data;
    471			nla_put_nohdr(skb, sizeof(u), &u);
    472		} else if (em->datalen > 0)
    473			nla_put_nohdr(skb, em->datalen, (void *) em->data);
    474
    475		tail = skb_tail_pointer(skb);
    476		match_start->nla_len = tail - (u8 *)match_start;
    477	}
    478
    479	nla_nest_end(skb, list_start);
    480	nla_nest_end(skb, top_start);
    481
    482	return 0;
    483
    484nla_put_failure:
    485	return -1;
    486}
    487EXPORT_SYMBOL(tcf_em_tree_dump);
    488
    489static inline int tcf_em_match(struct sk_buff *skb, struct tcf_ematch *em,
    490			       struct tcf_pkt_info *info)
    491{
    492	int r = em->ops->match(skb, em, info);
    493
    494	return tcf_em_is_inverted(em) ? !r : r;
    495}
    496
    497/* Do not use this function directly, use tcf_em_tree_match instead */
    498int __tcf_em_tree_match(struct sk_buff *skb, struct tcf_ematch_tree *tree,
    499			struct tcf_pkt_info *info)
    500{
    501	int stackp = 0, match_idx = 0, res = 0;
    502	struct tcf_ematch *cur_match;
    503	int stack[CONFIG_NET_EMATCH_STACK];
    504
    505proceed:
    506	while (match_idx < tree->hdr.nmatches) {
    507		cur_match = tcf_em_get_match(tree, match_idx);
    508
    509		if (tcf_em_is_container(cur_match)) {
    510			if (unlikely(stackp >= CONFIG_NET_EMATCH_STACK))
    511				goto stack_overflow;
    512
    513			stack[stackp++] = match_idx;
    514			match_idx = cur_match->data;
    515			goto proceed;
    516		}
    517
    518		res = tcf_em_match(skb, cur_match, info);
    519
    520		if (tcf_em_early_end(cur_match, res))
    521			break;
    522
    523		match_idx++;
    524	}
    525
    526pop_stack:
    527	if (stackp > 0) {
    528		match_idx = stack[--stackp];
    529		cur_match = tcf_em_get_match(tree, match_idx);
    530
    531		if (tcf_em_is_inverted(cur_match))
    532			res = !res;
    533
    534		if (tcf_em_early_end(cur_match, res)) {
    535			goto pop_stack;
    536		} else {
    537			match_idx++;
    538			goto proceed;
    539		}
    540	}
    541
    542	return res;
    543
    544stack_overflow:
    545	net_warn_ratelimited("tc ematch: local stack overflow, increase NET_EMATCH_STACK\n");
    546	return -1;
    547}
    548EXPORT_SYMBOL(__tcf_em_tree_match);