Revert "netfilter: nf_tables: prefer nft_chain_validate"
This reverts commit b362800323
.
This commit is contained in:
parent
0bffcfb5ef
commit
ebf3750840
1 changed files with 114 additions and 13 deletions
|
@ -3349,15 +3349,6 @@ static void nf_tables_rule_release(const struct nft_ctx *ctx, struct nft_rule *r
|
||||||
nf_tables_rule_destroy(ctx, rule);
|
nf_tables_rule_destroy(ctx, rule);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** nft_chain_validate - loop detection and hook validation
|
|
||||||
*
|
|
||||||
* @ctx: context containing call depth and base chain
|
|
||||||
* @chain: chain to validate
|
|
||||||
*
|
|
||||||
* Walk through the rules of the given chain and chase all jumps/gotos
|
|
||||||
* and set lookups until either the jump limit is hit or all reachable
|
|
||||||
* chains have been validated.
|
|
||||||
*/
|
|
||||||
int nft_chain_validate(const struct nft_ctx *ctx, const struct nft_chain *chain)
|
int nft_chain_validate(const struct nft_ctx *ctx, const struct nft_chain *chain)
|
||||||
{
|
{
|
||||||
struct nft_expr *expr, *last;
|
struct nft_expr *expr, *last;
|
||||||
|
@ -3376,9 +3367,6 @@ int nft_chain_validate(const struct nft_ctx *ctx, const struct nft_chain *chain)
|
||||||
if (!expr->ops->validate)
|
if (!expr->ops->validate)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* This may call nft_chain_validate() recursively,
|
|
||||||
* callers that do so must increment ctx->level.
|
|
||||||
*/
|
|
||||||
err = expr->ops->validate(ctx, expr, &data);
|
err = expr->ops->validate(ctx, expr, &data);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
@ -9099,6 +9087,119 @@ int nft_chain_validate_hooks(const struct nft_chain *chain,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nft_chain_validate_hooks);
|
EXPORT_SYMBOL_GPL(nft_chain_validate_hooks);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loop detection - walk through the ruleset beginning at the destination chain
|
||||||
|
* of a new jump until either the source chain is reached (loop) or all
|
||||||
|
* reachable chains have been traversed.
|
||||||
|
*
|
||||||
|
* The loop check is performed whenever a new jump verdict is added to an
|
||||||
|
* expression or verdict map or a verdict map is bound to a new chain.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int nf_tables_check_loops(const struct nft_ctx *ctx,
|
||||||
|
const struct nft_chain *chain);
|
||||||
|
|
||||||
|
static int nft_check_loops(const struct nft_ctx *ctx,
|
||||||
|
const struct nft_set_ext *ext)
|
||||||
|
{
|
||||||
|
const struct nft_data *data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
data = nft_set_ext_data(ext);
|
||||||
|
switch (data->verdict.code) {
|
||||||
|
case NFT_JUMP:
|
||||||
|
case NFT_GOTO:
|
||||||
|
ret = nf_tables_check_loops(ctx, data->verdict.chain);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nf_tables_loop_check_setelem(const struct nft_ctx *ctx,
|
||||||
|
struct nft_set *set,
|
||||||
|
const struct nft_set_iter *iter,
|
||||||
|
struct nft_set_elem *elem)
|
||||||
|
{
|
||||||
|
const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
|
||||||
|
|
||||||
|
if (nft_set_ext_exists(ext, NFT_SET_EXT_FLAGS) &&
|
||||||
|
*nft_set_ext_flags(ext) & NFT_SET_ELEM_INTERVAL_END)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return nft_check_loops(ctx, ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nf_tables_check_loops(const struct nft_ctx *ctx,
|
||||||
|
const struct nft_chain *chain)
|
||||||
|
{
|
||||||
|
const struct nft_rule *rule;
|
||||||
|
const struct nft_expr *expr, *last;
|
||||||
|
struct nft_set *set;
|
||||||
|
struct nft_set_binding *binding;
|
||||||
|
struct nft_set_iter iter;
|
||||||
|
|
||||||
|
if (ctx->chain == chain)
|
||||||
|
return -ELOOP;
|
||||||
|
|
||||||
|
list_for_each_entry(rule, &chain->rules, list) {
|
||||||
|
nft_rule_for_each_expr(expr, last, rule) {
|
||||||
|
struct nft_immediate_expr *priv;
|
||||||
|
const struct nft_data *data;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (strcmp(expr->ops->type->name, "immediate"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
priv = nft_expr_priv(expr);
|
||||||
|
if (priv->dreg != NFT_REG_VERDICT)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
data = &priv->data;
|
||||||
|
switch (data->verdict.code) {
|
||||||
|
case NFT_JUMP:
|
||||||
|
case NFT_GOTO:
|
||||||
|
err = nf_tables_check_loops(ctx,
|
||||||
|
data->verdict.chain);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
list_for_each_entry(set, &ctx->table->sets, list) {
|
||||||
|
if (!nft_is_active_next(ctx->net, set))
|
||||||
|
continue;
|
||||||
|
if (!(set->flags & NFT_SET_MAP) ||
|
||||||
|
set->dtype != NFT_DATA_VERDICT)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
list_for_each_entry(binding, &set->bindings, list) {
|
||||||
|
if (!(binding->flags & NFT_SET_MAP) ||
|
||||||
|
binding->chain != chain)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
iter.genmask = nft_genmask_next(ctx->net);
|
||||||
|
iter.skip = 0;
|
||||||
|
iter.count = 0;
|
||||||
|
iter.err = 0;
|
||||||
|
iter.fn = nf_tables_loop_check_setelem;
|
||||||
|
|
||||||
|
set->ops->walk(ctx, set, &iter);
|
||||||
|
if (iter.err < 0)
|
||||||
|
return iter.err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nft_parse_u32_check - fetch u32 attribute and check for maximum value
|
* nft_parse_u32_check - fetch u32 attribute and check for maximum value
|
||||||
*
|
*
|
||||||
|
@ -9234,7 +9335,7 @@ static int nft_validate_register_store(const struct nft_ctx *ctx,
|
||||||
if (data != NULL &&
|
if (data != NULL &&
|
||||||
(data->verdict.code == NFT_GOTO ||
|
(data->verdict.code == NFT_GOTO ||
|
||||||
data->verdict.code == NFT_JUMP)) {
|
data->verdict.code == NFT_JUMP)) {
|
||||||
err = nft_chain_validate(ctx, data->verdict.chain);
|
err = nf_tables_check_loops(ctx, data->verdict.chain);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue