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_immediate.c (6166B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
      4 *
      5 * Development of this code funded by Astaro AG (http://www.astaro.com/)
      6 */
      7
      8#include <linux/kernel.h>
      9#include <linux/init.h>
     10#include <linux/module.h>
     11#include <linux/netlink.h>
     12#include <linux/netfilter.h>
     13#include <linux/netfilter/nf_tables.h>
     14#include <net/netfilter/nf_tables_core.h>
     15#include <net/netfilter/nf_tables.h>
     16#include <net/netfilter/nf_tables_offload.h>
     17
     18void nft_immediate_eval(const struct nft_expr *expr,
     19			struct nft_regs *regs,
     20			const struct nft_pktinfo *pkt)
     21{
     22	const struct nft_immediate_expr *priv = nft_expr_priv(expr);
     23
     24	nft_data_copy(&regs->data[priv->dreg], &priv->data, priv->dlen);
     25}
     26
     27static const struct nla_policy nft_immediate_policy[NFTA_IMMEDIATE_MAX + 1] = {
     28	[NFTA_IMMEDIATE_DREG]	= { .type = NLA_U32 },
     29	[NFTA_IMMEDIATE_DATA]	= { .type = NLA_NESTED },
     30};
     31
     32static int nft_immediate_init(const struct nft_ctx *ctx,
     33			      const struct nft_expr *expr,
     34			      const struct nlattr * const tb[])
     35{
     36	struct nft_immediate_expr *priv = nft_expr_priv(expr);
     37	struct nft_data_desc desc;
     38	int err;
     39
     40	if (tb[NFTA_IMMEDIATE_DREG] == NULL ||
     41	    tb[NFTA_IMMEDIATE_DATA] == NULL)
     42		return -EINVAL;
     43
     44	err = nft_data_init(ctx, &priv->data, sizeof(priv->data), &desc,
     45			    tb[NFTA_IMMEDIATE_DATA]);
     46	if (err < 0)
     47		return err;
     48
     49	priv->dlen = desc.len;
     50
     51	err = nft_parse_register_store(ctx, tb[NFTA_IMMEDIATE_DREG],
     52				       &priv->dreg, &priv->data, desc.type,
     53				       desc.len);
     54	if (err < 0)
     55		goto err1;
     56
     57	if (priv->dreg == NFT_REG_VERDICT) {
     58		struct nft_chain *chain = priv->data.verdict.chain;
     59
     60		switch (priv->data.verdict.code) {
     61		case NFT_JUMP:
     62		case NFT_GOTO:
     63			if (nft_chain_is_bound(chain)) {
     64				err = -EBUSY;
     65				goto err1;
     66			}
     67			chain->bound = true;
     68			break;
     69		default:
     70			break;
     71		}
     72	}
     73
     74	return 0;
     75
     76err1:
     77	nft_data_release(&priv->data, desc.type);
     78	return err;
     79}
     80
     81static void nft_immediate_activate(const struct nft_ctx *ctx,
     82				   const struct nft_expr *expr)
     83{
     84	const struct nft_immediate_expr *priv = nft_expr_priv(expr);
     85
     86	return nft_data_hold(&priv->data, nft_dreg_to_type(priv->dreg));
     87}
     88
     89static void nft_immediate_deactivate(const struct nft_ctx *ctx,
     90				     const struct nft_expr *expr,
     91				     enum nft_trans_phase phase)
     92{
     93	const struct nft_immediate_expr *priv = nft_expr_priv(expr);
     94
     95	if (phase == NFT_TRANS_COMMIT)
     96		return;
     97
     98	return nft_data_release(&priv->data, nft_dreg_to_type(priv->dreg));
     99}
    100
    101static void nft_immediate_destroy(const struct nft_ctx *ctx,
    102				  const struct nft_expr *expr)
    103{
    104	const struct nft_immediate_expr *priv = nft_expr_priv(expr);
    105	const struct nft_data *data = &priv->data;
    106	struct nft_rule *rule, *n;
    107	struct nft_ctx chain_ctx;
    108	struct nft_chain *chain;
    109
    110	if (priv->dreg != NFT_REG_VERDICT)
    111		return;
    112
    113	switch (data->verdict.code) {
    114	case NFT_JUMP:
    115	case NFT_GOTO:
    116		chain = data->verdict.chain;
    117
    118		if (!nft_chain_is_bound(chain))
    119			break;
    120
    121		chain_ctx = *ctx;
    122		chain_ctx.chain = chain;
    123
    124		list_for_each_entry_safe(rule, n, &chain->rules, list)
    125			nf_tables_rule_release(&chain_ctx, rule);
    126
    127		nf_tables_chain_destroy(&chain_ctx);
    128		break;
    129	default:
    130		break;
    131	}
    132}
    133
    134static int nft_immediate_dump(struct sk_buff *skb, const struct nft_expr *expr)
    135{
    136	const struct nft_immediate_expr *priv = nft_expr_priv(expr);
    137
    138	if (nft_dump_register(skb, NFTA_IMMEDIATE_DREG, priv->dreg))
    139		goto nla_put_failure;
    140
    141	return nft_data_dump(skb, NFTA_IMMEDIATE_DATA, &priv->data,
    142			     nft_dreg_to_type(priv->dreg), priv->dlen);
    143
    144nla_put_failure:
    145	return -1;
    146}
    147
    148static int nft_immediate_validate(const struct nft_ctx *ctx,
    149				  const struct nft_expr *expr,
    150				  const struct nft_data **d)
    151{
    152	const struct nft_immediate_expr *priv = nft_expr_priv(expr);
    153	struct nft_ctx *pctx = (struct nft_ctx *)ctx;
    154	const struct nft_data *data;
    155	int err;
    156
    157	if (priv->dreg != NFT_REG_VERDICT)
    158		return 0;
    159
    160	data = &priv->data;
    161
    162	switch (data->verdict.code) {
    163	case NFT_JUMP:
    164	case NFT_GOTO:
    165		pctx->level++;
    166		err = nft_chain_validate(ctx, data->verdict.chain);
    167		if (err < 0)
    168			return err;
    169		pctx->level--;
    170		break;
    171	default:
    172		break;
    173	}
    174
    175	return 0;
    176}
    177
    178static int nft_immediate_offload_verdict(struct nft_offload_ctx *ctx,
    179					 struct nft_flow_rule *flow,
    180					 const struct nft_immediate_expr *priv)
    181{
    182	struct flow_action_entry *entry;
    183	const struct nft_data *data;
    184
    185	entry = &flow->rule->action.entries[ctx->num_actions++];
    186
    187	data = &priv->data;
    188	switch (data->verdict.code) {
    189	case NF_ACCEPT:
    190		entry->id = FLOW_ACTION_ACCEPT;
    191		break;
    192	case NF_DROP:
    193		entry->id = FLOW_ACTION_DROP;
    194		break;
    195	default:
    196		return -EOPNOTSUPP;
    197	}
    198
    199	return 0;
    200}
    201
    202static int nft_immediate_offload(struct nft_offload_ctx *ctx,
    203				 struct nft_flow_rule *flow,
    204				 const struct nft_expr *expr)
    205{
    206	const struct nft_immediate_expr *priv = nft_expr_priv(expr);
    207
    208	if (priv->dreg == NFT_REG_VERDICT)
    209		return nft_immediate_offload_verdict(ctx, flow, priv);
    210
    211	memcpy(&ctx->regs[priv->dreg].data, &priv->data, sizeof(priv->data));
    212
    213	return 0;
    214}
    215
    216static bool nft_immediate_offload_action(const struct nft_expr *expr)
    217{
    218	const struct nft_immediate_expr *priv = nft_expr_priv(expr);
    219
    220	if (priv->dreg == NFT_REG_VERDICT)
    221		return true;
    222
    223	return false;
    224}
    225
    226static bool nft_immediate_reduce(struct nft_regs_track *track,
    227				 const struct nft_expr *expr)
    228{
    229	const struct nft_immediate_expr *priv = nft_expr_priv(expr);
    230
    231	if (priv->dreg != NFT_REG_VERDICT)
    232		nft_reg_track_cancel(track, priv->dreg, priv->dlen);
    233
    234	return false;
    235}
    236
    237static const struct nft_expr_ops nft_imm_ops = {
    238	.type		= &nft_imm_type,
    239	.size		= NFT_EXPR_SIZE(sizeof(struct nft_immediate_expr)),
    240	.eval		= nft_immediate_eval,
    241	.init		= nft_immediate_init,
    242	.activate	= nft_immediate_activate,
    243	.deactivate	= nft_immediate_deactivate,
    244	.destroy	= nft_immediate_destroy,
    245	.dump		= nft_immediate_dump,
    246	.validate	= nft_immediate_validate,
    247	.reduce		= nft_immediate_reduce,
    248	.offload	= nft_immediate_offload,
    249	.offload_action	= nft_immediate_offload_action,
    250};
    251
    252struct nft_expr_type nft_imm_type __read_mostly = {
    253	.name		= "immediate",
    254	.ops		= &nft_imm_ops,
    255	.policy		= nft_immediate_policy,
    256	.maxattr	= NFTA_IMMEDIATE_MAX,
    257	.owner		= THIS_MODULE,
    258};