aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2018-07-17 01:17:56 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2018-07-20 09:31:44 -0400
commitc6cc94df65c3174be92afbee638f11cbb5e606a7 (patch)
tree0c7c3a3de8183ffcb6b8c11718076a0a428fc5a8
parent9f8aac0be21ed5f99bd5ba0ff315d710737d1794 (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.c42
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;
1689err:
1690 free_percpu(stats);
1691 kfree(trans);
1692 return err;
1677} 1693}
1678 1694
1679static int nf_tables_newchain(struct net *net, struct sock *nlsk, 1695static int nf_tables_newchain(struct net *net, struct sock *nlsk,