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

nft_range.c (3666B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (c) 2016 Pablo Neira Ayuso <pablo@netfilter.org>
      4 */
      5
      6#include <linux/kernel.h>
      7#include <linux/init.h>
      8#include <linux/module.h>
      9#include <linux/netlink.h>
     10#include <linux/netfilter.h>
     11#include <linux/netfilter/nf_tables.h>
     12#include <net/netfilter/nf_tables_core.h>
     13#include <net/netfilter/nf_tables.h>
     14
     15struct nft_range_expr {
     16	struct nft_data		data_from;
     17	struct nft_data		data_to;
     18	u8			sreg;
     19	u8			len;
     20	enum nft_range_ops	op:8;
     21};
     22
     23void nft_range_eval(const struct nft_expr *expr,
     24		    struct nft_regs *regs, const struct nft_pktinfo *pkt)
     25{
     26	const struct nft_range_expr *priv = nft_expr_priv(expr);
     27	int d1, d2;
     28
     29	d1 = memcmp(&regs->data[priv->sreg], &priv->data_from, priv->len);
     30	d2 = memcmp(&regs->data[priv->sreg], &priv->data_to, priv->len);
     31	switch (priv->op) {
     32	case NFT_RANGE_EQ:
     33		if (d1 < 0 || d2 > 0)
     34			regs->verdict.code = NFT_BREAK;
     35		break;
     36	case NFT_RANGE_NEQ:
     37		if (d1 >= 0 && d2 <= 0)
     38			regs->verdict.code = NFT_BREAK;
     39		break;
     40	}
     41}
     42
     43static const struct nla_policy nft_range_policy[NFTA_RANGE_MAX + 1] = {
     44	[NFTA_RANGE_SREG]		= { .type = NLA_U32 },
     45	[NFTA_RANGE_OP]			= { .type = NLA_U32 },
     46	[NFTA_RANGE_FROM_DATA]		= { .type = NLA_NESTED },
     47	[NFTA_RANGE_TO_DATA]		= { .type = NLA_NESTED },
     48};
     49
     50static int nft_range_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
     51			const struct nlattr * const tb[])
     52{
     53	struct nft_range_expr *priv = nft_expr_priv(expr);
     54	struct nft_data_desc desc_from, desc_to;
     55	int err;
     56	u32 op;
     57
     58	if (!tb[NFTA_RANGE_SREG]      ||
     59	    !tb[NFTA_RANGE_OP]	      ||
     60	    !tb[NFTA_RANGE_FROM_DATA] ||
     61	    !tb[NFTA_RANGE_TO_DATA])
     62		return -EINVAL;
     63
     64	err = nft_data_init(NULL, &priv->data_from, sizeof(priv->data_from),
     65			    &desc_from, tb[NFTA_RANGE_FROM_DATA]);
     66	if (err < 0)
     67		return err;
     68
     69	if (desc_from.type != NFT_DATA_VALUE) {
     70		err = -EINVAL;
     71		goto err1;
     72	}
     73
     74	err = nft_data_init(NULL, &priv->data_to, sizeof(priv->data_to),
     75			    &desc_to, tb[NFTA_RANGE_TO_DATA]);
     76	if (err < 0)
     77		goto err1;
     78
     79	if (desc_to.type != NFT_DATA_VALUE) {
     80		err = -EINVAL;
     81		goto err2;
     82	}
     83
     84	if (desc_from.len != desc_to.len) {
     85		err = -EINVAL;
     86		goto err2;
     87	}
     88
     89	err = nft_parse_register_load(tb[NFTA_RANGE_SREG], &priv->sreg,
     90				      desc_from.len);
     91	if (err < 0)
     92		goto err2;
     93
     94	err = nft_parse_u32_check(tb[NFTA_RANGE_OP], U8_MAX, &op);
     95	if (err < 0)
     96		goto err2;
     97
     98	switch (op) {
     99	case NFT_RANGE_EQ:
    100	case NFT_RANGE_NEQ:
    101		break;
    102	default:
    103		err = -EINVAL;
    104		goto err2;
    105	}
    106
    107	priv->op  = op;
    108	priv->len = desc_from.len;
    109	return 0;
    110err2:
    111	nft_data_release(&priv->data_to, desc_to.type);
    112err1:
    113	nft_data_release(&priv->data_from, desc_from.type);
    114	return err;
    115}
    116
    117static int nft_range_dump(struct sk_buff *skb, const struct nft_expr *expr)
    118{
    119	const struct nft_range_expr *priv = nft_expr_priv(expr);
    120
    121	if (nft_dump_register(skb, NFTA_RANGE_SREG, priv->sreg))
    122		goto nla_put_failure;
    123	if (nla_put_be32(skb, NFTA_RANGE_OP, htonl(priv->op)))
    124		goto nla_put_failure;
    125
    126	if (nft_data_dump(skb, NFTA_RANGE_FROM_DATA, &priv->data_from,
    127			  NFT_DATA_VALUE, priv->len) < 0 ||
    128	    nft_data_dump(skb, NFTA_RANGE_TO_DATA, &priv->data_to,
    129			  NFT_DATA_VALUE, priv->len) < 0)
    130		goto nla_put_failure;
    131	return 0;
    132
    133nla_put_failure:
    134	return -1;
    135}
    136
    137static const struct nft_expr_ops nft_range_ops = {
    138	.type		= &nft_range_type,
    139	.size		= NFT_EXPR_SIZE(sizeof(struct nft_range_expr)),
    140	.eval		= nft_range_eval,
    141	.init		= nft_range_init,
    142	.dump		= nft_range_dump,
    143	.reduce		= NFT_REDUCE_READONLY,
    144};
    145
    146struct nft_expr_type nft_range_type __read_mostly = {
    147	.name		= "range",
    148	.ops		= &nft_range_ops,
    149	.policy		= nft_range_policy,
    150	.maxattr	= NFTA_RANGE_MAX,
    151	.owner		= THIS_MODULE,
    152};