diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2018-10-01 14:51:24 +0200 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2018-10-03 12:19:35 +0200 |
commit | 95629758a5ec36313d839f8545fef0dc220408d8 (patch) | |
tree | 87d41f7f29438af6b5ca75731282c22d0dc57a2b /src | |
parent | 2e0ea44c99e466ea0bcb6aca5de95e2c7284f09c (diff) |
segtree: bogus range via get set element on existing elements
table ip x {
set y {
type inet_service
flags interval
elements = { 10, 20-30, 40, 50-60 }
}
}
# nft get element x y { 20-40 }
table ip x {
set y {
type inet_service
flags interval
elements = { 20-40 }
}
}
20 and 40 exist in the tree, but they are part of different ranges.
This patch adds a new get_set_decompose() function to validate that the
left and the right side of the range.
Reported-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src')
-rw-r--r-- | src/netlink.c | 5 | ||||
-rw-r--r-- | src/segtree.c | 48 |
2 files changed, 49 insertions, 4 deletions
diff --git a/src/netlink.c b/src/netlink.c index f795d984..7c3082bb 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -1361,8 +1361,9 @@ int netlink_get_setelem(struct netlink_ctx *ctx, const struct handle *h, nftnl_set_free(nls_out); ctx->set = NULL; - if (set->flags & NFT_SET_INTERVAL) - get_set_decompose(table, set); + if (set->flags & NFT_SET_INTERVAL && + get_set_decompose(table, set) < 0) + return -1; return 0; } diff --git a/src/segtree.c b/src/segtree.c index 8a8aa71e..288b01f4 100644 --- a/src/segtree.c +++ b/src/segtree.c @@ -641,6 +641,42 @@ struct expr *get_set_intervals(const struct set *set, const struct expr *init) return new_init; } +static struct expr *get_set_interval_find(const struct table *table, + const char *set_name, + struct expr *left, + struct expr *right) +{ + struct expr *range = NULL; + struct set *set; + mpz_t low, high; + struct expr *i; + + set = set_lookup(table, set_name); + mpz_init2(low, set->key->len); + mpz_init2(high, set->key->len); + + list_for_each_entry(i, &set->init->expressions, list) { + switch (i->key->ops->type) { + case EXPR_RANGE: + range_expr_value_low(low, i); + range_expr_value_high(high, i); + if (mpz_cmp(left->key->value, low) >= 0 && + mpz_cmp(right->key->value, high) <= 0) + range = range_expr_alloc(&internal_location, + expr_clone(left->key), + expr_clone(right->key)); + break; + default: + break; + } + } + + mpz_clear(low); + mpz_clear(high); + + return range; +} + static struct expr *get_set_interval_end(const struct table *table, const char *set_name, struct expr *left) @@ -675,7 +711,7 @@ static struct expr *get_set_interval_end(const struct table *table, return left; } -void get_set_decompose(struct table *table, struct set *set) +int get_set_decompose(struct table *table, struct set *set) { struct expr *i, *next, *new; struct expr *left = NULL; @@ -688,7 +724,13 @@ void get_set_decompose(struct table *table, struct set *set) list_del(&left->list); list_del(&i->list); mpz_sub_ui(i->key->value, i->key->value, 1); - new = range_expr_alloc(&internal_location, left, i); + new = get_set_interval_find(table, set->handle.set.name, + left, i); + if (!new) { + errno = ENOENT; + return -1; + } + compound_expr_add(new_init, new); left = NULL; } else { @@ -707,6 +749,8 @@ void get_set_decompose(struct table *table, struct set *set) } set->init = new_init; + + return 0; } static bool range_is_prefix(const mpz_t range) |