public inbox for linux-fsdevel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next] net: datagram: Bypass usercopy checks for kernel iterators
@ 2026-02-25 16:25 Chuck Lever
  2026-02-28  3:19 ` Jakub Kicinski
  0 siblings, 1 reply; 4+ messages in thread
From: Chuck Lever @ 2026-02-25 16:25 UTC (permalink / raw)
  To: davem, edumazet, kuba, pabeni
  Cc: David Howells, netdev, linux-fsdevel, Chuck Lever

From: Chuck Lever <chuck.lever@oracle.com>

Profiling NFSD under an iozone workload showed that hardened
usercopy checks consume roughly 1.3% of CPU in the TCP receive path.
These checks validate memory regions during copies, but provide no
security benefit when both source (skb data) and destination (kernel
pages in BVEC/KVEC iterators) reside in kernel address space.

Modify simple_copy_to_iter() and crc32c_and_copy_to_iter() to call
_copy_to_iter() directly when the destination is a kernel-only
iterator, bypassing the usercopy hardening validation. User-backed
iterators (ITER_UBUF, ITER_IOVEC) continue to use copy_to_iter()
with full validation.

This benefits kernel consumers of TCP receive such as the NFS client
and server and NVMe-TCP, which use ITER_BVEC for their receive
buffers.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 net/core/datagram.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/net/core/datagram.c b/net/core/datagram.c
index c285c6465923..e83cf0125008 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -490,7 +490,10 @@ static size_t crc32c_and_copy_to_iter(const void *addr, size_t bytes,
 	u32 *crcp = _crcp;
 	size_t copied;
 
-	copied = copy_to_iter(addr, bytes, i);
+	if (user_backed_iter(i))
+		copied = copy_to_iter(addr, bytes, i);
+	else
+		copied = _copy_to_iter(addr, bytes, i);
 	*crcp = crc32c(*crcp, addr, copied);
 	return copied;
 }
@@ -515,10 +518,17 @@ int skb_copy_and_crc32c_datagram_iter(const struct sk_buff *skb, int offset,
 EXPORT_SYMBOL(skb_copy_and_crc32c_datagram_iter);
 #endif /* CONFIG_NET_CRC32C */
 
+/*
+ * Bypass usercopy hardening for kernel-only iterators: no data
+ * crosses the user/kernel boundary, so the slab whitelist check
+ * on the source buffer is unnecessary overhead.
+ */
 static size_t simple_copy_to_iter(const void *addr, size_t bytes,
 		void *data __always_unused, struct iov_iter *i)
 {
-	return copy_to_iter(addr, bytes, i);
+	if (user_backed_iter(i))
+		return copy_to_iter(addr, bytes, i);
+	return _copy_to_iter(addr, bytes, i);
 }
 
 /**
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH net-next] net: datagram: Bypass usercopy checks for kernel iterators
  2026-02-25 16:25 [PATCH net-next] net: datagram: Bypass usercopy checks for kernel iterators Chuck Lever
@ 2026-02-28  3:19 ` Jakub Kicinski
  0 siblings, 0 replies; 4+ messages in thread
From: Jakub Kicinski @ 2026-02-28  3:19 UTC (permalink / raw)
  To: Chuck Lever
  Cc: davem, edumazet, pabeni, David Howells, netdev, linux-fsdevel,
	Chuck Lever, Alexander Viro, linux-block

On Wed, 25 Feb 2026 11:25:32 -0500 Chuck Lever wrote:
> From: Chuck Lever <chuck.lever@oracle.com>
> 
> Profiling NFSD under an iozone workload showed that hardened
> usercopy checks consume roughly 1.3% of CPU in the TCP receive path.
> These checks validate memory regions during copies, but provide no
> security benefit when both source (skb data) and destination (kernel
> pages in BVEC/KVEC iterators) reside in kernel address space.
> 
> Modify simple_copy_to_iter() and crc32c_and_copy_to_iter() to call
> _copy_to_iter() directly when the destination is a kernel-only
> iterator, bypassing the usercopy hardening validation. User-backed
> iterators (ITER_UBUF, ITER_IOVEC) continue to use copy_to_iter()
> with full validation.
> 
> This benefits kernel consumers of TCP receive such as the NFS client
> and server and NVMe-TCP, which use ITER_BVEC for their receive
> buffers.

If it makes such a difference why not make copy_to_iter()
check the iter type? Why force callers to check it?

> diff --git a/net/core/datagram.c b/net/core/datagram.c
> index c285c6465923..e83cf0125008 100644
> --- a/net/core/datagram.c
> +++ b/net/core/datagram.c
> @@ -490,7 +490,10 @@ static size_t crc32c_and_copy_to_iter(const void *addr, size_t bytes,
>  	u32 *crcp = _crcp;
>  	size_t copied;
>  
> -	copied = copy_to_iter(addr, bytes, i);
> +	if (user_backed_iter(i))
> +		copied = copy_to_iter(addr, bytes, i);
> +	else
> +		copied = _copy_to_iter(addr, bytes, i);
>  	*crcp = crc32c(*crcp, addr, copied);
>  	return copied;
>  }
> @@ -515,10 +518,17 @@ int skb_copy_and_crc32c_datagram_iter(const struct sk_buff *skb, int offset,
>  EXPORT_SYMBOL(skb_copy_and_crc32c_datagram_iter);
>  #endif /* CONFIG_NET_CRC32C */
>  
> +/*
> + * Bypass usercopy hardening for kernel-only iterators: no data
> + * crosses the user/kernel boundary, so the slab whitelist check
> + * on the source buffer is unnecessary overhead.
> + */
>  static size_t simple_copy_to_iter(const void *addr, size_t bytes,
>  		void *data __always_unused, struct iov_iter *i)
>  {
> -	return copy_to_iter(addr, bytes, i);
> +	if (user_backed_iter(i))
> +		return copy_to_iter(addr, bytes, i);
> +	return _copy_to_iter(addr, bytes, i);
>  }
>  
>  /**


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH net-next] net: datagram: Bypass usercopy checks for kernel iterators
@ 2026-03-03  9:42 Paolo Abeni
  2026-03-03 15:53 ` Chuck Lever
  0 siblings, 1 reply; 4+ messages in thread
From: Paolo Abeni @ 2026-03-03  9:42 UTC (permalink / raw)
  To: Chuck Lever, David S. Miller, Eric Dumazet, Jakub Kicinski
  Cc: David Howells, Network Development,
	open list:FILESYSTEMS (VFS and infrastructure), Chuck Lever

On 2/25/26 5:25 PM, Chuck Lever wrote:
> From: Chuck Lever <chuck.lever@oracle.com>
>
> Profiling NFSD under an iozone workload showed that hardened
> usercopy checks consume roughly 1.3% of CPU in the TCP receive path.
> These checks validate memory regions during copies, but provide no
> security benefit when both source (skb data) and destination (kernel
> pages in BVEC/KVEC iterators) reside in kernel address space.

Are you sure? AFAICS:

size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i)
{
        if (check_copy_size(addr, bytes, false))
                return _copy_from_iter(addr, bytes, i);

calls check_copy_size() on the source address, and the latter:

static __always_inline __must_check bool
check_copy_size(const void *addr, size_t bytes, bool is_source)
{
        int sz = __builtin_object_size(addr, 0);
        if (unlikely(sz >= 0 && sz < bytes)) {
        if (!__builtin_constant_p(bytes))
                        copy_overflow(sz, bytes);
                else if (is_source)$
                        __bad_copy_from();
                else
                        __bad_copy_to();
                return false;
        }
        if (WARN_ON_ONCE(bytes > INT_MAX))
                return false;

Validates vs overflow regardless of the source address being in kernel
space or user-space.

FTR, I also observe a relevant overhead in check_copy_size(), especially
for oldish CPUs.

/P


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH net-next] net: datagram: Bypass usercopy checks for kernel iterators
  2026-03-03  9:42 Paolo Abeni
@ 2026-03-03 15:53 ` Chuck Lever
  0 siblings, 0 replies; 4+ messages in thread
From: Chuck Lever @ 2026-03-03 15:53 UTC (permalink / raw)
  To: Paolo Abeni, David S. Miller, Eric Dumazet, Jakub Kicinski
  Cc: David Howells, Network Development,
	open list:FILESYSTEMS (VFS and infrastructure), Chuck Lever



On Tue, Mar 3, 2026, at 4:42 AM, Paolo Abeni wrote:
> On 2/25/26 5:25 PM, Chuck Lever wrote:
>> From: Chuck Lever <chuck.lever@oracle.com>
>>
>> Profiling NFSD under an iozone workload showed that hardened
>> usercopy checks consume roughly 1.3% of CPU in the TCP receive path.
>> These checks validate memory regions during copies, but provide no
>> security benefit when both source (skb data) and destination (kernel
>> pages in BVEC/KVEC iterators) reside in kernel address space.
>
> Are you sure? AFAICS:
>
> size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i)
> {
>         if (check_copy_size(addr, bytes, false))
>                 return _copy_from_iter(addr, bytes, i);
>
> calls check_copy_size() on the source address, and the latter:
>
> static __always_inline __must_check bool
> check_copy_size(const void *addr, size_t bytes, bool is_source)
> {
>         int sz = __builtin_object_size(addr, 0);
>         if (unlikely(sz >= 0 && sz < bytes)) {
>         if (!__builtin_constant_p(bytes))
>                         copy_overflow(sz, bytes);
>                 else if (is_source)$
>                         __bad_copy_from();
>                 else
>                         __bad_copy_to();
>                 return false;
>         }
>         if (WARN_ON_ONCE(bytes > INT_MAX))
>                 return false;
>
> Validates vs overflow regardless of the source address being in kernel
> space or user-space.
>
> FTR, I also observe a relevant overhead in check_copy_size(), especially
> for oldish CPUs.
>
> /P

Paolo, thanks for the review. I'll post a refreshed patch shortly that
attempts to address your comments, and that modifies the common helper,
as Jakub suggested earlier.


-- 
Chuck Lever

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-03-03 15:54 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-25 16:25 [PATCH net-next] net: datagram: Bypass usercopy checks for kernel iterators Chuck Lever
2026-02-28  3:19 ` Jakub Kicinski
  -- strict thread matches above, loose matches on Subject: below --
2026-03-03  9:42 Paolo Abeni
2026-03-03 15:53 ` Chuck Lever

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox