Skip to content

Commit

Permalink
netfilter: nf_tables: honor NLM_F_EXCL flag in set element insertion
Browse files Browse the repository at this point in the history
If the NLM_F_EXCL flag is set, then new elements that clash with an
existing one return EEXIST. In case you try to add an element whose
data area differs from what we have, then this returns EBUSY. If no
flag is specified at all, then this returns success to userspace.

This patch also update the set insert operation so we can fetch the
existing element that clashes with the one you want to add, we need
this to make sure the element data doesn't differ.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
  • Loading branch information
ummakynes committed Aug 26, 2016
1 parent 5ca8cc5 commit c016c7e
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 14 deletions.
3 changes: 2 additions & 1 deletion include/net/netfilter/nf_tables.h
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,8 @@ struct nft_set_ops {

int (*insert)(const struct net *net,
const struct nft_set *set,
const struct nft_set_elem *elem);
const struct nft_set_elem *elem,
struct nft_set_ext **ext);
void (*activate)(const struct net *net,
const struct nft_set *set,
const struct nft_set_elem *elem);
Expand Down
20 changes: 15 additions & 5 deletions net/netfilter/nf_tables_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -3483,12 +3483,12 @@ static int nft_setelem_parse_flags(const struct nft_set *set,
}

static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
const struct nlattr *attr)
const struct nlattr *attr, u32 nlmsg_flags)
{
struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
struct nft_data_desc d1, d2;
struct nft_set_ext_tmpl tmpl;
struct nft_set_ext *ext;
struct nft_set_ext *ext, *ext2;
struct nft_set_elem elem;
struct nft_set_binding *binding;
struct nft_userdata *udata;
Expand Down Expand Up @@ -3615,9 +3615,19 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
goto err4;

ext->genmask = nft_genmask_cur(ctx->net) | NFT_SET_ELEM_BUSY_MASK;
err = set->ops->insert(ctx->net, set, &elem);
if (err < 0)
err = set->ops->insert(ctx->net, set, &elem, &ext2);
if (err) {
if (err == -EEXIST) {
if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA) &&
nft_set_ext_exists(ext2, NFT_SET_EXT_DATA) &&
memcmp(nft_set_ext_data(ext),
nft_set_ext_data(ext2), set->dlen) != 0)
err = -EBUSY;
else if (!(nlmsg_flags & NLM_F_EXCL))
err = 0;
}
goto err5;
}

nft_trans_elem(trans) = elem;
list_add_tail(&trans->list, &ctx->net->nft.commit_list);
Expand Down Expand Up @@ -3673,7 +3683,7 @@ static int nf_tables_newsetelem(struct net *net, struct sock *nlsk,
!atomic_add_unless(&set->nelems, 1, set->size + set->ndeact))
return -ENFILE;

err = nft_add_set_elem(&ctx, set, attr);
err = nft_add_set_elem(&ctx, set, attr, nlh->nlmsg_flags);
if (err < 0) {
atomic_dec(&set->nelems);
break;
Expand Down
17 changes: 13 additions & 4 deletions net/netfilter/nft_set_hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,8 @@ static bool nft_hash_update(struct nft_set *set, const u32 *key,
}

static int nft_hash_insert(const struct net *net, const struct nft_set *set,
const struct nft_set_elem *elem)
const struct nft_set_elem *elem,
struct nft_set_ext **ext)
{
struct nft_hash *priv = nft_set_priv(set);
struct nft_hash_elem *he = elem->priv;
Expand All @@ -135,9 +136,17 @@ static int nft_hash_insert(const struct net *net, const struct nft_set *set,
.set = set,
.key = elem->key.val.data,
};

return rhashtable_lookup_insert_key(&priv->ht, &arg, &he->node,
nft_hash_params);
struct nft_hash_elem *prev;

prev = rhashtable_lookup_get_insert_key(&priv->ht, &arg, &he->node,
nft_hash_params);
if (IS_ERR(prev))
return PTR_ERR(prev);
if (prev) {
*ext = &prev->ext;
return -EEXIST;
}
return 0;
}

static void nft_hash_activate(const struct net *net, const struct nft_set *set,
Expand Down
12 changes: 8 additions & 4 deletions net/netfilter/nft_set_rbtree.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ static bool nft_rbtree_lookup(const struct net *net, const struct nft_set *set,
}

static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
struct nft_rbtree_elem *new)
struct nft_rbtree_elem *new,
struct nft_set_ext **ext)
{
struct nft_rbtree *priv = nft_set_priv(set);
u8 genmask = nft_genmask_next(net);
Expand Down Expand Up @@ -122,8 +123,10 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
else if (!nft_rbtree_interval_end(rbe) &&
nft_rbtree_interval_end(new))
p = &parent->rb_right;
else
else {
*ext = &rbe->ext;
return -EEXIST;
}
}
}
}
Expand All @@ -133,13 +136,14 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
}

static int nft_rbtree_insert(const struct net *net, const struct nft_set *set,
const struct nft_set_elem *elem)
const struct nft_set_elem *elem,
struct nft_set_ext **ext)
{
struct nft_rbtree_elem *rbe = elem->priv;
int err;

spin_lock_bh(&nft_rbtree_lock);
err = __nft_rbtree_insert(net, set, rbe);
err = __nft_rbtree_insert(net, set, rbe, ext);
spin_unlock_bh(&nft_rbtree_lock);

return err;
Expand Down

0 comments on commit c016c7e

Please sign in to comment.