All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] SUNRPC: Fix use-after-free in svc_age_temp_xprts_now()
@ 2026-10-22 20:53 Chuck Lever
  2026-10-23  2:13 ` NeilBrown
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Chuck Lever @ 2026-10-22 20:53 UTC (permalink / raw)
  To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
  Cc: linux-nfs, Mohammed Alquraini

svc_age_temp_xprts_now() moves each matching temporary transport
onto a local list under sv_lock, then drops the lock and walks the
local list without holding a reference on any of them. In the
meantime svc_delete_xprt() can take sv_lock, unlink the same
xpt_list node, and drop the transport's last reference. An idle
temporary transport holds only that one reference, so a peer FIN
that arrives between the two loops frees the svc_sock out from under
the second loop. The notifier then sets XPT_CLOSE in freed memory,
and svc_xprt_enqueue() reads xpt_flags and xpt_server from the freed
object and queues that object on a pool for an nfsd thread. KASAN
reports a slab-use-after-free in svc_xprt_enqueue() under
nfsd_inetaddr_event(), with the object freed by svc_sock_free() on
an nfsd thread.

The two-phase walk dates from when the second loop called into the
socket layer and could sleep. Commit 546125d16142 ("sunrpc: don't
call sleeping functions from the notifier block callbacks") moved
that work to the nfsd threads, so nothing left in the second loop
needs sv_lock dropped. Mark and enqueue each matching transport
under sv_lock in a single pass, as svc_age_temp_xprts() already
does, so that svc_delete_xprt() cannot unlink and free a transport
the notifier is still touching.

Fixes: c3d4879e01be ("sunrpc: Add a function to close temporary transports immediately")
Reported-by: Mohammed Alquraini <mohammed.saad.alquraini@gmail.com>
Signed-off-by: Chuck Lever <cel@kernel.org>
---
 net/sunrpc/svc_xprt.c | 16 ++++------------
 1 file changed, 4 insertions(+), 12 deletions(-)

Mohammed, thanks for the report. Please test and report your results.

diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
index 5db42e53be62..076c624fe675 100644
--- a/net/sunrpc/svc_xprt.c
+++ b/net/sunrpc/svc_xprt.c
@@ -1075,29 +1075,21 @@ void svc_age_temp_xprts_now(struct svc_serv *serv, struct sockaddr *server_addr)
 {
 	struct svc_xprt *xprt;
 	struct list_head *le, *next;
-	LIST_HEAD(to_be_closed);
 
 	spin_lock_bh(&serv->sv_lock);
 	list_for_each_safe(le, next, &serv->sv_tempsocks) {
 		xprt = list_entry(le, struct svc_xprt, xpt_list);
-		if (rpc_cmp_addr(server_addr, (struct sockaddr *)
-				&xprt->xpt_local)) {
-			dprintk("svc_age_temp_xprts_now: found %p\n", xprt);
-			list_move(le, &to_be_closed);
-		}
-	}
-	spin_unlock_bh(&serv->sv_lock);
-
-	while (!list_empty(&to_be_closed)) {
-		le = to_be_closed.next;
+		if (!rpc_cmp_addr(server_addr, (struct sockaddr *)
+				&xprt->xpt_local))
+			continue;
 		list_del_init(le);
-		xprt = list_entry(le, struct svc_xprt, xpt_list);
 		set_bit(XPT_CLOSE, &xprt->xpt_flags);
 		set_bit(XPT_KILL_TEMP, &xprt->xpt_flags);
 		dprintk("svc_age_temp_xprts_now: queuing xprt %p for closing\n",
 				xprt);
 		svc_xprt_enqueue(xprt);
 	}
+	spin_unlock_bh(&serv->sv_lock);
 }
 EXPORT_SYMBOL_GPL(svc_age_temp_xprts_now);
 
-- 
2.54.0


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

* Re: [PATCH] SUNRPC: Fix use-after-free in svc_age_temp_xprts_now()
  2026-10-22 20:53 [PATCH] SUNRPC: Fix use-after-free in svc_age_temp_xprts_now() Chuck Lever
@ 2026-10-23  2:13 ` NeilBrown
  2026-10-26 10:30 ` Mohammed
  2026-10-26 11:44 ` Jeff Layton
  2 siblings, 0 replies; 6+ messages in thread
From: NeilBrown @ 2026-10-23  2:13 UTC (permalink / raw)
  To: Chuck Lever
  Cc: Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey, linux-nfs,
	Mohammed Alquraini

On Fri, 23 Oct 2026, Chuck Lever wrote:
> svc_age_temp_xprts_now() moves each matching temporary transport
> onto a local list under sv_lock, then drops the lock and walks the
> local list without holding a reference on any of them. In the
> meantime svc_delete_xprt() can take sv_lock, unlink the same
> xpt_list node, and drop the transport's last reference. An idle
> temporary transport holds only that one reference, so a peer FIN
> that arrives between the two loops frees the svc_sock out from under
> the second loop. The notifier then sets XPT_CLOSE in freed memory,
> and svc_xprt_enqueue() reads xpt_flags and xpt_server from the freed
> object and queues that object on a pool for an nfsd thread. KASAN
> reports a slab-use-after-free in svc_xprt_enqueue() under
> nfsd_inetaddr_event(), with the object freed by svc_sock_free() on
> an nfsd thread.
> 
> The two-phase walk dates from when the second loop called into the
> socket layer and could sleep. Commit 546125d16142 ("sunrpc: don't
> call sleeping functions from the notifier block callbacks") moved
> that work to the nfsd threads, so nothing left in the second loop
> needs sv_lock dropped. Mark and enqueue each matching transport
> under sv_lock in a single pass, as svc_age_temp_xprts() already
> does, so that svc_delete_xprt() cannot unlink and free a transport
> the notifier is still touching.
> 
> Fixes: c3d4879e01be ("sunrpc: Add a function to close temporary transports immediately")
> Reported-by: Mohammed Alquraini <mohammed.saad.alquraini@gmail.com>
> Signed-off-by: Chuck Lever <cel@kernel.org>

Reviewed-by: NeilBrown <neil@brown.name>

Everything being moved into the locked region is safe in that context,
so this is a nice simplification as well as being a bug-fix.

Thanks,
NeilBrown


> ---
>  net/sunrpc/svc_xprt.c | 16 ++++------------
>  1 file changed, 4 insertions(+), 12 deletions(-)
> 
> Mohammed, thanks for the report. Please test and report your results.
> 
> diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
> index 5db42e53be62..076c624fe675 100644
> --- a/net/sunrpc/svc_xprt.c
> +++ b/net/sunrpc/svc_xprt.c
> @@ -1075,29 +1075,21 @@ void svc_age_temp_xprts_now(struct svc_serv *serv, struct sockaddr *server_addr)
>  {
>  	struct svc_xprt *xprt;
>  	struct list_head *le, *next;
> -	LIST_HEAD(to_be_closed);
>  
>  	spin_lock_bh(&serv->sv_lock);
>  	list_for_each_safe(le, next, &serv->sv_tempsocks) {
>  		xprt = list_entry(le, struct svc_xprt, xpt_list);
> -		if (rpc_cmp_addr(server_addr, (struct sockaddr *)
> -				&xprt->xpt_local)) {
> -			dprintk("svc_age_temp_xprts_now: found %p\n", xprt);
> -			list_move(le, &to_be_closed);
> -		}
> -	}
> -	spin_unlock_bh(&serv->sv_lock);
> -
> -	while (!list_empty(&to_be_closed)) {
> -		le = to_be_closed.next;
> +		if (!rpc_cmp_addr(server_addr, (struct sockaddr *)
> +				&xprt->xpt_local))
> +			continue;
>  		list_del_init(le);
> -		xprt = list_entry(le, struct svc_xprt, xpt_list);
>  		set_bit(XPT_CLOSE, &xprt->xpt_flags);
>  		set_bit(XPT_KILL_TEMP, &xprt->xpt_flags);
>  		dprintk("svc_age_temp_xprts_now: queuing xprt %p for closing\n",
>  				xprt);
>  		svc_xprt_enqueue(xprt);
>  	}
> +	spin_unlock_bh(&serv->sv_lock);
>  }
>  EXPORT_SYMBOL_GPL(svc_age_temp_xprts_now);
>  
> -- 
> 2.54.0
> 
> 


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

* Re: [PATCH] SUNRPC: Fix use-after-free in svc_age_temp_xprts_now()
  2026-10-22 20:53 [PATCH] SUNRPC: Fix use-after-free in svc_age_temp_xprts_now() Chuck Lever
  2026-10-23  2:13 ` NeilBrown
@ 2026-10-26 10:30 ` Mohammed
  2026-10-26 13:05   ` Chuck Lever
  2026-10-26 11:44 ` Jeff Layton
  2 siblings, 1 reply; 6+ messages in thread
From: Mohammed @ 2026-10-26 10:30 UTC (permalink / raw)
  To: Chuck Lever
  Cc: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey,
	linux-nfs

Hi Chuck,

This patch fixes the issue.

Thanks for the quick response and fix!

Best,
Mohammed

On Thu, Oct 22, 2026 at 11:54 PM Chuck Lever <cel@kernel.org> wrote:
>
> svc_age_temp_xprts_now() moves each matching temporary transport
> onto a local list under sv_lock, then drops the lock and walks the
> local list without holding a reference on any of them. In the
> meantime svc_delete_xprt() can take sv_lock, unlink the same
> xpt_list node, and drop the transport's last reference. An idle
> temporary transport holds only that one reference, so a peer FIN
> that arrives between the two loops frees the svc_sock out from under
> the second loop. The notifier then sets XPT_CLOSE in freed memory,
> and svc_xprt_enqueue() reads xpt_flags and xpt_server from the freed
> object and queues that object on a pool for an nfsd thread. KASAN
> reports a slab-use-after-free in svc_xprt_enqueue() under
> nfsd_inetaddr_event(), with the object freed by svc_sock_free() on
> an nfsd thread.
>
> The two-phase walk dates from when the second loop called into the
> socket layer and could sleep. Commit 546125d16142 ("sunrpc: don't
> call sleeping functions from the notifier block callbacks") moved
> that work to the nfsd threads, so nothing left in the second loop
> needs sv_lock dropped. Mark and enqueue each matching transport
> under sv_lock in a single pass, as svc_age_temp_xprts() already
> does, so that svc_delete_xprt() cannot unlink and free a transport
> the notifier is still touching.
>
> Fixes: c3d4879e01be ("sunrpc: Add a function to close temporary transports immediately")
> Reported-by: Mohammed Alquraini <mohammed.saad.alquraini@gmail.com>
> Signed-off-by: Chuck Lever <cel@kernel.org>
> ---
>  net/sunrpc/svc_xprt.c | 16 ++++------------
>  1 file changed, 4 insertions(+), 12 deletions(-)
>
> Mohammed, thanks for the report. Please test and report your results.
>
> diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
> index 5db42e53be62..076c624fe675 100644
> --- a/net/sunrpc/svc_xprt.c
> +++ b/net/sunrpc/svc_xprt.c
> @@ -1075,29 +1075,21 @@ void svc_age_temp_xprts_now(struct svc_serv *serv, struct sockaddr *server_addr)
>  {
>         struct svc_xprt *xprt;
>         struct list_head *le, *next;
> -       LIST_HEAD(to_be_closed);
>
>         spin_lock_bh(&serv->sv_lock);
>         list_for_each_safe(le, next, &serv->sv_tempsocks) {
>                 xprt = list_entry(le, struct svc_xprt, xpt_list);
> -               if (rpc_cmp_addr(server_addr, (struct sockaddr *)
> -                               &xprt->xpt_local)) {
> -                       dprintk("svc_age_temp_xprts_now: found %p\n", xprt);
> -                       list_move(le, &to_be_closed);
> -               }
> -       }
> -       spin_unlock_bh(&serv->sv_lock);
> -
> -       while (!list_empty(&to_be_closed)) {
> -               le = to_be_closed.next;
> +               if (!rpc_cmp_addr(server_addr, (struct sockaddr *)
> +                               &xprt->xpt_local))
> +                       continue;
>                 list_del_init(le);
> -               xprt = list_entry(le, struct svc_xprt, xpt_list);
>                 set_bit(XPT_CLOSE, &xprt->xpt_flags);
>                 set_bit(XPT_KILL_TEMP, &xprt->xpt_flags);
>                 dprintk("svc_age_temp_xprts_now: queuing xprt %p for closing\n",
>                                 xprt);
>                 svc_xprt_enqueue(xprt);
>         }
> +       spin_unlock_bh(&serv->sv_lock);
>  }
>  EXPORT_SYMBOL_GPL(svc_age_temp_xprts_now);
>
> --
> 2.54.0
>

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

* Re: [PATCH] SUNRPC: Fix use-after-free in svc_age_temp_xprts_now()
  2026-10-22 20:53 [PATCH] SUNRPC: Fix use-after-free in svc_age_temp_xprts_now() Chuck Lever
  2026-10-23  2:13 ` NeilBrown
  2026-10-26 10:30 ` Mohammed
@ 2026-10-26 11:44 ` Jeff Layton
  2 siblings, 0 replies; 6+ messages in thread
From: Jeff Layton @ 2026-10-26 11:44 UTC (permalink / raw)
  To: Chuck Lever, NeilBrown, Olga Kornievskaia, Dai Ngo, Tom Talpey
  Cc: linux-nfs, Mohammed Alquraini

On Thu, 2026-10-22 at 16:53 -0400, Chuck Lever wrote:
> svc_age_temp_xprts_now() moves each matching temporary transport
> onto a local list under sv_lock, then drops the lock and walks the
> local list without holding a reference on any of them. In the
> meantime svc_delete_xprt() can take sv_lock, unlink the same
> xpt_list node, and drop the transport's last reference. An idle
> temporary transport holds only that one reference, so a peer FIN
> that arrives between the two loops frees the svc_sock out from under
> the second loop. The notifier then sets XPT_CLOSE in freed memory,
> and svc_xprt_enqueue() reads xpt_flags and xpt_server from the freed
> object and queues that object on a pool for an nfsd thread. KASAN
> reports a slab-use-after-free in svc_xprt_enqueue() under
> nfsd_inetaddr_event(), with the object freed by svc_sock_free() on
> an nfsd thread.
> 
> The two-phase walk dates from when the second loop called into the
> socket layer and could sleep. Commit 546125d16142 ("sunrpc: don't
> call sleeping functions from the notifier block callbacks") moved
> that work to the nfsd threads, so nothing left in the second loop
> needs sv_lock dropped. Mark and enqueue each matching transport
> under sv_lock in a single pass, as svc_age_temp_xprts() already
> does, so that svc_delete_xprt() cannot unlink and free a transport
> the notifier is still touching.
> 
> Fixes: c3d4879e01be ("sunrpc: Add a function to close temporary transports immediately")
> Reported-by: Mohammed Alquraini <mohammed.saad.alquraini@gmail.com>
> Signed-off-by: Chuck Lever <cel@kernel.org>
> ---
>  net/sunrpc/svc_xprt.c | 16 ++++------------
>  1 file changed, 4 insertions(+), 12 deletions(-)
> 
> Mohammed, thanks for the report. Please test and report your results.
> 
> diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
> index 5db42e53be62..076c624fe675 100644
> --- a/net/sunrpc/svc_xprt.c
> +++ b/net/sunrpc/svc_xprt.c
> @@ -1075,29 +1075,21 @@ void svc_age_temp_xprts_now(struct svc_serv *serv, struct sockaddr *server_addr)
>  {
>  	struct svc_xprt *xprt;
>  	struct list_head *le, *next;
> -	LIST_HEAD(to_be_closed);
>  
>  	spin_lock_bh(&serv->sv_lock);
>  	list_for_each_safe(le, next, &serv->sv_tempsocks) {
>  		xprt = list_entry(le, struct svc_xprt, xpt_list);
> -		if (rpc_cmp_addr(server_addr, (struct sockaddr *)
> -				&xprt->xpt_local)) {
> -			dprintk("svc_age_temp_xprts_now: found %p\n", xprt);
> -			list_move(le, &to_be_closed);
> -		}
> -	}
> -	spin_unlock_bh(&serv->sv_lock);
> -
> -	while (!list_empty(&to_be_closed)) {
> -		le = to_be_closed.next;
> +		if (!rpc_cmp_addr(server_addr, (struct sockaddr *)
> +				&xprt->xpt_local))
> +			continue;
>  		list_del_init(le);
> -		xprt = list_entry(le, struct svc_xprt, xpt_list);
>  		set_bit(XPT_CLOSE, &xprt->xpt_flags);
>  		set_bit(XPT_KILL_TEMP, &xprt->xpt_flags);
>  		dprintk("svc_age_temp_xprts_now: queuing xprt %p for closing\n",
>  				xprt);
>  		svc_xprt_enqueue(xprt);
>  	}
> +	spin_unlock_bh(&serv->sv_lock);
>  }
>  EXPORT_SYMBOL_GPL(svc_age_temp_xprts_now);
>  

Reviewed-by: Jeff Layton <jlayton@kernel.org>

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

* Re: [PATCH] SUNRPC: Fix use-after-free in svc_age_temp_xprts_now()
  2026-10-26 10:30 ` Mohammed
@ 2026-10-26 13:05   ` Chuck Lever
  2026-10-26 13:39     ` Mohammed
  0 siblings, 1 reply; 6+ messages in thread
From: Chuck Lever @ 2026-10-26 13:05 UTC (permalink / raw)
  To: Mohammed
  Cc: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey,
	linux-nfs



On Mon, Oct 26, 2026, at 6:30 AM, Mohammed wrote:
> Hi Chuck,
>
> This patch fixes the issue.
>
> Thanks for the quick response and fix!

May I add:

Tested-by: Mohammed <mohammed.saad.alquraini@gmail.com>

?

> Best,
> Mohammed
>
> On Thu, Oct 22, 2026 at 11:54 PM Chuck Lever <cel@kernel.org> wrote:
>>
>> svc_age_temp_xprts_now() moves each matching temporary transport
>> onto a local list under sv_lock, then drops the lock and walks the
>> local list without holding a reference on any of them. In the
>> meantime svc_delete_xprt() can take sv_lock, unlink the same
>> xpt_list node, and drop the transport's last reference. An idle
>> temporary transport holds only that one reference, so a peer FIN
>> that arrives between the two loops frees the svc_sock out from under
>> the second loop. The notifier then sets XPT_CLOSE in freed memory,
>> and svc_xprt_enqueue() reads xpt_flags and xpt_server from the freed
>> object and queues that object on a pool for an nfsd thread. KASAN
>> reports a slab-use-after-free in svc_xprt_enqueue() under
>> nfsd_inetaddr_event(), with the object freed by svc_sock_free() on
>> an nfsd thread.
>>
>> The two-phase walk dates from when the second loop called into the
>> socket layer and could sleep. Commit 546125d16142 ("sunrpc: don't
>> call sleeping functions from the notifier block callbacks") moved
>> that work to the nfsd threads, so nothing left in the second loop
>> needs sv_lock dropped. Mark and enqueue each matching transport
>> under sv_lock in a single pass, as svc_age_temp_xprts() already
>> does, so that svc_delete_xprt() cannot unlink and free a transport
>> the notifier is still touching.
>>
>> Fixes: c3d4879e01be ("sunrpc: Add a function to close temporary transports immediately")
>> Reported-by: Mohammed Alquraini <mohammed.saad.alquraini@gmail.com>
>> Signed-off-by: Chuck Lever <cel@kernel.org>
>> ---
>>  net/sunrpc/svc_xprt.c | 16 ++++------------
>>  1 file changed, 4 insertions(+), 12 deletions(-)
>>
>> Mohammed, thanks for the report. Please test and report your results.
>>
>> diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
>> index 5db42e53be62..076c624fe675 100644
>> --- a/net/sunrpc/svc_xprt.c
>> +++ b/net/sunrpc/svc_xprt.c
>> @@ -1075,29 +1075,21 @@ void svc_age_temp_xprts_now(struct svc_serv *serv, struct sockaddr *server_addr)
>>  {
>>         struct svc_xprt *xprt;
>>         struct list_head *le, *next;
>> -       LIST_HEAD(to_be_closed);
>>
>>         spin_lock_bh(&serv->sv_lock);
>>         list_for_each_safe(le, next, &serv->sv_tempsocks) {
>>                 xprt = list_entry(le, struct svc_xprt, xpt_list);
>> -               if (rpc_cmp_addr(server_addr, (struct sockaddr *)
>> -                               &xprt->xpt_local)) {
>> -                       dprintk("svc_age_temp_xprts_now: found %p\n", xprt);
>> -                       list_move(le, &to_be_closed);
>> -               }
>> -       }
>> -       spin_unlock_bh(&serv->sv_lock);
>> -
>> -       while (!list_empty(&to_be_closed)) {
>> -               le = to_be_closed.next;
>> +               if (!rpc_cmp_addr(server_addr, (struct sockaddr *)
>> +                               &xprt->xpt_local))
>> +                       continue;
>>                 list_del_init(le);
>> -               xprt = list_entry(le, struct svc_xprt, xpt_list);
>>                 set_bit(XPT_CLOSE, &xprt->xpt_flags);
>>                 set_bit(XPT_KILL_TEMP, &xprt->xpt_flags);
>>                 dprintk("svc_age_temp_xprts_now: queuing xprt %p for closing\n",
>>                                 xprt);
>>                 svc_xprt_enqueue(xprt);
>>         }
>> +       spin_unlock_bh(&serv->sv_lock);
>>  }
>>  EXPORT_SYMBOL_GPL(svc_age_temp_xprts_now);
>>
>> --
>> 2.54.0
>>

-- 
Chuck Lever (Come to NFS bake-a-thon! https://nfsv4bat.org)

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

* Re: [PATCH] SUNRPC: Fix use-after-free in svc_age_temp_xprts_now()
  2026-10-26 13:05   ` Chuck Lever
@ 2026-10-26 13:39     ` Mohammed
  0 siblings, 0 replies; 6+ messages in thread
From: Mohammed @ 2026-10-26 13:39 UTC (permalink / raw)
  To: Chuck Lever
  Cc: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey,
	linux-nfs

Sure thing.

On Mon, Oct 26, 2026 at 4:05 PM Chuck Lever <cel@kernel.org> wrote:
>
>
>
> On Mon, Oct 26, 2026, at 6:30 AM, Mohammed wrote:
> > Hi Chuck,
> >
> > This patch fixes the issue.
> >
> > Thanks for the quick response and fix!
>
> May I add:
>
> Tested-by: Mohammed <mohammed.saad.alquraini@gmail.com>
>
> ?
>
> > Best,
> > Mohammed
> >
> > On Thu, Oct 22, 2026 at 11:54 PM Chuck Lever <cel@kernel.org> wrote:
> >>
> >> svc_age_temp_xprts_now() moves each matching temporary transport
> >> onto a local list under sv_lock, then drops the lock and walks the
> >> local list without holding a reference on any of them. In the
> >> meantime svc_delete_xprt() can take sv_lock, unlink the same
> >> xpt_list node, and drop the transport's last reference. An idle
> >> temporary transport holds only that one reference, so a peer FIN
> >> that arrives between the two loops frees the svc_sock out from under
> >> the second loop. The notifier then sets XPT_CLOSE in freed memory,
> >> and svc_xprt_enqueue() reads xpt_flags and xpt_server from the freed
> >> object and queues that object on a pool for an nfsd thread. KASAN
> >> reports a slab-use-after-free in svc_xprt_enqueue() under
> >> nfsd_inetaddr_event(), with the object freed by svc_sock_free() on
> >> an nfsd thread.
> >>
> >> The two-phase walk dates from when the second loop called into the
> >> socket layer and could sleep. Commit 546125d16142 ("sunrpc: don't
> >> call sleeping functions from the notifier block callbacks") moved
> >> that work to the nfsd threads, so nothing left in the second loop
> >> needs sv_lock dropped. Mark and enqueue each matching transport
> >> under sv_lock in a single pass, as svc_age_temp_xprts() already
> >> does, so that svc_delete_xprt() cannot unlink and free a transport
> >> the notifier is still touching.
> >>
> >> Fixes: c3d4879e01be ("sunrpc: Add a function to close temporary transports immediately")
> >> Reported-by: Mohammed Alquraini <mohammed.saad.alquraini@gmail.com>
> >> Signed-off-by: Chuck Lever <cel@kernel.org>
> >> ---
> >>  net/sunrpc/svc_xprt.c | 16 ++++------------
> >>  1 file changed, 4 insertions(+), 12 deletions(-)
> >>
> >> Mohammed, thanks for the report. Please test and report your results.
> >>
> >> diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
> >> index 5db42e53be62..076c624fe675 100644
> >> --- a/net/sunrpc/svc_xprt.c
> >> +++ b/net/sunrpc/svc_xprt.c
> >> @@ -1075,29 +1075,21 @@ void svc_age_temp_xprts_now(struct svc_serv *serv, struct sockaddr *server_addr)
> >>  {
> >>         struct svc_xprt *xprt;
> >>         struct list_head *le, *next;
> >> -       LIST_HEAD(to_be_closed);
> >>
> >>         spin_lock_bh(&serv->sv_lock);
> >>         list_for_each_safe(le, next, &serv->sv_tempsocks) {
> >>                 xprt = list_entry(le, struct svc_xprt, xpt_list);
> >> -               if (rpc_cmp_addr(server_addr, (struct sockaddr *)
> >> -                               &xprt->xpt_local)) {
> >> -                       dprintk("svc_age_temp_xprts_now: found %p\n", xprt);
> >> -                       list_move(le, &to_be_closed);
> >> -               }
> >> -       }
> >> -       spin_unlock_bh(&serv->sv_lock);
> >> -
> >> -       while (!list_empty(&to_be_closed)) {
> >> -               le = to_be_closed.next;
> >> +               if (!rpc_cmp_addr(server_addr, (struct sockaddr *)
> >> +                               &xprt->xpt_local))
> >> +                       continue;
> >>                 list_del_init(le);
> >> -               xprt = list_entry(le, struct svc_xprt, xpt_list);
> >>                 set_bit(XPT_CLOSE, &xprt->xpt_flags);
> >>                 set_bit(XPT_KILL_TEMP, &xprt->xpt_flags);
> >>                 dprintk("svc_age_temp_xprts_now: queuing xprt %p for closing\n",
> >>                                 xprt);
> >>                 svc_xprt_enqueue(xprt);
> >>         }
> >> +       spin_unlock_bh(&serv->sv_lock);
> >>  }
> >>  EXPORT_SYMBOL_GPL(svc_age_temp_xprts_now);
> >>
> >> --
> >> 2.54.0
> >>
>
> --
> Chuck Lever (Come to NFS bake-a-thon! https://nfsv4bat.org)

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

end of thread, other threads:[~2026-10-26 13:39 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-22 20:53 [PATCH] SUNRPC: Fix use-after-free in svc_age_temp_xprts_now() Chuck Lever
2026-10-23  2:13 ` NeilBrown
2026-10-26 10:30 ` Mohammed
2026-10-26 13:05   ` Chuck Lever
2026-10-26 13:39     ` Mohammed
2026-10-26 11:44 ` Jeff Layton

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.