syzbot
WARNING in svc_destroy
Status:
moderation: reported on 2026/11/05 19:35
Subsystems:
net
nfs
Labels:
prio:normal
[Documentation on labels]
Reported-by: syzbot+3c98edca676012db07cf@syzkaller.appspotmail.com
First crash: 2h33m, last: 2h33m
✨ AI-generated root cause summary:
In fs/nfs/callback.c, nfs4_callback_up_net() first initializes an IPv4 TCP listener transport via svc_xprt_create(..., PF_INET, ...), which links the transport onto serv->sv_permsocks. When a subsequent call to svc_xprt_create(..., PF_INET6, ...) fails with an error other than -EAFNOSUPPORT, nfs4_callback_up_net() returns the error immediately without tearing down the existing IPv4 transport. As a result, nfs_callback_up() unwinds on error and calls xprt_svc_destroy_nullify_bc() -> svc_destroy(), which triggers the WARN_ONCE(!list_empty(&serv->sv_permsocks)) warning because the IPv4 transport is still attached to the service, and subsequently frees the service while leaving the active listener with a dangling pointer.
▶
▼
✨ Full AI root cause analysis
Technical Root Cause Analysis
Involved Components
- Source Files:
fs/nfs/callback.c, net/sunrpc/svc.c, net/sunrpc/svc_xprt.c
- Functions:
nfs4_callback_up_net(), nfs_callback_up_net(), nfs_callback_up(), svc_destroy(), svc_xprt_create(), svc_add_new_perm_xprt()
- Data Structures and Fields:
struct svc_serv: fields sv_permsocks, sv_pools
struct svc_xprt: fields xpt_list, xpt_server, xpt_flags
Root Cause and Trigger Mechanism
-
Callback Service Initialization:
During NFSv4.0 mount/client setup, nfs_callback_up() is invoked to bring up the callback service.
It creates a server instance (struct svc_serv) via nfs_callback_create_svc(minorversion) and attempts to configure per-network-namespace callback transports by calling nfs_callback_up_net(minorversion, serv, net, xprt).
-
Creation of Listeners in nfs4_callback_up_net():
For NFSv4.0 (minorversion == 0), nfs_callback_up_net() invokes nfs4_callback_up_net():
ret = svc_xprt_create(serv, "tcp", net, PF_INET,
nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS, cred);
if (ret <= 0)
goto out_err;
nn->nfs_callback_tcpport = ret;
ret = svc_xprt_create(serv, "tcp", net, PF_INET6,
nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS, cred);
if (ret > 0) {
nn->nfs_callback_tcpport6 = ret;
} else if (ret != -EAFNOSUPPORT)
goto out_err;
- The first call to
svc_xprt_create() for PF_INET succeeds. The created struct svc_xprt is attached to serv->sv_permsocks via svc_add_new_perm_xprt(), and its xpt_server pointer is set to serv.
- The second call to
svc_xprt_create() for PF_INET6 fails with an error other than -EAFNOSUPPORT (for example, -EINVAL, -EADDRINUSE, -ENOBUFS, or other socket creation/bind errors).
nfs4_callback_up_net() takes the goto out_err; branch and returns the error code without cleaning up or closing the previously created PF_INET transport.
-
Incomplete Error Unwind:
- In
nfs_callback_up_net(), on ret < 0, it prints "NFS: callback service start failed", decrements nn->cb_users[minorversion], and returns ret without destroying any transports associated with serv.
- Control returns to
nfs_callback_up(), which branches to err_net:. Because cb_info->users is 0, it calls:
xprt_svc_shutdown_bc(xprt);
svc_set_num_threads(cb_info->serv, 0, 0);
xprt_svc_destroy_nullify_bc(xprt, &cb_info->serv);
xprt_svc_destroy_nullify_bc() forwards directly to svc_destroy(&cb_info->serv).
-
Premature Destruction of svc_serv:
In svc_destroy() (net/sunrpc/svc.c):
WARN_ONCE(!list_empty(&serv->sv_permsocks),
"SVC: permsocks remain for %s\n", serv->sv_programs->pg_name);
WARN_ONCE(!list_empty(&serv->sv_tempsocks),
"SVC: tempsocks remain for %s\n", serv->sv_programs->pg_name);
...
kfree(serv->sv_pools);
kfree(serv);
Because the IPv4 transport was never torn down (unlike during graceful shutdown or in fs/lockd/svc.c:make_socks() where svc_xprt_destroy_all(serv, net, ...) is called on error), serv->sv_permsocks is not empty. This triggers the reported WARN_ONCE.
-
Dangling Pointer and Use-After-Free:
Following the warning, svc_destroy() proceeds to free serv->sv_pools and serv. The still-active IPv4 listener transport (struct svc_xprt) remains registered in the network stack with its xpt_server field holding a dangling pointer to the freed struct svc_serv.
Sample crash report:
NFS: callback service start failed
------------[ cut here ]------------
SVC: permsocks remain for NFSv4 callback
WARNING: net/sunrpc/svc.c:532 at svc_destroy+0x299/0x330 net/sunrpc/svc.c:532, CPU#1: syz.2.321/6994
Modules linked in:
CPU: 1 UID: 0 PID: 6994 Comm: syz.2.321 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/15/2026
RIP: 0010:svc_destroy+0x29d/0x330 net/sunrpc/svc.c:532
Code: 48 b8 00 00 00 00 00 fc ff df 49 8b 5d 00 48 8d 7b 18 48 89 fa 48 c1 ea 03 80 3c 02 00 75 67 48 8d 3d 17 5e 78 07 48 8b 73 18 <67> 48 0f b9 3a e9 d0 fd ff ff 48 8b 7c 24 08 e8 bf 13 86 f7 e9 a5
RSP: 0018:ffffc900042af860 EFLAGS: 00010246
RAX: dffffc0000000000 RBX: ffffffff9040ba80 RCX: ffffc900063d9000
RDX: 1ffffffff2081753 RSI: ffffffff8c37e800 RDI: ffffffff927aee30
RBP: 0000000000000000 R08: 00000000ffffffff R09: 0000000000000000
R10: 0000000000000001 R11: 0000000000000000 R12: ffff888035744000
R13: ffff888055f04c00 R14: ffff88802de30000 R15: ffffffff9cd5b540
FS: 00007ff81118f6c0(0000) GS:ffff88812257c000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 000000110c29af61 CR3: 0000000056a04000 CR4: 00000000003526f0
Call Trace:
<TASK>
nfs_callback_up+0x511/0xad0 fs/nfs/callback.c:236
nfs4_init_callback fs/nfs/nfs4client.c:327 [inline]
nfs4_init_client_minor_version fs/nfs/nfs4client.c:379 [inline]
nfs4_init_client+0x236/0x420 fs/nfs/nfs4client.c:429
nfs_get_client+0xf38/0x1230 fs/nfs/client.c:467
nfs4_set_client+0x3f6/0x640 fs/nfs/nfs4client.c:763
nfs4_init_server.isra.0+0x5be/0xf80 fs/nfs/nfs4client.c:1014
nfs4_create_server+0x185/0x2b0 fs/nfs/nfs4client.c:1063
nfs4_try_get_tree+0x93/0x140 fs/nfs/nfs4super.c:228
nfs_get_tree+0xa61/0x1440 fs/nfs/fs_context.c:1621
vfs_get_tree+0x92/0x320 fs/super.c:1881
fc_mount fs/namespace.c:1282 [inline]
do_new_mount_fc fs/namespace.c:3910 [inline]
do_new_mount fs/namespace.c:3986 [inline]
path_mount+0x7d0/0x2850 fs/namespace.c:4337
do_mount fs/namespace.c:4350 [inline]
__do_sys_mount fs/namespace.c:4565 [inline]
__se_sys_mount fs/namespace.c:4542 [inline]
__x64_sys_mount+0x293/0x310 fs/namespace.c:4542
do_syscall_x64 arch/x86/entry/syscall_64.c:61 [inline]
do_syscall_64+0x123/0x790 arch/x86/entry/syscall_64.c:84
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7ff81039fb19
Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007ff81118f028 EFLAGS: 00000246 ORIG_RAX: 00000000000000a5
RAX: ffffffffffffffda RBX: 00007ff810625fa0 RCX: 00007ff81039fb19
RDX: 0000200000000480 RSI: 0000200000000440 RDI: 0000200000000400
RBP: 00007ff810437b70 R08: 00002000000004c0 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 00007ff810626038 R14: 00007ff810625fa0 R15: 00007ffd2a563db8
</TASK>
----------------
Code disassembly (best guess):
0: 48 b8 00 00 00 00 00 movabs $0xdffffc0000000000,%rax
7: fc ff df
a: 49 8b 5d 00 mov 0x0(%r13),%rbx
e: 48 8d 7b 18 lea 0x18(%rbx),%rdi
12: 48 89 fa mov %rdi,%rdx
15: 48 c1 ea 03 shr $0x3,%rdx
19: 80 3c 02 00 cmpb $0x0,(%rdx,%rax,1)
1d: 75 67 jne 0x86
1f: 48 8d 3d 17 5e 78 07 lea 0x7785e17(%rip),%rdi # 0x7785e3d
26: 48 8b 73 18 mov 0x18(%rbx),%rsi
* 2a: 67 48 0f b9 3a ud1 (%edx),%rdi <-- trapping instruction
2f: e9 d0 fd ff ff jmp 0xfffffe04
34: 48 8b 7c 24 08 mov 0x8(%rsp),%rdi
39: e8 bf 13 86 f7 call 0xf78613fd
3e: e9 .byte 0xe9
3f: a5 movsl %ds:(%rsi),%es:(%rdi)
* Struck through repros no longer work on HEAD.