nlattr_to_sctp() assigns the user-supplied CTA_PROTOINFO_SCTP_STATE value directly to ct->proto.sctp.state without checking that it is within the valid range. The state value is later used as an array index in sctp_print_conntrack() (sctp_conntrack_names[state]) and sctp_new_state() (sctp_conntracks[dir][i][state]), causing global-out-of-bounds reads. This is the same class of bug that was fixed for DCCP in CVE-2023-39197, but the SCTP counterpart was missed. Add a range check against SCTP_CONNTRACK_MAX, consistent with the existing validation in nlattr_to_tcp() for TCP conntrack state. KASAN report: [ 1.101351] BUG: KASAN: global-out-of-bounds in sctp_print_conntrack+0x30/0x50 [ 1.101574] Read of size 8 at addr ffffffff847a5770 by task poc_sctp/131 [ 1.101770] [ 1.101824] CPU: 1 UID: 0 PID: 131 Comm: poc_sctp Not tainted 7.0.0-rc2+ #6 PREEMPTLAZY [ 1.101827] 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 [ 1.101829] Call Trace: [ 1.101833] [ 1.101834] dump_stack_lvl+0x64/0x80 [ 1.101844] print_report+0xce/0x660 [ 1.101849] ? __pfx__raw_spin_lock_irqsave+0x10/0x10 [ 1.101857] ? __virt_addr_valid+0xef/0x1a0 [ 1.101863] ? sctp_print_conntrack+0x30/0x50 [ 1.101866] kasan_report+0xce/0x100 [ 1.101868] ? sctp_print_conntrack+0x30/0x50 [ 1.101870] sctp_print_conntrack+0x30/0x50 [ 1.101874] ct_seq_show+0x392/0x7f0 [ 1.101878] ? __pfx_ct_seq_show+0x10/0x10 [ 1.101880] ? __kasan_kmalloc+0x8f/0xa0 [ 1.101884] ? ktime_get_with_offset+0xa3/0x140 [ 1.101889] ? ct_get_next+0x14e/0x190 [ 1.101892] seq_read_iter+0x292/0x7d0 [ 1.101897] seq_read+0x214/0x290 [ 1.101901] ? __pfx_seq_read+0x10/0x10 [ 1.101903] ? apparmor_file_permission+0x114/0x340 [ 1.101911] proc_reg_read+0xe4/0x140 [ 1.101916] vfs_read+0x141/0x570 [ 1.101919] ? kmem_cache_free+0x100/0x440 [ 1.101924] ? __pfx_vfs_read+0x10/0x10 [ 1.101926] ? do_sys_openat2+0xed/0x150 [ 1.101930] ? __pfx_do_sys_openat2+0x10/0x10 [ 1.101932] ksys_read+0xcc/0x160 [ 1.101934] ? __pfx_ksys_read+0x10/0x10 [ 1.101936] do_syscall_64+0xc3/0x6e0 [ 1.101940] entry_SYSCALL_64_after_hwframe+0x76/0x7e [ 1.101944] RIP: 0033:0x41b301 [ 1.101949] Code: f7 d8 64 89 02 b8 ff ff ff ff eb ba e8 e8 16 00 00 0f 1f 84 00 00 00 00 00 f3 0f 1e fa 80 3d 5d 8d 09 00 00 74 13 31 c0 0f 05 <48> 3d 00 f0 ff ff 77 4f c3 66 0f 1f 44 00 00 55 48 89 e5 48 83 ec [ 1.101951] RSP: 002b:00007ffca1da7f08 EFLAGS: 00000246 ORIG_RAX: 0000000000000000 [ 1.101957] RAX: ffffffffffffffda RBX: 0000000000000004 RCX: 000000000041b301 [ 1.101958] RDX: 0000000000001fff RSI: 00007ffca1da7f10 RDI: 0000000000000004 [ 1.101959] RBP: 00007ffca1da7f10 R08: 0000000000000000 R09: 0000000000000000 [ 1.101962] R10: 0000000000000000 R11: 0000000000000246 R12: 00007ffca1daa820 [ 1.101963] R13: 00007ffca1dab988 R14: 0000000000000003 R15: 00007ffca1da9f84 [ 1.101965] [ 1.101966] [ 1.107833] The buggy address belongs to the variable: [ 1.107977] sctp_conntrack_names+0x50/0xc0 [ 1.108107] [ 1.108155] The buggy address belongs to the physical page: [ 1.108309] page: refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x47a5 [ 1.108536] flags: 0x100000000002000(reserved|node=0|zone=1) [ 1.108702] raw: 0100000000002000 ffffea000011e948 ffffea000011e948 0000000000000000 [ 1.108916] raw: 0000000000000000 0000000000000000 00000001ffffffff 0000000000000000 [ 1.109132] page dumped because: kasan: bad access detected [ 1.109288] [ 1.109337] Memory state around the buggy address: [ 1.109476] ffffffff847a5600: f9 f9 f9 f9 00 06 f9 f9 f9 f9 f9 f9 00 06 f9 f9 [ 1.109690] ffffffff847a5680: f9 f9 f9 f9 00 00 02 f9 f9 f9 f9 f9 00 07 f9 f9 [ 1.109910] >ffffffff847a5700: f9 f9 f9 f9 00 00 00 00 00 00 00 00 00 f9 f9 f9 [ 1.110118] ^ [ 1.110309] ffffffff847a5780: f9 f9 f9 f9 00 00 00 07 f9 f9 f9 f9 00 00 00 00 [ 1.110515] ffffffff847a5800: 00 00 00 00 00 00 00 00 00 f9 f9 f9 f9 f9 f9 f9 [ 1.110720] ================================================================== Fixes: a258860e01b8 ("netfilter: ctnetlink: add full support for SCTP to ctnetlink") Signed-off-by: Hyunwoo Kim --- net/netfilter/nf_conntrack_proto_sctp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c index 7c6f7c9f7332..cbee99be7b5e 100644 --- a/net/netfilter/nf_conntrack_proto_sctp.c +++ b/net/netfilter/nf_conntrack_proto_sctp.c @@ -612,6 +612,9 @@ static int nlattr_to_sctp(struct nlattr *cda[], struct nf_conn *ct) !tb[CTA_PROTOINFO_SCTP_VTAG_REPLY]) return -EINVAL; + if (nla_get_u8(tb[CTA_PROTOINFO_SCTP_STATE]) >= SCTP_CONNTRACK_MAX) + return -EINVAL; + spin_lock_bh(&ct->lock); ct->proto.sctp.state = nla_get_u8(tb[CTA_PROTOINFO_SCTP_STATE]); ct->proto.sctp.vtag[IP_CT_DIR_ORIGINAL] = -- 2.43.0