]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
src: fix extended netlink error reporting with large set elements
authorPablo Neira Ayuso <pablo@netfilter.org>
Wed, 23 Oct 2024 22:24:55 +0000 (00:24 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Mon, 28 Oct 2024 22:20:38 +0000 (23:20 +0100)
Large sets can expand into several netlink messages, use sequence number
and attribute offset to correlate the set element and the location.

When set element command expands into several netlink messages,
increment sequence number for each netlink message. Update struct cmd to
store the range of netlink messages that result from this command.

struct nlerr_loc remains in the same size in x86_64.

 # nft -f set-65535.nft
 set-65535.nft:65029:22-32: Error: Could not process rule: File exists
 create element x y { 1.1.254.253 }
                      ^^^^^^^^^^^

Fixes: f8aec603aa7e ("src: initial extended netlink error reporting")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/rule.h
src/cmd.c
src/libnftables.c
src/mnl.c
src/parser_json.c

index 3fcfa445d1037215537f625651ae135567f4e7fe..48e148e6afdd9723965fa2eda762723bda227188 100644 (file)
@@ -695,6 +695,7 @@ void monitor_free(struct monitor *m);
 #define NFT_NLATTR_LOC_MAX 32
 
 struct nlerr_loc {
+       uint32_t                seqnum;
        uint32_t                offset;
        const struct location   *location;
 };
@@ -717,7 +718,8 @@ struct cmd {
        enum cmd_ops            op;
        enum cmd_obj            obj;
        struct handle           handle;
-       uint32_t                seqnum;
+       uint32_t                seqnum_from;
+       uint32_t                seqnum_to;
        union {
                void            *data;
                struct expr     *expr;
index 0c7a43edd73ac27dbdf3ade23b56aa5fa89e13d7..eb44b986a49a131852942d2211d7a26371c873c2 100644 (file)
--- a/src/cmd.c
+++ b/src/cmd.c
@@ -24,6 +24,7 @@ void cmd_add_loc(struct cmd *cmd, const struct nlmsghdr *nlh, const struct locat
                cmd->attr = xrealloc(cmd->attr, sizeof(struct nlerr_loc) * cmd->attr_array_len);
        }
 
+       cmd->attr[cmd->num_attrs].seqnum = nlh->nlmsg_seq;
        cmd->attr[cmd->num_attrs].offset = nlh->nlmsg_len;
        cmd->attr[cmd->num_attrs].location = loc;
        cmd->num_attrs++;
@@ -323,7 +324,8 @@ void nft_cmd_error(struct netlink_ctx *ctx, struct cmd *cmd,
        uint32_t i;
 
        for (i = 0; i < cmd->num_attrs; i++) {
-               if (cmd->attr[i].offset == err->offset)
+               if (cmd->attr[i].seqnum == err->seqnum &&
+                   cmd->attr[i].offset == err->offset)
                        loc = cmd->attr[i].location;
        }
 
index 3550961d5d0e526a69b12a22052ccfb9f331599f..1df22b3cb57d953c025a32b92fd80d52a1e9c5fd 100644 (file)
@@ -39,7 +39,7 @@ static int nft_netlink(struct nft_ctx *nft,
 
        batch_seqnum = mnl_batch_begin(ctx.batch, mnl_seqnum_inc(&seqnum));
        list_for_each_entry(cmd, cmds, list) {
-               ctx.seqnum = cmd->seqnum = mnl_seqnum_inc(&seqnum);
+               ctx.seqnum = cmd->seqnum_from = mnl_seqnum_inc(&seqnum);
                ret = do_command(&ctx, cmd);
                if (ret < 0) {
                        netlink_io_error(&ctx, &cmd->location,
@@ -47,6 +47,8 @@ static int nft_netlink(struct nft_ctx *nft,
                                         strerror(errno));
                        goto out;
                }
+               seqnum = cmd->seqnum_to = ctx.seqnum;
+               mnl_seqnum_inc(&seqnum);
                num_cmds++;
        }
        if (!nft->check)
@@ -80,12 +82,14 @@ static int nft_netlink(struct nft_ctx *nft,
                        cmd = list_first_entry(cmds, struct cmd, list);
 
                list_for_each_entry_from(cmd, cmds, list) {
-                       last_seqnum = cmd->seqnum;
-                       if (err->seqnum == cmd->seqnum ||
+                       last_seqnum = cmd->seqnum_to;
+                       if ((err->seqnum >= cmd->seqnum_from &&
+                            err->seqnum <= cmd->seqnum_to) ||
                            err->seqnum == batch_seqnum) {
                                nft_cmd_error(&ctx, cmd, err);
                                errno = err->err;
-                               if (err->seqnum == cmd->seqnum) {
+                               if (err->seqnum >= cmd->seqnum_from ||
+                                   err->seqnum <= cmd->seqnum_to) {
                                        mnl_err_list_free(err);
                                        break;
                                }
index 42d1b0d87ec17e6c97e1c798fcacd8d7fd0d6546..12a6345cbed8caef919c52470bdc337cf2c8120c 100644 (file)
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -1722,7 +1722,7 @@ static void netlink_dump_setelem_done(struct netlink_ctx *ctx)
 static int mnl_nft_setelem_batch(const struct nftnl_set *nls, struct cmd *cmd,
                                 struct nftnl_batch *batch,
                                 enum nf_tables_msg_types msg_type,
-                                unsigned int flags, uint32_t seqnum,
+                                unsigned int flags, uint32_t *seqnum,
                                 const struct expr *set,
                                 struct netlink_ctx *ctx)
 {
@@ -1741,7 +1741,7 @@ static int mnl_nft_setelem_batch(const struct nftnl_set *nls, struct cmd *cmd,
 next:
        nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(batch), msg_type,
                                    nftnl_set_get_u32(nls, NFTNL_SET_FAMILY),
-                                   flags, seqnum);
+                                   flags, *seqnum);
 
        if (nftnl_set_is_set(nls, NFTNL_SET_TABLE)) {
                 mnl_attr_put_strz(nlh, NFTA_SET_ELEM_LIST_TABLE,
@@ -1774,6 +1774,7 @@ next:
                if (mnl_nft_attr_nest_overflow(nlh, nest1, nest2)) {
                        mnl_attr_nest_end(nlh, nest1);
                        mnl_nft_batch_continue(batch);
+                       mnl_seqnum_inc(seqnum);
                        goto next;
                }
        }
@@ -1808,7 +1809,7 @@ int mnl_nft_setelem_add(struct netlink_ctx *ctx, struct cmd *cmd,
        netlink_dump_set(nls, ctx);
 
        err = mnl_nft_setelem_batch(nls, cmd, ctx->batch, NFT_MSG_NEWSETELEM,
-                                   flags, ctx->seqnum, expr, ctx);
+                                   flags, &ctx->seqnum, expr, ctx);
        nftnl_set_free(nls);
 
        return err;
@@ -1868,7 +1869,7 @@ int mnl_nft_setelem_del(struct netlink_ctx *ctx, struct cmd *cmd,
                msg_type = NFT_MSG_DESTROYSETELEM;
 
        err = mnl_nft_setelem_batch(nls, cmd, ctx->batch, msg_type, 0,
-                                   ctx->seqnum, init, ctx);
+                                   &ctx->seqnum, init, ctx);
        nftnl_set_free(nls);
 
        return err;
index bbe3b1c59192c6e526d34c1c82a0d100df38b3a4..37ec34cb7796402d048847e3a7e616abbfbe5523 100644 (file)
@@ -4269,13 +4269,13 @@ static json_t *seqnum_to_json(const uint32_t seqnum)
                cur = json_cmd_assoc_list;
                json_cmd_assoc_list = cur->next;
 
-               key = cur->cmd->seqnum % CMD_ASSOC_HSIZE;
+               key = cur->cmd->seqnum_from % CMD_ASSOC_HSIZE;
                hlist_add_head(&cur->hnode, &json_cmd_assoc_hash[key]);
        }
 
        key = seqnum % CMD_ASSOC_HSIZE;
        hlist_for_each_entry(cur, n, &json_cmd_assoc_hash[key], hnode) {
-               if (cur->cmd->seqnum == seqnum)
+               if (cur->cmd->seqnum_from == seqnum)
                        return cur->json;
        }