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

strfilter.c (6409B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include "string2.h"
      3#include "strfilter.h"
      4
      5#include <errno.h>
      6#include <stdlib.h>
      7#include <linux/ctype.h>
      8#include <linux/string.h>
      9#include <linux/zalloc.h>
     10
     11/* Operators */
     12static const char *OP_and	= "&";	/* Logical AND */
     13static const char *OP_or	= "|";	/* Logical OR */
     14static const char *OP_not	= "!";	/* Logical NOT */
     15
     16#define is_operator(c)	((c) == '|' || (c) == '&' || (c) == '!')
     17#define is_separator(c)	(is_operator(c) || (c) == '(' || (c) == ')')
     18
     19static void strfilter_node__delete(struct strfilter_node *node)
     20{
     21	if (node) {
     22		if (node->p && !is_operator(*node->p))
     23			zfree((char **)&node->p);
     24		strfilter_node__delete(node->l);
     25		strfilter_node__delete(node->r);
     26		free(node);
     27	}
     28}
     29
     30void strfilter__delete(struct strfilter *filter)
     31{
     32	if (filter) {
     33		strfilter_node__delete(filter->root);
     34		free(filter);
     35	}
     36}
     37
     38static const char *get_token(const char *s, const char **e)
     39{
     40	const char *p;
     41
     42	s = skip_spaces(s);
     43
     44	if (*s == '\0') {
     45		p = s;
     46		goto end;
     47	}
     48
     49	p = s + 1;
     50	if (!is_separator(*s)) {
     51		/* End search */
     52retry:
     53		while (*p && !is_separator(*p) && !isspace(*p))
     54			p++;
     55		/* Escape and special case: '!' is also used in glob pattern */
     56		if (*(p - 1) == '\\' || (*p == '!' && *(p - 1) == '[')) {
     57			p++;
     58			goto retry;
     59		}
     60	}
     61end:
     62	*e = p;
     63	return s;
     64}
     65
     66static struct strfilter_node *strfilter_node__alloc(const char *op,
     67						    struct strfilter_node *l,
     68						    struct strfilter_node *r)
     69{
     70	struct strfilter_node *node = zalloc(sizeof(*node));
     71
     72	if (node) {
     73		node->p = op;
     74		node->l = l;
     75		node->r = r;
     76	}
     77
     78	return node;
     79}
     80
     81static struct strfilter_node *strfilter_node__new(const char *s,
     82						  const char **ep)
     83{
     84	struct strfilter_node root, *cur, *last_op;
     85	const char *e;
     86
     87	if (!s)
     88		return NULL;
     89
     90	memset(&root, 0, sizeof(root));
     91	last_op = cur = &root;
     92
     93	s = get_token(s, &e);
     94	while (*s != '\0' && *s != ')') {
     95		switch (*s) {
     96		case '&':	/* Exchg last OP->r with AND */
     97			if (!cur->r || !last_op->r)
     98				goto error;
     99			cur = strfilter_node__alloc(OP_and, last_op->r, NULL);
    100			if (!cur)
    101				goto nomem;
    102			last_op->r = cur;
    103			last_op = cur;
    104			break;
    105		case '|':	/* Exchg the root with OR */
    106			if (!cur->r || !root.r)
    107				goto error;
    108			cur = strfilter_node__alloc(OP_or, root.r, NULL);
    109			if (!cur)
    110				goto nomem;
    111			root.r = cur;
    112			last_op = cur;
    113			break;
    114		case '!':	/* Add NOT as a leaf node */
    115			if (cur->r)
    116				goto error;
    117			cur->r = strfilter_node__alloc(OP_not, NULL, NULL);
    118			if (!cur->r)
    119				goto nomem;
    120			cur = cur->r;
    121			break;
    122		case '(':	/* Recursively parses inside the parenthesis */
    123			if (cur->r)
    124				goto error;
    125			cur->r = strfilter_node__new(s + 1, &s);
    126			if (!s)
    127				goto nomem;
    128			if (!cur->r || *s != ')')
    129				goto error;
    130			e = s + 1;
    131			break;
    132		default:
    133			if (cur->r)
    134				goto error;
    135			cur->r = strfilter_node__alloc(NULL, NULL, NULL);
    136			if (!cur->r)
    137				goto nomem;
    138			cur->r->p = strndup(s, e - s);
    139			if (!cur->r->p)
    140				goto nomem;
    141		}
    142		s = get_token(e, &e);
    143	}
    144	if (!cur->r)
    145		goto error;
    146	*ep = s;
    147	return root.r;
    148nomem:
    149	s = NULL;
    150error:
    151	*ep = s;
    152	strfilter_node__delete(root.r);
    153	return NULL;
    154}
    155
    156/*
    157 * Parse filter rule and return new strfilter.
    158 * Return NULL if fail, and *ep == NULL if memory allocation failed.
    159 */
    160struct strfilter *strfilter__new(const char *rules, const char **err)
    161{
    162	struct strfilter *filter = zalloc(sizeof(*filter));
    163	const char *ep = NULL;
    164
    165	if (filter)
    166		filter->root = strfilter_node__new(rules, &ep);
    167
    168	if (!filter || !filter->root || *ep != '\0') {
    169		if (err)
    170			*err = ep;
    171		strfilter__delete(filter);
    172		filter = NULL;
    173	}
    174
    175	return filter;
    176}
    177
    178static int strfilter__append(struct strfilter *filter, bool _or,
    179			     const char *rules, const char **err)
    180{
    181	struct strfilter_node *right, *root;
    182	const char *ep = NULL;
    183
    184	if (!filter || !rules)
    185		return -EINVAL;
    186
    187	right = strfilter_node__new(rules, &ep);
    188	if (!right || *ep != '\0') {
    189		if (err)
    190			*err = ep;
    191		goto error;
    192	}
    193	root = strfilter_node__alloc(_or ? OP_or : OP_and, filter->root, right);
    194	if (!root) {
    195		ep = NULL;
    196		goto error;
    197	}
    198
    199	filter->root = root;
    200	return 0;
    201
    202error:
    203	strfilter_node__delete(right);
    204	return ep ? -EINVAL : -ENOMEM;
    205}
    206
    207int strfilter__or(struct strfilter *filter, const char *rules, const char **err)
    208{
    209	return strfilter__append(filter, true, rules, err);
    210}
    211
    212int strfilter__and(struct strfilter *filter, const char *rules,
    213		   const char **err)
    214{
    215	return strfilter__append(filter, false, rules, err);
    216}
    217
    218static bool strfilter_node__compare(struct strfilter_node *node,
    219				    const char *str)
    220{
    221	if (!node || !node->p)
    222		return false;
    223
    224	switch (*node->p) {
    225	case '|':	/* OR */
    226		return strfilter_node__compare(node->l, str) ||
    227			strfilter_node__compare(node->r, str);
    228	case '&':	/* AND */
    229		return strfilter_node__compare(node->l, str) &&
    230			strfilter_node__compare(node->r, str);
    231	case '!':	/* NOT */
    232		return !strfilter_node__compare(node->r, str);
    233	default:
    234		return strglobmatch(str, node->p);
    235	}
    236}
    237
    238/* Return true if STR matches the filter rules */
    239bool strfilter__compare(struct strfilter *filter, const char *str)
    240{
    241	if (!filter)
    242		return false;
    243	return strfilter_node__compare(filter->root, str);
    244}
    245
    246static int strfilter_node__sprint(struct strfilter_node *node, char *buf);
    247
    248/* sprint node in parenthesis if needed */
    249static int strfilter_node__sprint_pt(struct strfilter_node *node, char *buf)
    250{
    251	int len;
    252	int pt = node->r ? 2 : 0;	/* don't need to check node->l */
    253
    254	if (buf && pt)
    255		*buf++ = '(';
    256	len = strfilter_node__sprint(node, buf);
    257	if (len < 0)
    258		return len;
    259	if (buf && pt)
    260		*(buf + len) = ')';
    261	return len + pt;
    262}
    263
    264static int strfilter_node__sprint(struct strfilter_node *node, char *buf)
    265{
    266	int len = 0, rlen;
    267
    268	if (!node || !node->p)
    269		return -EINVAL;
    270
    271	switch (*node->p) {
    272	case '|':
    273	case '&':
    274		len = strfilter_node__sprint_pt(node->l, buf);
    275		if (len < 0)
    276			return len;
    277		__fallthrough;
    278	case '!':
    279		if (buf) {
    280			*(buf + len++) = *node->p;
    281			buf += len;
    282		} else
    283			len++;
    284		rlen = strfilter_node__sprint_pt(node->r, buf);
    285		if (rlen < 0)
    286			return rlen;
    287		len += rlen;
    288		break;
    289	default:
    290		len = strlen(node->p);
    291		if (buf)
    292			strcpy(buf, node->p);
    293	}
    294
    295	return len;
    296}
    297
    298char *strfilter__string(struct strfilter *filter)
    299{
    300	int len;
    301	char *ret = NULL;
    302
    303	len = strfilter_node__sprint(filter->root, NULL);
    304	if (len < 0)
    305		return NULL;
    306
    307	ret = malloc(len + 1);
    308	if (ret)
    309		strfilter_node__sprint(filter->root, ret);
    310
    311	return ret;
    312}