diff options
author | Florian Westphal <fw@strlen.de> | 2018-07-17 01:17:56 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2018-07-20 09:31:44 -0400 |
commit | c6cc94df65c3174be92afbee638f11cbb5e606a7 (patch) | |
tree | 0c7c3a3de8183ffcb6b8c11718076a0a428fc5a8 | |
parent | 9f8aac0be21ed5f99bd5ba0ff315d710737d1794 (diff) |
netfilter: nf_tables: don't allow to rename to already-pending name
Its possible to rename two chains to the same name in one
transaction:
nft add chain t c1
nft add chain t c2
nft 'rename chain t c1 c3;rename chain t c2 c3'
This creates two chains named 'c3'.
Appears to be harmless, both chains can still be deleted both
by name or handle, but, nevertheless, its a bug.
Walk transaction log and also compare vs. the pending renames.
Both chains can still be deleted, but nevertheless it is a bug as
we don't allow to create chains with identical names, so we should
prevent this from happening-by-rename too.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r-- | net/netfilter/nf_tables_api.c | 42 |
1 files changed, 29 insertions, 13 deletions
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 91230d713190..d7b9748e338e 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c | |||
@@ -1598,7 +1598,6 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy, | |||
1598 | struct nft_base_chain *basechain; | 1598 | struct nft_base_chain *basechain; |
1599 | struct nft_stats *stats = NULL; | 1599 | struct nft_stats *stats = NULL; |
1600 | struct nft_chain_hook hook; | 1600 | struct nft_chain_hook hook; |
1601 | const struct nlattr *name; | ||
1602 | struct nf_hook_ops *ops; | 1601 | struct nf_hook_ops *ops; |
1603 | struct nft_trans *trans; | 1602 | struct nft_trans *trans; |
1604 | int err; | 1603 | int err; |
@@ -1646,12 +1645,11 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy, | |||
1646 | return PTR_ERR(stats); | 1645 | return PTR_ERR(stats); |
1647 | } | 1646 | } |
1648 | 1647 | ||
1648 | err = -ENOMEM; | ||
1649 | trans = nft_trans_alloc(ctx, NFT_MSG_NEWCHAIN, | 1649 | trans = nft_trans_alloc(ctx, NFT_MSG_NEWCHAIN, |
1650 | sizeof(struct nft_trans_chain)); | 1650 | sizeof(struct nft_trans_chain)); |
1651 | if (trans == NULL) { | 1651 | if (trans == NULL) |
1652 | free_percpu(stats); | 1652 | goto err; |
1653 | return -ENOMEM; | ||
1654 | } | ||
1655 | 1653 | ||
1656 | nft_trans_chain_stats(trans) = stats; | 1654 | nft_trans_chain_stats(trans) = stats; |
1657 | nft_trans_chain_update(trans) = true; | 1655 | nft_trans_chain_update(trans) = true; |
@@ -1661,19 +1659,37 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy, | |||
1661 | else | 1659 | else |
1662 | nft_trans_chain_policy(trans) = -1; | 1660 | nft_trans_chain_policy(trans) = -1; |
1663 | 1661 | ||
1664 | name = nla[NFTA_CHAIN_NAME]; | 1662 | if (nla[NFTA_CHAIN_HANDLE] && |
1665 | if (nla[NFTA_CHAIN_HANDLE] && name) { | 1663 | nla[NFTA_CHAIN_NAME]) { |
1666 | nft_trans_chain_name(trans) = | 1664 | struct nft_trans *tmp; |
1667 | nla_strdup(name, GFP_KERNEL); | 1665 | char *name; |
1668 | if (!nft_trans_chain_name(trans)) { | 1666 | |
1669 | kfree(trans); | 1667 | err = -ENOMEM; |
1670 | free_percpu(stats); | 1668 | name = nla_strdup(nla[NFTA_CHAIN_NAME], GFP_KERNEL); |
1671 | return -ENOMEM; | 1669 | if (!name) |
1670 | goto err; | ||
1671 | |||
1672 | err = -EEXIST; | ||
1673 | list_for_each_entry(tmp, &ctx->net->nft.commit_list, list) { | ||
1674 | if (tmp->msg_type == NFT_MSG_NEWCHAIN && | ||
1675 | tmp->ctx.table == table && | ||
1676 | nft_trans_chain_update(tmp) && | ||
1677 | nft_trans_chain_name(tmp) && | ||
1678 | strcmp(name, nft_trans_chain_name(tmp)) == 0) { | ||
1679 | kfree(name); | ||
1680 | goto err; | ||
1681 | } | ||
1672 | } | 1682 | } |
1683 | |||
1684 | nft_trans_chain_name(trans) = name; | ||
1673 | } | 1685 | } |
1674 | list_add_tail(&trans->list, &ctx->net->nft.commit_list); | 1686 | list_add_tail(&trans->list, &ctx->net->nft.commit_list); |
1675 | 1687 | ||
1676 | return 0; | 1688 | return 0; |
1689 | err: | ||
1690 | free_percpu(stats); | ||
1691 | kfree(trans); | ||
1692 | return err; | ||
1677 | } | 1693 | } |
1678 | 1694 | ||
1679 | static int nf_tables_newchain(struct net *net, struct sock *nlsk, | 1695 | static int nf_tables_newchain(struct net *net, struct sock *nlsk, |