|
@@ -207,6 +207,18 @@ static int nft_delchain(struct nft_ctx *ctx)
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/* either expr ops provide both activate/deactivate, or neither */
|
|
|
|
+static bool nft_expr_check_ops(const struct nft_expr_ops *ops)
|
|
|
|
+{
|
|
|
|
+ if (!ops)
|
|
|
|
+ return true;
|
|
|
|
+
|
|
|
|
+ if (WARN_ON_ONCE((!ops->activate ^ !ops->deactivate)))
|
|
|
|
+ return false;
|
|
|
|
+
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
static void nft_rule_expr_activate(const struct nft_ctx *ctx,
|
|
static void nft_rule_expr_activate(const struct nft_ctx *ctx,
|
|
struct nft_rule *rule)
|
|
struct nft_rule *rule)
|
|
{
|
|
{
|
|
@@ -1907,6 +1919,9 @@ static int nf_tables_delchain(struct net *net, struct sock *nlsk,
|
|
*/
|
|
*/
|
|
int nft_register_expr(struct nft_expr_type *type)
|
|
int nft_register_expr(struct nft_expr_type *type)
|
|
{
|
|
{
|
|
|
|
+ if (!nft_expr_check_ops(type->ops))
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
nfnl_lock(NFNL_SUBSYS_NFTABLES);
|
|
nfnl_lock(NFNL_SUBSYS_NFTABLES);
|
|
if (type->family == NFPROTO_UNSPEC)
|
|
if (type->family == NFPROTO_UNSPEC)
|
|
list_add_tail_rcu(&type->list, &nf_tables_expressions);
|
|
list_add_tail_rcu(&type->list, &nf_tables_expressions);
|
|
@@ -2054,6 +2069,10 @@ static int nf_tables_expr_parse(const struct nft_ctx *ctx,
|
|
err = PTR_ERR(ops);
|
|
err = PTR_ERR(ops);
|
|
goto err1;
|
|
goto err1;
|
|
}
|
|
}
|
|
|
|
+ if (!nft_expr_check_ops(ops)) {
|
|
|
|
+ err = -EINVAL;
|
|
|
|
+ goto err1;
|
|
|
|
+ }
|
|
} else
|
|
} else
|
|
ops = type->ops;
|
|
ops = type->ops;
|
|
|
|
|