* [PATCH net] ipv6: Keep the SCTP provider alive through socket allocation
@ 2026-10-12 4:42 Cen Zhang
0 siblings, 0 replies; only message in thread
From: Cen Zhang @ 2026-10-12 4:42 UTC (permalink / raw)
To: davem, edumazet, kuba, pabeni, horms, kuniyu, fmancera, willemb, kees
Cc: netdev, linux-kernel, baijiaju1990, jjzuming, zzzccc427
The sctpv6_prot slab must remain alive through socket allocation.
inet6_create() selects that proto under RCU, but drops RCU before
sk_alloc(). sk_prot_alloc() obtains the owner reference only after
allocating from the slab.
SCTP publishes its IPv6 stream and seqpacket entries while its module
is still COMING. A concurrent user socket can select an entry before
register_pernet_subsys(&sctp_ctrlsock_ops), sctp_v4_add_protocol() or
sctp_v6_add_protocol() fails. The subsequent initialization unwind
removes both entries and destroys the cache without waiting for owner
references.
After the constructor captures the cache pointer, initialization can
fail and destroy the cache before the allocator consumes that pointer:
User socket creation SCTP module initialization
-------------------- --------------------------
publish IPv6 protosw entries
select sctpv6_prot under RCU
drop RCU
capture prot->slab
fail a later setup step
sctp_v6_protosw_exit()
unlink both entries
synchronize_net()
proto_unregister()
destroy slab cache
kmem_cache_alloc(saved slab)
The allocator can then read retired cache metadata and fault. The grace
period drains lookup readers, but the constructor has already left RCU.
An early owner reference alone cannot prevent initialization failure
from destroying the cache, since try_module_get() accepts COMING.
The initialization-failure path follows from source inspection. The
Oops below came from an unload experiment using a modified kernel with
allocator bootstrap changes, scheduling instrumentation and SCTP's
internal control socket omitted. With that socket present, its owner
reference blocks ordinary unload. The experiment selected and captured
the same cache that teardown destroyed; the seqpacket constructor then
faulted before the allocator returned.
Reject user SCTP sockets while the owner is COMING and take a temporary
owner reference under the lookup's RCU protection before dropping RCU.
User allocation then requires completed initialization, and the
reference prevents normal module exit until sk_alloc() takes the
socket's own reference or fails. Release the temporary reference in
either case. Keep kernel control socket creation allowed during init,
where SCTP's per-net registration orders construction and cleanup.
KASAN report as below:
Oops: general protection fault, probably for non-canonical address
0xffff11036c3d1430: 0000 [#1] SMP KASAN NOPTI
KASAN: maybe wild-memory-access in range
[0xfff8a81b61e8a180-0xfff8a81b61e8a187]
CPU: 2 UID: 0 PID: 532 Comm: sctp-race-fixtu Not tainted
7.2.0-rc5-pmb-ipcore-functional-v2+ #1 PREEMPT(lazy)
Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix,
1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
RIP: 0010:kmem_cache_alloc_noprof+0xd6/0x600
Code: 85 c0 0f 8e 93 04 00 00 44 8b 74 24 18 0f 1f 44 00 00 41 bf ff ff
ff ff 65 ff 05 b5 e6 0d 09 65 4c 8b 2d a5 e6 0d 09 4c 03 2b <41> 0f b6
45 30 84 c0 0f 85 11 04 00 00 41 c6 45 30 01 45 31 c9 41
RSP: 0018:ffff8881135dfcc0 EFLAGS: 00010287
RAX: 0000000000000001 RBX: ffff88810891ec80 RCX: dffffc0000000000
RDX: 0000000000000cc0 RSI: 0000000000000890 RDI: ffff88810891ec80
RBP: 0000000000000c00 R08: 0000000000000001 R09: 00000000000000bd
R10: 0000000000000028 R11: ffff888113e5ba00 R12: 0000000000000cc0
R13: ffff11036c3d1400 R14: 0000000000000000 R15: 00000000ffffffff
FS: 00007ff3c2206780(0000) GS:ffff88826b86a000(0000)
knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 000055b973e7b10c CR3: 00000001158b5005 CR4: 0000000000770ef0
PKRU: 55555554
Call Trace:
<TASK>
? srso_alias_return_thunk+0x5/0xfbef5
? sk_prot_alloc+0x6f/0x2c0
sk_prot_alloc+0x6f/0x2c0
sk_alloc+0x37/0xb40
inet6_create+0x31b/0x1230
? inet6_create+0x5a/0x1230
__sock_create+0x2c4/0x730
__sys_socket+0x141/0x210
? __pfx___sys_socket+0x10/0x10
? srso_alias_return_thunk+0x5/0xfbef5
? handle_mm_fault+0x12e/0x580
__x64_sys_socket+0x77/0xc0
do_syscall_64+0x115/0x6a0
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7ff3c231b437
Code: 8b 54 24 08 64 48 2b 14 25 28 00 00 00 75 05 48 83 c4 18 c3 e8 ba
a7 00 00 66 2e 0f 1f 84 00 00 00 00 00 b8 29 00 00 00 0f 05 <48> 3d 01
f0 ff ff 73 01 c3 48 8b 0d a9 29 0d 00 f7 d8 64 89 01 48
RSP: 002b:00007ffed24e4ab8 EFLAGS: 00000246 ORIG_RAX: 0000000000000029
RAX: ffffffffffffffda RBX: 00007ffed24e4bd8 RCX: 00007ff3c231b437
RDX: 0000000000000084 RSI: 0000000000000005 RDI: 000000000000000a
RBP: 0000000000000002 R08: 0000000000000000 R09: 00007ff3c2413aa0
R10: 00007ffed24e4800 R11: 0000000000000246 R12: 0000000000000000
R13: 00007ffed24e4bf0 R14: 00007ff3c2444000 R15: 000055b973e7cd48
</TASK>
Modules linked in: [last unloaded: sctp]
---[ end trace 0000000000000000 ]---
RIP: 0010:kmem_cache_alloc_noprof+0xd6/0x600
Code: 85 c0 0f 8e 93 04 00 00 44 8b 74 24 18 0f 1f 44 00 00 41 bf ff ff
ff ff 65 ff 05 b5 e6 0d 09 65 4c 8b 2d a5 e6 0d 09 4c 03 2b <41> 0f b6
45 30 84 c0 0f 85 11 04 00 00 41 c6 45 30 01 45 31 c9 41
RSP: 0018:ffff8881135dfcc0 EFLAGS: 00010287
RAX: 0000000000000001 RBX: ffff88810891ec80 RCX: dffffc0000000000
RDX: 0000000000000cc0 RSI: 0000000000000890 RDI: ffff88810891ec80
RBP: 0000000000000c00 R08: 0000000000000001 R09: 00000000000000bd
R10: 0000000000000028 R11: ffff888113e5ba00 R12: 0000000000000cc0
R13: ffff11036c3d1400 R14: 0000000000000000 R15: 00000000ffffffff
FS: 00007ff3c2206780(0000) GS:ffff88826b86a000(0000)
knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 000055b973e7b10c CR3: 00000001158b5005 CR4: 0000000000770ef0
PKRU: 55555554
Kernel panic - not syncing: Fatal exception
Kernel Offset: disabled
---[ end Kernel panic - not syncing: Fatal exception ]---
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
Assisted-by: LLM
---
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index a9b8b4b42a1af72f09fb9544b0e13aade00a1e3d..fb7f84baeeb66f5d3926169df790cc439f98224f 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -110,6 +110,7 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol,
struct sock *sk;
struct inet_protosw *answer;
struct proto *answer_prot;
+ struct module *owner = NULL;
unsigned char answer_flags;
int try_loading_module = 0;
int err;
@@ -169,6 +170,17 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol,
sock->ops = answer->ops;
answer_prot = answer->prot;
+ if (answer->protocol == IPPROTO_SCTP) {
+ owner = answer_prot->owner;
+ err = -EPROTONOSUPPORT;
+ /* SCTP init can unwind despite an owner reference.
+ * Allow the kernel control socket during initialization.
+ */
+ if (!kern && owner && module_is_coming(owner))
+ goto out_rcu_unlock;
+ if (!try_module_get(owner))
+ goto out_rcu_unlock;
+ }
answer_flags = answer->flags;
rcu_read_unlock();
@@ -176,6 +188,7 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol,
err = -ENOBUFS;
sk = sk_alloc(net, PF_INET6, GFP_KERNEL, answer_prot, kern);
+ module_put(owner);
if (!sk)
goto out;
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2026-10-12 4:42 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-12 4:42 [PATCH net] ipv6: Keep the SCTP provider alive through socket allocation Cen Zhang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®