summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAlvaro Neira <alvaroneay@gmail.com>2015-02-24 09:10:32 +0100
committerPablo Neira Ayuso <pablo@netfilter.org>2015-02-24 14:47:23 +0100
commit5dd19ef301a9c92beb470099df0a76e33a614173 (patch)
tree5aa0f9eee91141be1a2ec1e98c883c7948bd9d59 /src
parent05eb2b89defda80be57199315f6bf40cf711460e (diff)
ruleset: fix crash if we free sets included in the set_list
When we parse a ruleset which has a rule using a set. First step is to parse the set, set up an ID and add it to a set list. Later, we use this set list to find the set associated to the rule and we set up the set ID to the expression (lookup expression) of the rule. The problem is that if we return this set to the callback function nft_ruleset_parse_file_cb() and we free this set, we have a crash when we try to iterate in the set list. This patch solves it, cloning the set and adding the new set to the set list. Signed-off-by: Alvaro Neira Ayuso <alvaroneay@gmail.com> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src')
-rw-r--r--src/ruleset.c9
-rw-r--r--src/set.c31
-rw-r--r--src/set_elem.c16
3 files changed, 55 insertions, 1 deletions
diff --git a/src/ruleset.c b/src/ruleset.c
index 89ea344..280f1bc 100644
--- a/src/ruleset.c
+++ b/src/ruleset.c
@@ -312,8 +312,15 @@ static int nft_ruleset_parse_set(struct nft_parse_ctx *ctx,
struct nft_set *set, uint32_t type,
struct nft_parse_err *err)
{
+ struct nft_set *newset;
+
nft_set_attr_set_u32(set, NFT_SET_ATTR_ID, ctx->set_id++);
- nft_set_list_add_tail(set, ctx->set_list);
+
+ newset = nft_set_clone(set);
+ if (newset == NULL)
+ goto err;
+
+ nft_set_list_add_tail(newset, ctx->set_list);
nft_ruleset_ctx_set_u32(ctx, NFT_RULESET_CTX_TYPE, type);
nft_ruleset_ctx_set(ctx, NFT_RULESET_CTX_SET, set);
diff --git a/src/set.c b/src/set.c
index f810fce..70b4bc6 100644
--- a/src/set.c
+++ b/src/set.c
@@ -246,6 +246,37 @@ uint32_t nft_set_attr_get_u32(struct nft_set *s, uint16_t attr)
}
EXPORT_SYMBOL(nft_set_attr_get_u32);
+struct nft_set *nft_set_clone(const struct nft_set *set)
+{
+ struct nft_set *newset;
+ struct nft_set_elem *elem, *newelem;
+
+ newset = nft_set_alloc();
+ if (newset == NULL)
+ return NULL;
+
+ memcpy(newset, set, sizeof(*set));
+
+ if (set->flags & (1 << NFT_SET_ATTR_TABLE))
+ newset->table = strdup(set->table);
+ if (set->flags & (1 << NFT_SET_ATTR_NAME))
+ newset->name = strdup(set->name);
+
+ INIT_LIST_HEAD(&newset->element_list);
+ list_for_each_entry(elem, &set->element_list, head) {
+ newelem = nft_set_elem_clone(elem);
+ if (newelem == NULL)
+ goto err;
+
+ list_add_tail(&newelem->head, &newset->element_list);
+ }
+
+ return newset;
+err:
+ nft_set_free(newset);
+ return NULL;
+}
+
static void
nft_set_nlmsg_build_desc_payload(struct nlmsghdr *nlh, struct nft_set *s)
{
diff --git a/src/set_elem.c b/src/set_elem.c
index 25cd951..e822acc 100644
--- a/src/set_elem.c
+++ b/src/set_elem.c
@@ -161,6 +161,22 @@ uint32_t nft_set_elem_attr_get_u32(struct nft_set_elem *s, uint16_t attr)
}
EXPORT_SYMBOL(nft_set_elem_attr_get_u32);
+struct nft_set_elem *nft_set_elem_clone(struct nft_set_elem *elem)
+{
+ struct nft_set_elem *newelem;
+
+ newelem = nft_set_elem_alloc();
+ if (newelem == NULL)
+ return NULL;
+
+ memcpy(newelem, elem, sizeof(*elem));
+
+ if (elem->flags & (1 << NFT_SET_ELEM_ATTR_CHAIN))
+ newelem->data.chain = strdup(elem->data.chain);
+
+ return newelem;
+}
+
void nft_set_elem_nlmsg_build_payload(struct nlmsghdr *nlh,
struct nft_set_elem *e)
{