All of lore.kernel.org
 help / color / mirror / Atom feed
From: Pablo Neira Ayuso <pablo@netfilter.org>
To: Zihan Xi <zihanx@nebusec.ai>
Cc: netfilter-devel@vger.kernel.org, coreteam@netfilter.org,
	fw@strlen.de, phil@nwl.cc, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, davem@davemloft.net,
	edumazet@google.com, kuba@kernel.org, pabeni@redhat.com,
	horms@kernel.org
Subject: Re: [PATCH nf v3 1/1] netfilter: x_tables: avoid holding mutex over faultable user copies
Date: Fri, 9 Oct 2026 01:54:43 +0200	[thread overview]
Message-ID: <asgtQ3E2LVWqfV8D@chamomile> (raw)
In-Reply-To: <f88fc502b17b4022105a99eea407525807ee573e.1789885804.git.zihanx@nebusec.ai>

On Sun, Sep 20, 2026 at 11:58:22AM +0000, Zihan Xi wrote:
> The legacy IPv4, IPv6 and ARP table GET_INFO and GET_ENTRIES paths hold
> the per-family xtables mutexes while copying table data to userspace. A
> faultable destination may sleep indefinitely while the mutex is held,
> blocking unrelated table and registry operations.
> 
> Disable page faults while each locked user copy runs. For GET_ENTRIES,
> validate the table and requested size while holding the table mutex, then
> release it before faulting in the output range. Reacquire the mutex and
> revalidate the table and size before the nofault copy. If a nofault copy
> fails, fault the range outside the lock and retry the operation up to three
> times after the initial attempt. A failed fault-in returns -EFAULT;
> repeated nofault failures are limited to four attempts in total and then
> return -EFAULT. This avoids discarding a locked counter snapshot on the
> common first fault. Move GET_INFO's fixed-size copy outside the table locks
> and apply the same fault-safe handling to the IPv4/IPv6 compat GET_ENTRIES
> paths.
> 
> The ebtables GET paths use a separate ebt_mutex and are outside this
> IPv4/IPv6/ARP series.

I keep spinning on this, and I am not sure this fix is the right thing
to do. There is no single caller of this pagefault_disable/enable() mm
subsystem function in the net folder.

Would it be feasible to turn this global family mutex into a per-netns
family mutex? xt_find_table_lock() could be revamped to make it?

The iteration over xt_templates[] still needs to hold the global
family lock, but only to create the table in that netns.

> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Cc: stable@vger.kernel.org
> Reported-by: Vega <vega@nebusec.ai>
> Assisted-by: LLM
> Co-developed-by: Luxing Yin <root@tr0jan.top>
> Signed-off-by: Luxing Yin <root@tr0jan.top>
> Signed-off-by: Zihan Xi <zihanx@nebusec.ai>
> ---
> changes in v3:
>   - Validate table and requested size before fault-in, then revalidate the
>     table and size after lock reacquisition in native and IPv4/IPv6 compat
>     GET_ENTRIES paths.
>   - Make retry semantics explicit: one initial nofault attempt followed by
>     at most three retries. Keep fault-in and retry decisions outside family
>     mutexes; failed fault-in and exhausted retries return -EFAULT.
>   - Keep the fixed-size GET_INFO copy outside table locks and brace compat
>     lookup error arms.
>   - Clarify ARP-only runtime coverage, privilege scope, helper build,
>     holder/waiter evidence, QEMU configuration, and the NOT RUN
>     crash-log status.
>   - Regenerate the numbered patch and cover with LF line endings; use the
>     standard 0001-*.patch filename.
>   - v2 Link:
>     https://lore.kernel.org/all/cover.1788961415.git.zihanx@nebusec.ai/
> changes in v2:
>   - Rebase onto current nf.git after 0bd7ed1a3263c
>     ("netfilter: arp_tables: remove the 32bit compat interface").
>     ARP GET_INFO and GET_ENTRIES use native paths only; IPv4 and IPv6
>     retain compat handling.
>   - Drop hung_task_panic and the 10-second hung_task timeout from the
>     reproducer, as pointed out by Pablo Neira Ayuso; observe holder/waiter
>     wchan instead.
>   - v1 Link:
>     https://lore.kernel.org/all/cover.1788244146.git.zihanx@nebusec.ai/
> 
>  net/ipv4/netfilter/arp_tables.c | 49 ++++++++++++++++---
>  net/ipv4/netfilter/ip_tables.c  | 87 +++++++++++++++++++++++++++++----
>  net/ipv6/netfilter/ip6_tables.c | 87 +++++++++++++++++++++++++++++----
>  3 files changed, 197 insertions(+), 26 deletions(-)
> 
> diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
> index db307fa..a857e67 100644
> --- a/net/ipv4/netfilter/arp_tables.c
7> +++ b/net/ipv4/netfilter/arp_tables.c
> @@ -23,6 +23,7 @@
>  #include <linux/init.h>
>  #include <linux/mutex.h>
>  #include <linux/err.h>
> +#include <linux/pagemap.h>
>  #include <net/sock.h>
>  #include <linux/uaccess.h>
>  
> @@ -695,6 +696,7 @@ static int copy_entries_to_user(unsigned int total_size,
>  
>  	loc_cpu_entry = private->entries;
>  
> +	pagefault_disable();
>  	/* FIXME: use iterator macros --RR */
>  	/* ... then go back and fix counters and names */
>  	for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
> @@ -719,12 +721,14 @@ static int copy_entries_to_user(unsigned int total_size,
>  	}
>  
>   free_counters:
> +	pagefault_enable();
>  	vfree(counters);
>  	return ret;
>  }
>  
>  static int get_info(struct net *net, void __user *user, const int *len)
>  {
> +	struct arpt_getinfo info;
>  	char name[XT_TABLE_MAXNAMELEN];
>  	struct xt_table *t;
>  	int ret;
> @@ -738,7 +742,6 @@ static int get_info(struct net *net, void __user *user, const int *len)
>  	name[XT_TABLE_MAXNAMELEN-1] = '\0';
>  	t = xt_request_find_table_lock(net, NFPROTO_ARP, name);
>  	if (!IS_ERR(t)) {
> -		struct arpt_getinfo info;
>  		const struct xt_table_info *private = t->private;
>  
>  		memset(&info, 0, sizeof(info));
> @@ -751,15 +754,14 @@ static int get_info(struct net *net, void __user *user, const int *len)
>  		info.size = private->size;
>  		strscpy(info.name, name);
>  
> -		if (copy_to_user(user, &info, *len) != 0)
> -			ret = -EFAULT;
> -		else
> -			ret = 0;
> +		ret = 0;
>  		xt_table_unlock(t);
>  		module_put(t->me);
>  	} else
>  		ret = PTR_ERR(t);
>  
> +	if (!ret && copy_to_user(user, &info, *len) != 0)
> +		ret = -EFAULT;
>  	return ret;
>  }
>  
> @@ -769,6 +771,7 @@ static int get_entries(struct net *net, struct arpt_get_entries __user *uptr,
>  	int ret;
>  	struct arpt_get_entries get;
>  	struct xt_table *t;
> +	unsigned int retries = 0;
>  
>  	if (*len < sizeof(get))
>  		return -EINVAL;
> @@ -779,21 +782,51 @@ static int get_entries(struct net *net, struct arpt_get_entries __user *uptr,
>  
>  	get.name[sizeof(get.name) - 1] = '\0';
>  
> +retry:
> +	t = xt_find_table_lock(net, NFPROTO_ARP, get.name);
> +	if (IS_ERR(t)) {
> +		ret = PTR_ERR(t);
> +		goto out;
> +	}
> +
> +	if (get.size != t->private->size) {
> +		ret = -EAGAIN;
> +		module_put(t->me);
> +		xt_table_unlock(t);
> +		goto out;
> +	}
> +
> +	module_put(t->me);
> +	xt_table_unlock(t);
> +
> +	/* Fault in only after validating the table and requested size. */
> +	if (fault_in_safe_writeable((char __user *)uptr->entrytable,
> +				    get.size))
> +		return -EFAULT;
> +
>  	t = xt_find_table_lock(net, NFPROTO_ARP, get.name);
>  	if (!IS_ERR(t)) {
>  		const struct xt_table_info *private = t->private;
>  
> -		if (get.size == private->size)
> +		if (get.size != private->size) {
> +			ret = -EAGAIN;
> +		} else {
>  			ret = copy_entries_to_user(private->size,
>  						   t, uptr->entrytable);
> -		else
> -			ret = -EAGAIN;
> +		}
>  
>  		module_put(t->me);
>  		xt_table_unlock(t);
>  	} else
>  		ret = PTR_ERR(t);
>  
> +out:
> +	/* Allow three retries after the initial nofault copy. */
> +	if (ret == -EFAULT && retries < 3) {
> +		retries++;
> +		goto retry;
> +	}
> +
>  	return ret;
>  }
>  
> diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
> index 809441c..90f4a26 100644
> --- a/net/ipv4/netfilter/ip_tables.c
> +++ b/net/ipv4/netfilter/ip_tables.c
> @@ -21,6 +21,7 @@
>  #include <linux/proc_fs.h>
>  #include <linux/err.h>
>  #include <linux/cpumask.h>
> +#include <linux/pagemap.h>
>  
>  #include <linux/netfilter/x_tables.h>
>  #include <linux/netfilter_ipv4/ip_tables.h>
> @@ -824,6 +825,7 @@ copy_entries_to_user(unsigned int total_size,
>  
>  	loc_cpu_entry = private->entries;
>  
> +	pagefault_disable();
>  	/* FIXME: use iterator macros --RR */
>  	/* ... then go back and fix counters and names */
>  	for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
> @@ -861,6 +863,7 @@ copy_entries_to_user(unsigned int total_size,
>  	}
>  
>   free_counters:
> +	pagefault_enable();
>  	vfree(counters);
>  	return ret;
>  }
> @@ -943,6 +946,7 @@ static int compat_table_info(const struct xt_table_info *info,
>  
>  static int get_info(struct net *net, void __user *user, const int *len)
>  {
> +	struct ipt_getinfo info;
>  	char name[XT_TABLE_MAXNAMELEN];
>  	struct xt_table *t;
>  	int ret;
> @@ -960,7 +964,6 @@ static int get_info(struct net *net, void __user *user, const int *len)
>  #endif
>  	t = xt_request_find_table_lock(net, AF_INET, name);
>  	if (!IS_ERR(t)) {
> -		struct ipt_getinfo info;
>  		const struct xt_table_info *private = t->private;
>  #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
>  		struct xt_table_info tmp;
> @@ -981,10 +984,7 @@ static int get_info(struct net *net, void __user *user, const int *len)
>  		info.size = private->size;
>  		strscpy(info.name, name);
>  
> -		if (copy_to_user(user, &info, *len) != 0)
> -			ret = -EFAULT;
> -		else
> -			ret = 0;
> +		ret = 0;
>  
>  		xt_table_unlock(t);
>  		module_put(t->me);
> @@ -994,6 +994,8 @@ static int get_info(struct net *net, void __user *user, const int *len)
>  	if (in_compat_syscall())
>  		xt_compat_unlock(AF_INET);
>  #endif
> +	if (!ret && copy_to_user(user, &info, *len) != 0)
> +		ret = -EFAULT;
>  	return ret;
>  }
>  
> @@ -1004,6 +1006,7 @@ get_entries(struct net *net, struct ipt_get_entries __user *uptr,
>  	int ret;
>  	struct ipt_get_entries get;
>  	struct xt_table *t;
> +	unsigned int retries = 0;
>  
>  	if (*len < sizeof(get))
>  		return -EINVAL;
> @@ -1013,20 +1016,50 @@ get_entries(struct net *net, struct ipt_get_entries __user *uptr,
>  		return -EINVAL;
>  	get.name[sizeof(get.name) - 1] = '\0';
>  
> +retry:
> +	t = xt_find_table_lock(net, AF_INET, get.name);
> +	if (IS_ERR(t)) {
> +		ret = PTR_ERR(t);
> +		goto out;
> +	}
> +
> +	if (get.size != t->private->size) {
> +		ret = -EAGAIN;
> +		module_put(t->me);
> +		xt_table_unlock(t);
> +		goto out;
> +	}
> +
> +	module_put(t->me);
> +	xt_table_unlock(t);
> +
> +	/* Fault in only after validating the table and requested size. */
> +	if (fault_in_safe_writeable((char __user *)uptr->entrytable,
> +				    get.size))
> +		return -EFAULT;
> +
>  	t = xt_find_table_lock(net, AF_INET, get.name);
>  	if (!IS_ERR(t)) {
>  		const struct xt_table_info *private = t->private;
> -		if (get.size == private->size)
> +		if (get.size != private->size) {
> +			ret = -EAGAIN;
> +		} else {
>  			ret = copy_entries_to_user(private->size,
>  						   t, uptr->entrytable);
> -		else
> -			ret = -EAGAIN;
> +		}
>  
>  		module_put(t->me);
>  		xt_table_unlock(t);
>  	} else
>  		ret = PTR_ERR(t);
>  
> +out:
> +	/* Allow three retries after the initial nofault copy. */
> +	if (ret == -EFAULT && retries < 3) {
> +		retries++;
> +		goto retry;
> +	}
> +
>  	return ret;
>  }
>  
> @@ -1561,12 +1594,14 @@ compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table,
>  
>  	pos = userptr;
>  	size = total_size;
> +	pagefault_disable();
>  	xt_entry_foreach(iter, private->entries, total_size) {
>  		ret = compat_copy_entry_to_user(iter, &pos,
>  						&size, counters, i++);
>  		if (ret != 0)
>  			break;
>  	}
> +	pagefault_enable();
>  
>  	vfree(counters);
>  	return ret;
> @@ -1579,6 +1614,7 @@ compat_get_entries(struct net *net, struct compat_ipt_get_entries __user *uptr,
>  	int ret;
>  	struct compat_ipt_get_entries get;
>  	struct xt_table *t;
> +	unsigned int retries = 0;
>  
>  	if (*len < sizeof(get))
>  		return -EINVAL;
> @@ -1591,6 +1627,32 @@ compat_get_entries(struct net *net, struct compat_ipt_get_entries __user *uptr,
>  
>  	get.name[sizeof(get.name) - 1] = '\0';
>  
> +retry:
> +	xt_compat_lock(AF_INET);
> +	t = xt_find_table_lock(net, AF_INET, get.name);
> +	if (!IS_ERR(t)) {
> +		const struct xt_table_info *private = t->private;
> +		struct xt_table_info info;
> +
> +		ret = compat_table_info(private, &info);
> +		if (!ret && get.size != info.size)
> +			ret = -EAGAIN;
> +
> +		xt_compat_flush_offsets(AF_INET);
> +		module_put(t->me);
> +		xt_table_unlock(t);
> +	} else {
> +		ret = PTR_ERR(t);
> +	}
> +	xt_compat_unlock(AF_INET);
> +	if (ret)
> +		goto out;
> +
> +	/* Fault in only after validating the table and requested size. */
> +	if (fault_in_safe_writeable((char __user *)uptr->entrytable,
> +				    get.size))
> +		return -EFAULT;
> +
>  	xt_compat_lock(AF_INET);
>  	t = xt_find_table_lock(net, AF_INET, get.name);
>  	if (!IS_ERR(t)) {
> @@ -1606,10 +1668,17 @@ compat_get_entries(struct net *net, struct compat_ipt_get_entries __user *uptr,
>  		xt_compat_flush_offsets(AF_INET);
>  		module_put(t->me);
>  		xt_table_unlock(t);
> -	} else
> +	} else {
>  		ret = PTR_ERR(t);
> +	}
>  
>  	xt_compat_unlock(AF_INET);
> +out:
> +	/* Allow three retries after the initial nofault copy. */
> +	if (ret == -EFAULT && retries < 3) {
> +		retries++;
> +		goto retry;
> +	}
>  	return ret;
>  }
>  #endif
> diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
> index f42fb96..4952bfd 100644
> --- a/net/ipv6/netfilter/ip6_tables.c
> +++ b/net/ipv6/netfilter/ip6_tables.c
> @@ -25,6 +25,7 @@
>  #include <linux/proc_fs.h>
>  #include <linux/err.h>
>  #include <linux/cpumask.h>
> +#include <linux/pagemap.h>
>  
>  #include <linux/netfilter_ipv6/ip6_tables.h>
>  #include <linux/netfilter/x_tables.h>
> @@ -840,6 +841,7 @@ copy_entries_to_user(unsigned int total_size,
>  
>  	loc_cpu_entry = private->entries;
>  
> +	pagefault_disable();
>  	/* FIXME: use iterator macros --RR */
>  	/* ... then go back and fix counters and names */
>  	for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
> @@ -877,6 +879,7 @@ copy_entries_to_user(unsigned int total_size,
>  	}
>  
>   free_counters:
> +	pagefault_enable();
>  	vfree(counters);
>  	return ret;
>  }
> @@ -959,6 +962,7 @@ static int compat_table_info(const struct xt_table_info *info,
>  
>  static int get_info(struct net *net, void __user *user, const int *len)
>  {
> +	struct ip6t_getinfo info;
>  	char name[XT_TABLE_MAXNAMELEN];
>  	struct xt_table *t;
>  	int ret;
> @@ -976,7 +980,6 @@ static int get_info(struct net *net, void __user *user, const int *len)
>  #endif
>  	t = xt_request_find_table_lock(net, AF_INET6, name);
>  	if (!IS_ERR(t)) {
> -		struct ip6t_getinfo info;
>  		const struct xt_table_info *private = t->private;
>  #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
>  		struct xt_table_info tmp;
> @@ -997,10 +1000,7 @@ static int get_info(struct net *net, void __user *user, const int *len)
>  		info.size = private->size;
>  		strcpy(info.name, name);
>  
> -		if (copy_to_user(user, &info, *len) != 0)
> -			ret = -EFAULT;
> -		else
> -			ret = 0;
> +		ret = 0;
>  
>  		xt_table_unlock(t);
>  		module_put(t->me);
> @@ -1010,6 +1010,8 @@ static int get_info(struct net *net, void __user *user, const int *len)
>  	if (in_compat_syscall())
>  		xt_compat_unlock(AF_INET6);
>  #endif
> +	if (!ret && copy_to_user(user, &info, *len) != 0)
> +		ret = -EFAULT;
>  	return ret;
>  }
>  
> @@ -1020,6 +1022,7 @@ get_entries(struct net *net, struct ip6t_get_entries __user *uptr,
>  	int ret;
>  	struct ip6t_get_entries get;
>  	struct xt_table *t;
> +	unsigned int retries = 0;
>  
>  	if (*len < sizeof(get))
>  		return -EINVAL;
> @@ -1030,20 +1033,50 @@ get_entries(struct net *net, struct ip6t_get_entries __user *uptr,
>  
>  	get.name[sizeof(get.name) - 1] = '\0';
>  
> +retry:
> +	t = xt_find_table_lock(net, AF_INET6, get.name);
> +	if (IS_ERR(t)) {
> +		ret = PTR_ERR(t);
> +		goto out;
> +	}
> +
> +	if (get.size != t->private->size) {
> +		ret = -EAGAIN;
> +		module_put(t->me);
> +		xt_table_unlock(t);
> +		goto out;
> +	}
> +
> +	module_put(t->me);
> +	xt_table_unlock(t);
> +
> +	/* Fault in only after validating the table and requested size. */
> +	if (fault_in_safe_writeable((char __user *)uptr->entrytable,
> +				    get.size))
> +		return -EFAULT;
> +
>  	t = xt_find_table_lock(net, AF_INET6, get.name);
>  	if (!IS_ERR(t)) {
>  		struct xt_table_info *private = t->private;
> -		if (get.size == private->size)
> +		if (get.size != private->size) {
> +			ret = -EAGAIN;
> +		} else {
>  			ret = copy_entries_to_user(private->size,
>  						   t, uptr->entrytable);
> -		else
> -			ret = -EAGAIN;
> +		}
>  
>  		module_put(t->me);
>  		xt_table_unlock(t);
>  	} else
>  		ret = PTR_ERR(t);
>  
> +out:
> +	/* Allow three retries after the initial nofault copy. */
> +	if (ret == -EFAULT && retries < 3) {
> +		retries++;
> +		goto retry;
> +	}
> +
>  	return ret;
>  }
>  
> @@ -1570,12 +1603,14 @@ compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table,
>  
>  	pos = userptr;
>  	size = total_size;
> +	pagefault_disable();
>  	xt_entry_foreach(iter, private->entries, total_size) {
>  		ret = compat_copy_entry_to_user(iter, &pos,
>  						&size, counters, i++);
>  		if (ret != 0)
>  			break;
>  	}
> +	pagefault_enable();
>  
>  	vfree(counters);
>  	return ret;
> @@ -1588,6 +1623,7 @@ compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr,
>  	int ret;
>  	struct compat_ip6t_get_entries get;
>  	struct xt_table *t;
> +	unsigned int retries = 0;
>  
>  	if (*len < sizeof(get))
>  		return -EINVAL;
> @@ -1600,6 +1636,32 @@ compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr,
>  
>  	get.name[sizeof(get.name) - 1] = '\0';
>  
> +retry:
> +	xt_compat_lock(AF_INET6);
> +	t = xt_find_table_lock(net, AF_INET6, get.name);
> +	if (!IS_ERR(t)) {
> +		const struct xt_table_info *private = t->private;
> +		struct xt_table_info info;
> +
> +		ret = compat_table_info(private, &info);
> +		if (!ret && get.size != info.size)
> +			ret = -EAGAIN;
> +
> +		xt_compat_flush_offsets(AF_INET6);
> +		module_put(t->me);
> +		xt_table_unlock(t);
> +	} else {
> +		ret = PTR_ERR(t);
> +	}
> +	xt_compat_unlock(AF_INET6);
> +	if (ret)
> +		goto out;
> +
> +	/* Fault in only after validating the table and requested size. */
> +	if (fault_in_safe_writeable((char __user *)uptr->entrytable,
> +				    get.size))
> +		return -EFAULT;
> +
>  	xt_compat_lock(AF_INET6);
>  	t = xt_find_table_lock(net, AF_INET6, get.name);
>  	if (!IS_ERR(t)) {
> @@ -1615,10 +1677,17 @@ compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr,
>  		xt_compat_flush_offsets(AF_INET6);
>  		module_put(t->me);
>  		xt_table_unlock(t);
> -	} else
> +	} else {
>  		ret = PTR_ERR(t);
> +	}
>  
>  	xt_compat_unlock(AF_INET6);
> +out:
> +	/* Allow three retries after the initial nofault copy. */
> +	if (ret == -EFAULT && retries < 3) {
> +		retries++;
> +		goto retry;
> +	}
>  	return ret;
>  }
>  #endif
> -- 
> 2.55.0.windows.3
> 
> 

  reply	other threads:[~2026-10-08 23:54 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-20 11:58 [PATCH nf v3 0/1] netfilter: x_tables: avoid holding mutex over faultable user copies Zihan Xi
2026-09-20 11:58 ` [PATCH nf v3 1/1] " Zihan Xi
2026-10-08 23:54   ` Pablo Neira Ayuso [this message]
2026-10-09  0:07     ` Florian Westphal
2026-10-09  0:14       ` Pablo Neira Ayuso
2026-10-09  1:09         ` zihan xi

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=asgtQ3E2LVWqfV8D@chamomile \
    --to=pablo@netfilter.org \
    --cc=coreteam@netfilter.org \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=fw@strlen.de \
    --cc=horms@kernel.org \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=netfilter-devel@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=phil@nwl.cc \
    --cc=zihanx@nebusec.ai \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.