Commit e189ae16 authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso

netfilter: nf_tables: add position handle in event notification

Add position handle to allow to identify the rule location from netlink
events. Otherwise, userspace cannot incrementally update a userspace
cache through monitoring events.

Skip handle dump if the rule has been either inserted (at the beginning
of the ruleset) or appended (at the end of the ruleset), the
NLM_F_APPEND netlink flag is sufficient in these two cases.

Handle NLM_F_REPLACE as NLM_F_APPEND since the rule replacement
expansion appends it after the specified rule handle.

Fixes: 96518518 ("netfilter: add nftables")
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 339031ba
...@@ -2866,8 +2866,7 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, struct net *net, ...@@ -2866,8 +2866,7 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, struct net *net,
u32 flags, int family, u32 flags, int family,
const struct nft_table *table, const struct nft_table *table,
const struct nft_chain *chain, const struct nft_chain *chain,
const struct nft_rule *rule, const struct nft_rule *rule, u64 handle)
const struct nft_rule *prule)
{ {
struct nlmsghdr *nlh; struct nlmsghdr *nlh;
const struct nft_expr *expr, *next; const struct nft_expr *expr, *next;
...@@ -2887,9 +2886,8 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, struct net *net, ...@@ -2887,9 +2886,8 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, struct net *net,
NFTA_RULE_PAD)) NFTA_RULE_PAD))
goto nla_put_failure; goto nla_put_failure;
if (event != NFT_MSG_DELRULE && prule) { if (event != NFT_MSG_DELRULE && handle) {
if (nla_put_be64(skb, NFTA_RULE_POSITION, if (nla_put_be64(skb, NFTA_RULE_POSITION, cpu_to_be64(handle),
cpu_to_be64(prule->handle),
NFTA_RULE_PAD)) NFTA_RULE_PAD))
goto nla_put_failure; goto nla_put_failure;
} }
...@@ -2925,7 +2923,10 @@ static void nf_tables_rule_notify(const struct nft_ctx *ctx, ...@@ -2925,7 +2923,10 @@ static void nf_tables_rule_notify(const struct nft_ctx *ctx,
const struct nft_rule *rule, int event) const struct nft_rule *rule, int event)
{ {
struct nftables_pernet *nft_net = nft_pernet(ctx->net); struct nftables_pernet *nft_net = nft_pernet(ctx->net);
const struct nft_rule *prule;
struct sk_buff *skb; struct sk_buff *skb;
u64 handle = 0;
u16 flags = 0;
int err; int err;
if (!ctx->report && if (!ctx->report &&
...@@ -2936,9 +2937,18 @@ static void nf_tables_rule_notify(const struct nft_ctx *ctx, ...@@ -2936,9 +2937,18 @@ static void nf_tables_rule_notify(const struct nft_ctx *ctx,
if (skb == NULL) if (skb == NULL)
goto err; goto err;
if (event == NFT_MSG_NEWRULE &&
!list_is_first(&rule->list, &ctx->chain->rules) &&
!list_is_last(&rule->list, &ctx->chain->rules)) {
prule = list_prev_entry(rule, list);
handle = prule->handle;
}
if (ctx->flags & (NLM_F_APPEND | NLM_F_REPLACE))
flags |= NLM_F_APPEND;
err = nf_tables_fill_rule_info(skb, ctx->net, ctx->portid, ctx->seq, err = nf_tables_fill_rule_info(skb, ctx->net, ctx->portid, ctx->seq,
event, 0, ctx->family, ctx->table, event, flags, ctx->family, ctx->table,
ctx->chain, rule, NULL); ctx->chain, rule, handle);
if (err < 0) { if (err < 0) {
kfree_skb(skb); kfree_skb(skb);
goto err; goto err;
...@@ -2964,6 +2974,7 @@ static int __nf_tables_dump_rules(struct sk_buff *skb, ...@@ -2964,6 +2974,7 @@ static int __nf_tables_dump_rules(struct sk_buff *skb,
struct net *net = sock_net(skb->sk); struct net *net = sock_net(skb->sk);
const struct nft_rule *rule, *prule; const struct nft_rule *rule, *prule;
unsigned int s_idx = cb->args[0]; unsigned int s_idx = cb->args[0];
u64 handle;
prule = NULL; prule = NULL;
list_for_each_entry_rcu(rule, &chain->rules, list) { list_for_each_entry_rcu(rule, &chain->rules, list) {
...@@ -2975,12 +2986,17 @@ static int __nf_tables_dump_rules(struct sk_buff *skb, ...@@ -2975,12 +2986,17 @@ static int __nf_tables_dump_rules(struct sk_buff *skb,
memset(&cb->args[1], 0, memset(&cb->args[1], 0,
sizeof(cb->args) - sizeof(cb->args[0])); sizeof(cb->args) - sizeof(cb->args[0]));
} }
if (prule)
handle = prule->handle;
else
handle = 0;
if (nf_tables_fill_rule_info(skb, net, NETLINK_CB(cb->skb).portid, if (nf_tables_fill_rule_info(skb, net, NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, cb->nlh->nlmsg_seq,
NFT_MSG_NEWRULE, NFT_MSG_NEWRULE,
NLM_F_MULTI | NLM_F_APPEND, NLM_F_MULTI | NLM_F_APPEND,
table->family, table->family,
table, chain, rule, prule) < 0) table, chain, rule, handle) < 0)
return 1; return 1;
nl_dump_check_consistent(cb, nlmsg_hdr(skb)); nl_dump_check_consistent(cb, nlmsg_hdr(skb));
...@@ -3143,7 +3159,7 @@ static int nf_tables_getrule(struct sk_buff *skb, const struct nfnl_info *info, ...@@ -3143,7 +3159,7 @@ static int nf_tables_getrule(struct sk_buff *skb, const struct nfnl_info *info,
err = nf_tables_fill_rule_info(skb2, net, NETLINK_CB(skb).portid, err = nf_tables_fill_rule_info(skb2, net, NETLINK_CB(skb).portid,
info->nlh->nlmsg_seq, NFT_MSG_NEWRULE, 0, info->nlh->nlmsg_seq, NFT_MSG_NEWRULE, 0,
family, table, chain, rule, NULL); family, table, chain, rule, 0);
if (err < 0) if (err < 0)
goto err_fill_rule_info; goto err_fill_rule_info;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment