From mboxrd@z Thu Jan 1 00:00:00 1970 From: Konstantin Khorenko Date: Wed, 12 Aug 2026 15:04:00 +0200 Subject: [Devel] [PATCH DRAFT vz10 4/5] ve/net/ip6_gre: Fix NULL deref when creating ip6gre/ip6erspan without VE_FEATURE_IPGRE In-Reply-To: <20260812130401.154702-1-khorenko@virtuozzo.com> References: <20260812130401.154702-1-khorenko@virtuozzo.com> Message-ID: <20260812130401.154702-5-khorenko@virtuozzo.com> List-Id: When a Container is not granted VE_FEATURE_IPGRE, ip6gre_init_net() frees the ip6gre_net_id net_generic slot, so net_generic() returns NULL for that netns. The guard added by commit 1e1433063539 ("net/gre: Consider VE_FEATURE_IPGRE on new net creation") was placed in ip6gre_newlink_common(), but both ip6gre_newlink() and ip6erspan_newlink() dereference the per-net data (ign) earlier - via rtnl_dereference(ign->collect_md_tun[_erspan]) and ip6gre_tunnel_find() -> __ip6gre_bucket() - before ever reaching ip6gre_newlink_common(). Both rtnl link ops are registered unconditionally, so a Container without the feature can trigger this by requesting an "ip6gre" or "ip6erspan" link, dereferencing a NULL ign and crashing the host. Move the guard to the top of ip6gre_newlink() and ip6erspan_newlink(), right after ign is fetched and before it is dereferenced, and drop the now-redundant check in ip6gre_newlink_common() (its only two callers now guarantee a non-NULL ign). The changelink paths are not affected: they operate on an already existing tunnel device, which can only exist when the feature is on and ign is non-NULL. Fixes: 1e1433063539 ("net/gre: Consider VE_FEATURE_IPGRE on new net creation") https://virtuozzo.atlassian.net/browse/VSTOR-141173 Feature: ve: per-CT features management Signed-off-by: Konstantin Khorenko --- net/ipv6/ip6_gre.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index ba32cc39fc882..fe867528a0c5b 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -2006,15 +2006,6 @@ static int ip6gre_newlink_common(struct net *src_net, struct net_device *dev, struct ip6_tnl *nt; struct ip_tunnel_encap ipencap; int err; -#ifdef CONFIG_VE - struct net *net = dev_net(dev); - struct ip6gre_net *ign; - - ign = net_generic(net, ip6gre_net_id); - - if (!ign) /* no VE_FEATURE_IPGRE */ - return -EACCES; -#endif nt = netdev_priv(dev); @@ -2054,6 +2045,11 @@ static int ip6gre_newlink(struct net *src_net, struct net_device *dev, ip6gre_netlink_parms(data, &nt->parms); ign = net_generic(net, ip6gre_net_id); +#ifdef CONFIG_VE + if (!ign) /* no VE_FEATURE_IPGRE */ + return -EACCES; +#endif + if (nt->parms.collect_md) { if (rtnl_dereference(ign->collect_md_tun)) return -EEXIST; @@ -2291,6 +2287,11 @@ static int ip6erspan_newlink(struct net *src_net, struct net_device *dev, ip6erspan_set_version(data, &nt->parms); ign = net_generic(net, ip6gre_net_id); +#ifdef CONFIG_VE + if (!ign) /* no VE_FEATURE_IPGRE */ + return -EACCES; +#endif + if (nt->parms.collect_md) { if (rtnl_dereference(ign->collect_md_tun_erspan)) return -EEXIST; -- 2.43.0