Netdev List
 help / color / mirror / Atom feed
From: Ilya Maximets <i.maximets@ovn.org>
To: Yuqi Xu <xuyuqiabc@gmail.com>, Aaron Conole <aconole@redhat.com>,
	Eelco Chaudron <echaudro@redhat.com>,
	Ilya Maximets <i.maximets@ovn.org>,
	Jakub Kicinski <kuba@kernel.org>
Cc: "David S. Miller" <davem@davemloft.net>,
	Eric Dumazet <edumazet@google.com>,
	Paolo Abeni <pabeni@redhat.com>, Simon Horman <horms@kernel.org>,
	Yi-Hung Wei <yihung.wei@gmail.com>,
	netdev@vger.kernel.org, dev@openvswitch.org,
	linux-kernel@vger.kernel.org, Vega <vega@nebusec.ai>,
	Nan Li <tonanli66@gmail.com>, Ren Wei <enjou1224z@gmail.com>
Subject: Re: [PATCH net v8 1/1] openvswitch: Fix CT limit teardown use-after-free
Date: Thu, 20 Aug 2026 18:00:41 +0200	[thread overview]
Message-ID: <aeae9794-f94d-4eca-99f1-c3c6dc3ef9cc@ovn.org> (raw)
In-Reply-To: <d9687780533d0b257e01ab792c8206a69beb281e.1787129643.git.xuyuqiabc@gmail.com>

On 8/19/26 11:24 AM, Yuqi Xu wrote:
> Packet processing uses CT limit state under RCU, while netns teardown
> frees that state under ovs_mutex. The CT limit pointer was neither removed
> from readers nor protected by a grace period, allowing packet processing to
> dereference the freed state.
> 
> An unprivileged user can trigger this bug from a user and network
> namespace, causing a slab-use-after-free in ovs_ct_execute() when the
> netns is torn down.
> 
> Publish the CT limit pointer through RCU, remove it before teardown, and
> wait for readers before freeing its contents. Keep ovs_mutex around
> individual CT limit updates, and use the RCU read-side lock while GET
> traverses the RCU-protected limit lists.
> 
> Netns teardown detaches the RCU-protected CT limit state in the pernet
> .pre_exit callback while holding ovs_mutex.  The pernet core guarantees an
> RCU grace period between the .pre_exit and .exit callbacks, so the .exit
> callback completes the teardown without adding any extra synchronization.
> 
> The netlink command handlers do not need NULL checks because the userspace
> netlink socket holds an active reference to its network namespace while a
> request is processed. The per-netns exit path therefore cannot run
> concurrently with SET, DEL, or GET for that socket's namespace.
> 
> Fixes: 11efd5cb04a1 ("openvswitch: Support conntrack zone limit")
> Cc: stable@vger.kernel.org
> Reported-by: Vega <vega@nebusec.ai>
> Link: https://lore.kernel.org/all/cover.1784711445.git.xuyuqiabc@gmail.com
> Assisted-by: Codex:GPT-5.4
> Co-developed-by: Nan Li <tonanli66@gmail.com>
> Signed-off-by: Nan Li <tonanli66@gmail.com>
> Signed-off-by: Yuqi Xu <xuyuqiabc@gmail.com>
> Reviewed-by: Ren Wei <enjou1224z@gmail.com>
> ---
> 
> Changes in v8:
> 
> - Rebase onto net/main, which now contains the adjacent nf_connlabels
>   leak fix.
> - Move the CT limit detach to the pernet .pre_exit callback and complete
>   the teardown in .exit, relying on the RCU grace period that the pernet
>   core guarantees between the two. Drop the extra synchronize_rcu() and
>   use plain kfree() in the teardown path.
> - v7 Link: https://lore.kernel.org/all/cover.1786936669.git.xuyuqiabc@gmail.com/

[...]

> diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
> index ded46d993a4e..362e322fb41f 100644
> --- a/net/openvswitch/datapath.c
> +++ b/net/openvswitch/datapath.c
> @@ -2757,17 +2757,24 @@ static void __net_exit list_vports_from_net(struct net *net, struct net *dnet,
>  	}
>  }
>  
> +static void __net_exit ovs_pre_exit_net(struct net *dnet)
> +{
> +	ovs_lock();
> +	ovs_ct_exit_start(dnet);
> +	ovs_unlock();
> +}
> +
>  static void __net_exit ovs_exit_net(struct net *dnet)
>  {
> -	struct datapath *dp, *dp_next;
>  	struct ovs_net *ovs_net = net_generic(dnet, ovs_net_id);
>  	struct vport *vport, *vport_next;
> +	struct datapath *dp, *dp_next;

Shouldn't move these around now that there are no other changes.

>  	struct net *net;
>  	LIST_HEAD(head);
>  
>  	ovs_lock();
>  
> -	ovs_ct_exit(dnet);
> +	ovs_ct_exit_finish(dnet, ovs_net->ct_exit_data);

This will not compile without CONFIG_NETFILTER_CONNCOUNT.
There is also asymmetry here.  The value is not set in this
module, there is no point to pass it from here.  The finish()
function can access it through the dnet pointer.

>  
>  	list_for_each_entry_safe(dp, dp_next, &ovs_net->dps, list_node)
>  		__dp_destroy(dp);
> @@ -2791,6 +2798,7 @@ static void __net_exit ovs_exit_net(struct net *dnet)
>  
>  static struct pernet_operations ovs_net_ops = {
>  	.init = ovs_init_net,
> +	.pre_exit = ovs_pre_exit_net,
>  	.exit = ovs_exit_net,
>  	.id   = &ovs_net_id,
>  	.size = sizeof(struct ovs_net),
> diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h
> index 696640e88fa7..446553c51c30 100644
> --- a/net/openvswitch/datapath.h
> +++ b/net/openvswitch/datapath.h
> @@ -164,7 +164,10 @@ struct dp_upcall_info {
>   * Protected by genl_mutex.
>   * @dp_notify_work: A work notifier to handle port unregistering.
>   * @masks_rebalance: A work to periodically optimize flow table caches.
> - * @ct_limit_info: A hash table of conntrack zone connection limits.
> + * @ct_limit_info: Hash table of conntrack zone connection limits. Protected
> + * by RCU; updates and teardown are serialized by ovs_mutex. May be NULL during
> + * netns teardown.
> + * @ct_exit_data: CT limit state detached at .pre_exit, freed at .exit.
>   * @xt_label: Whether connlables are configured for the network or not.
>   */
>  struct ovs_net {
> @@ -172,7 +175,8 @@ struct ovs_net {
>  	struct work_struct dp_notify_work;
>  	struct delayed_work masks_rebalance;
>  #if	IS_ENABLED(CONFIG_NETFILTER_CONNCOUNT)
> -	struct ovs_ct_limit_info *ct_limit_info;
> +	struct ovs_ct_limit_info __rcu *ct_limit_info;
> +	struct ovs_ct_limit_info *ct_exit_data;

Maybe rename into ct_limit_exit_data, since it is only for the limits
and guarded by the CONFIG_NETFILTER_CONNCOUNT.

>  #endif
>  	bool xt_label;
>  };
> 


  reply	other threads:[~2026-08-20 16:00 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-19  9:24 [PATCH net v8 0/1] openvswitch: Fix CT limit teardown use-after-free Yuqi Xu
2026-08-19  9:24 ` [PATCH net v8 1/1] " Yuqi Xu
2026-08-20 16:00   ` Ilya Maximets [this message]
2026-08-21  9:41   ` kernel test robot
2026-08-21 12:20   ` kernel test robot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=aeae9794-f94d-4eca-99f1-c3c6dc3ef9cc@ovn.org \
    --to=i.maximets@ovn.org \
    --cc=aconole@redhat.com \
    --cc=davem@davemloft.net \
    --cc=dev@openvswitch.org \
    --cc=echaudro@redhat.com \
    --cc=edumazet@google.com \
    --cc=enjou1224z@gmail.com \
    --cc=horms@kernel.org \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=tonanli66@gmail.com \
    --cc=vega@nebusec.ai \
    --cc=xuyuqiabc@gmail.com \
    --cc=yihung.wei@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox