netfilter: nft_tunnel: fix geneve_opt dump
authorFernando Fernandez Mancera <fmancera@suse.de>
Wed, 21 May 2025 09:41:08 +0000 (11:41 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Fri, 23 May 2025 11:57:12 +0000 (13:57 +0200)
When dumping a nft_tunnel with more than one geneve_opt configured the
netlink attribute hierarchy should be as follow:

 NFTA_TUNNEL_KEY_OPTS
 |
 |--NFTA_TUNNEL_KEY_OPTS_GENEVE
 |  |
 |  |--NFTA_TUNNEL_KEY_GENEVE_CLASS
 |  |--NFTA_TUNNEL_KEY_GENEVE_TYPE
 |  |--NFTA_TUNNEL_KEY_GENEVE_DATA
 |
 |--NFTA_TUNNEL_KEY_OPTS_GENEVE
 |  |
 |  |--NFTA_TUNNEL_KEY_GENEVE_CLASS
 |  |--NFTA_TUNNEL_KEY_GENEVE_TYPE
 |  |--NFTA_TUNNEL_KEY_GENEVE_DATA
 |
 |--NFTA_TUNNEL_KEY_OPTS_GENEVE
 ...

Otherwise, userspace tools won't be able to fetch the geneve options
configured correctly.

Fixes: 925d844696d9 ("netfilter: nft_tunnel: add support for geneve opts")
Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
net/netfilter/nft_tunnel.c

index 0c63d1367cf7a7ea24634b8f5af1d6484064e184..a12486ae089d6f38badd1b904f7670a3ef3bae80 100644 (file)
@@ -621,10 +621,10 @@ static int nft_tunnel_opts_dump(struct sk_buff *skb,
                struct geneve_opt *opt;
                int offset = 0;
 
-               inner = nla_nest_start_noflag(skb, NFTA_TUNNEL_KEY_OPTS_GENEVE);
-               if (!inner)
-                       goto failure;
                while (opts->len > offset) {
+                       inner = nla_nest_start_noflag(skb, NFTA_TUNNEL_KEY_OPTS_GENEVE);
+                       if (!inner)
+                               goto failure;
                        opt = (struct geneve_opt *)(opts->u.data + offset);
                        if (nla_put_be16(skb, NFTA_TUNNEL_KEY_GENEVE_CLASS,
                                         opt->opt_class) ||
@@ -634,8 +634,8 @@ static int nft_tunnel_opts_dump(struct sk_buff *skb,
                                    opt->length * 4, opt->opt_data))
                                goto inner_failure;
                        offset += sizeof(*opt) + opt->length * 4;
+                       nla_nest_end(skb, inner);
                }
-               nla_nest_end(skb, inner);
        }
        nla_nest_end(skb, nest);
        return 0;