]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
src: assert on EXPR_SET only contains EXPR_SET_ELEM in the expressions list
authorPablo Neira Ayuso <pablo@netfilter.org>
Thu, 5 Feb 2026 02:41:12 +0000 (03:41 +0100)
committerFlorian Westphal <fw@strlen.de>
Tue, 10 Feb 2026 17:22:01 +0000 (18:22 +0100)
Add assert() to validate that expression lists contain EXPR_SET_ELEM.
This allows to detect potential subtle bugs when dereferencing struct
expr.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Florian Westphal <fw@strlen.de>
src/evaluate.c
src/expression.c
src/intervals.c
src/json.c
src/netlink.c
src/netlink_delinearize.c
src/optimize.c
src/segtree.c

index e6689adf088008b953be7153c29465d944535492..f0a82a2c46eb7ed5da34769d9106a2447f082662 100644 (file)
@@ -2080,6 +2080,8 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr)
                        struct expr *new, *j;
 
                        list_for_each_entry(j, &expr_set(i->key->left)->expressions, list) {
+                               assert(j->etype == EXPR_SET_ELEM);
+
                                new = mapping_expr_alloc(&i->location,
                                                         expr_get(j->key),
                                                         expr_get(i->key->right));
@@ -2781,9 +2783,9 @@ static void optimize_singleton_set(struct expr *rel, struct expr **expr)
        struct expr *set = rel->right, *i;
 
        i = list_first_entry(&expr_set(set)->expressions, struct expr, list);
-       if (i->etype == EXPR_SET_ELEM &&
-           list_empty(&i->stmt_list)) {
+       assert (i->etype == EXPR_SET_ELEM);
 
+       if (list_empty(&i->stmt_list)) {
                switch (i->key->etype) {
                case EXPR_PREFIX:
                case EXPR_RANGE:
@@ -5488,19 +5490,12 @@ static struct expr *expr_set_to_list(struct eval_ctx *ctx, struct expr *dev_expr
        LIST_HEAD(tmp);
 
        list_for_each_entry_safe(expr, next, &expr_set(dev_expr)->expressions, list) {
-               list_del(&expr->list);
-
-               switch (expr->etype) {
-               case EXPR_SET_ELEM:
-                       key = expr_clone(expr->key);
-                       expr_free(expr);
-                       expr = key;
-                       break;
-               default:
-                       BUG("invalid expression type %s", expr_name(expr));
-                       break;
-               }
+               assert(expr->etype == EXPR_SET_ELEM);
 
+               list_del(&expr->list);
+               key = expr_clone(expr->key);
+               expr_free(expr);
+               expr = key;
                list_add(&expr->list, &tmp);
        }
 
index 5aac7165319f91a35ec248c3a7d513a35ec4346f..f356cf11730765da300bbd169c621e664807bbe5 100644 (file)
@@ -946,8 +946,9 @@ void relational_expr_pctx_update(struct proto_ctx *ctx,
                        ops->pctx_update(ctx, &expr->location, left, right);
                else if (right->etype == EXPR_SET) {
                        list_for_each_entry(i, &expr_set(right)->expressions, list) {
-                               if (i->etype == EXPR_SET_ELEM &&
-                                   i->key->etype == EXPR_VALUE)
+                               assert(i->etype == EXPR_SET_ELEM);
+
+                               if (i->key->etype == EXPR_VALUE)
                                        ops->pctx_update(ctx, &expr->location, left, i->key);
                        }
                } else if (ops == &meta_expr_ops &&
@@ -1384,6 +1385,8 @@ static void set_expr_print(const struct expr *expr, struct output_ctx *octx)
        nft_print(octx, "{ ");
 
        list_for_each_entry(i, &expr_set(expr)->expressions, list) {
+               assert(i->etype == EXPR_SET_ELEM);
+
                nft_print(octx, "%s", d);
                expr_print(i, octx);
                count++;
@@ -1406,8 +1409,10 @@ static void set_expr_destroy(struct expr *expr)
 {
        struct expr *i, *next;
 
-       list_for_each_entry_safe(i, next, &expr_set(expr)->expressions, list)
+       list_for_each_entry_safe(i, next, &expr_set(expr)->expressions, list) {
+               assert(i->etype == EXPR_SET_ELEM);
                expr_free(i);
+       }
 }
 
 static void set_expr_set_type(const struct expr *expr,
@@ -1416,8 +1421,11 @@ static void set_expr_set_type(const struct expr *expr,
 {
        struct expr *i;
 
-       list_for_each_entry(i, &expr_set(expr)->expressions, list)
+       list_for_each_entry(i, &expr_set(expr)->expressions, list) {
+               assert(i->etype == EXPR_SET_ELEM);
+
                expr_set_type(i, dtype, byteorder);
+       }
 }
 
 static const struct expr_ops set_expr_ops = {
index 9ab2cc20533a36c9038ac1bf2c0ca846db20d010..ec4435e08690ea929c7ad93c368fafe8c5e4a021 100644 (file)
@@ -183,6 +183,8 @@ static void setelem_automerge(struct set_automerge_ctx *ctx)
        mpz_init(rop);
 
        list_for_each_entry_safe(i, next, &expr_set(ctx->init)->expressions, list) {
+               assert(i->etype == EXPR_SET_ELEM);
+
                if (expr_type_catchall(i->key))
                        continue;
 
@@ -243,6 +245,8 @@ static void set_to_range(struct expr *init)
        struct expr *i, *elem;
 
        list_for_each_entry(i, &expr_set(init)->expressions, list) {
+               assert(i->etype == EXPR_SET_ELEM);
+
                elem = interval_expr_key(i);
                setelem_expr_to_range(elem);
        }
@@ -274,6 +278,8 @@ int set_automerge(struct list_head *msgs, struct cmd *cmd, struct set *set,
        setelem_automerge(&ctx);
 
        list_for_each_entry_safe(i, next, &expr_set(init)->expressions, list) {
+               assert(i->etype == EXPR_SET_ELEM);
+
                if (i->flags & EXPR_F_KERNEL) {
                        list_move_tail(&i->list, &expr_set(existing_set->init)->expressions);
                } else if (existing_set) {
@@ -413,6 +419,8 @@ static int setelem_delete(struct list_head *msgs, struct set *set,
        mpz_init(rop);
 
        list_for_each_entry_safe(elem, next, &expr_set(elems)->expressions, list) {
+               assert(elem->etype == EXPR_SET_ELEM);
+
                i = interval_expr_key(elem);
 
                if (expr_type_catchall(i->key)) {
@@ -585,6 +593,8 @@ static int setelem_overlap(struct list_head *msgs, struct set *set,
        mpz_init(rop);
 
        list_for_each_entry_safe(elem, next, &expr_set(init)->expressions, list) {
+               assert(elem->etype == EXPR_SET_ELEM);
+
                i = interval_expr_key(elem);
 
                if (expr_type_catchall(i->key))
@@ -654,6 +664,8 @@ int set_overlap(struct list_head *msgs, struct set *set, struct expr *init)
        err = setelem_overlap(msgs, set, init);
 
        list_for_each_entry_safe(i, n, &expr_set(init)->expressions, list) {
+               assert(i->etype == EXPR_SET_ELEM);
+
                if (i->flags & EXPR_F_KERNEL)
                        list_move_tail(&i->list, &expr_set(existing_set->init)->expressions);
                else if (existing_set) {
@@ -711,6 +723,8 @@ int set_to_intervals(const struct set *set, struct expr *init, bool add)
        mpz_t p;
 
        list_for_each_entry_safe(i, n, &expr_set(init)->expressions, list) {
+               assert(i->etype == EXPR_SET_ELEM);
+
                elem = interval_expr_key(i);
 
                if (expr_type_catchall(elem->key))
index 937a82dc19e98f52ec94596084648e4c029959f5..3c369fb916d08d9136a3cc7a562d1eb01f20554e 100644 (file)
@@ -232,8 +232,11 @@ static json_t *set_print_json(struct output_ctx *octx, const struct set *set)
                json_t *array = json_array();
                const struct expr *i;
 
-               list_for_each_entry(i, &expr_set(set->init)->expressions, list)
+               list_for_each_entry(i, &expr_set(set->init)->expressions, list) {
+                       assert(i->etype == EXPR_SET_ELEM);
+
                        json_array_append_new(array, expr_print_json(i, octx));
+               }
 
                json_object_set_new(root, "elem", array);
        }
@@ -768,8 +771,11 @@ json_t *set_expr_json(const struct expr *expr, struct output_ctx *octx)
        json_t *array = json_array();
        const struct expr *i;
 
-       list_for_each_entry(i, &expr_set(expr)->expressions, list)
+       list_for_each_entry(i, &expr_set(expr)->expressions, list) {
+               assert(i->etype == EXPR_SET_ELEM);
+
                json_array_append_new(array, expr_print_json(i, octx));
+       }
 
        return nft_json_pack("{s:o}", "set", array);
 }
index 3a28978547c3679e26455ab5abf6d644f55fdbdf..34c66799548948fb947ee8a0805bc18f04901443 100644 (file)
@@ -1309,6 +1309,8 @@ void alloc_setelem_cache(const struct expr *set, struct nftnl_set *nls)
        const struct expr *expr;
 
        list_for_each_entry(expr, &expr_set(set)->expressions, list) {
+               assert(expr->etype == EXPR_SET_ELEM);
+
                nlse = alloc_nftnl_setelem(set, expr);
                nftnl_set_elem_add(nls, nlse);
        }
index fc359d6d92943d505e71f3492a60d44dc6eab3f5..81763206f1362856ab52d3bdf479efd47b069377 100644 (file)
@@ -2206,9 +2206,9 @@ static void payload_match_postprocess(struct rule_pp_ctx *ctx,
                                struct expr *elem;
 
                                elem = list_first_entry(&expr_set(set->init)->expressions, struct expr, list);
+                               assert(elem->etype == EXPR_SET_ELEM);
 
-                               if (elem->etype == EXPR_SET_ELEM &&
-                                   elem->key->etype == EXPR_VALUE)
+                               if (elem->key->etype == EXPR_VALUE)
                                        payload_icmp_check(ctx, payload, elem->key);
                        }
                }
@@ -2883,8 +2883,11 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
                expr_postprocess(ctx, &expr->right);
                break;
        case EXPR_SET:
-               list_for_each_entry(i, &expr_set(expr)->expressions, list)
+               list_for_each_entry(i, &expr_set(expr)->expressions, list) {
+                       assert(i->etype == EXPR_SET_ELEM);
+
                        expr_postprocess(ctx, &i);
+               }
                break;
        case EXPR_CONCAT:
                expr_postprocess_concat(ctx, exprp);
index 3e6e24cf7b90534b7db8b336a72c87964c0e6ce4..a2bd3aab72d003ddd48a8d23a2ac81d2b3ffcc6c 100644 (file)
@@ -594,6 +594,7 @@ static void merge_vmap(const struct optimize_ctx *ctx,
 
        mappings = stmt_b->expr->mappings;
        list_for_each_entry(expr, &expr_set(mappings)->expressions, list) {
+               assert(expr->etype == EXPR_SET_ELEM);
                mapping = expr_clone(expr);
                set_expr_add(stmt_a->expr->mappings, mapping);
        }
@@ -660,6 +661,7 @@ static void __merge_concat(const struct optimize_ctx *ctx, uint32_t i,
                        switch (stmt_a->expr->right->etype) {
                        case EXPR_SET:
                                list_for_each_entry(expr, &expr_set(stmt_a->expr->right)->expressions, list) {
+                                       assert(expr->etype == EXPR_SET_ELEM);
                                        concat_clone = expr_clone(concat);
                                        clone = expr_clone(expr->key);
                                        concat_expr_add(concat_clone, clone);
@@ -771,6 +773,7 @@ static void build_verdict_map(struct expr *expr, struct stmt *verdict,
                break;
        case EXPR_SET:
                list_for_each_entry(item, &expr_set(expr)->expressions, list) {
+                       assert(item->etype == EXPR_SET_ELEM);
                        mapping = mapping_expr_alloc(&internal_location, expr_get(item->key),
                                                     expr_get(verdict->expr));
 
index 6d96b4f8a0a9947836db3dd78c2ffdfb011539bc..90e4a616edf0dfc7b511e8841b9703807498c7a4 100644 (file)
@@ -80,6 +80,8 @@ struct expr *get_set_intervals(const struct set *set, const struct expr *init)
        new_init = set_expr_alloc(&internal_location, NULL);
 
        list_for_each_entry(i, &expr_set(init)->expressions, list) {
+               assert(i->etype == EXPR_SET_ELEM);
+
                switch (i->key->etype) {
                case EXPR_VALUE:
                        set_elem_add(set, new_init, i->key->value,
@@ -137,6 +139,8 @@ static struct expr *get_set_interval_find(const struct set *cache_set,
        mpz_init2(val, set->key->len);
 
        list_for_each_entry(i, &expr_set(set->init)->expressions, list) {
+               assert(i->etype == EXPR_SET_ELEM);
+
                key = expr_value(i);
                switch (key->etype) {
                case EXPR_VALUE:
@@ -357,6 +361,8 @@ void concat_range_aggregate(struct expr *set)
        mpz_t range, p;
 
        list_for_each_entry_safe(i, next, &expr_set(set)->expressions, list) {
+               assert(i->etype == EXPR_SET_ELEM);
+
                if (!start) {
                        start = i;
                        continue;