[<prev] [next>] [day] [month] [year] [list]
Message-ID: <20250911034337.43331-2-anderson@allelesecurity.com>
Date: Thu, 11 Sep 2025 00:43:38 -0300
From: Anderson Nascimento <anderson@...elesecurity.com>
To: edumazet@...gle.com,
ncardwell@...gle.com,
kuniyu@...gle.com,
davem@...emloft.net,
dsahern@...nel.org,
kuba@...nel.org,
pabeni@...hat.com,
horms@...nel.org,
netdev@...r.kernel.org,
linux-kernel@...r.kernel.org
Cc: Anderson Nascimento <anderson@...elesecurity.com>
Subject: [PATCH v2] net/tcp: Fix a NULL pointer dereference when using TCP-AO with TCP_REPAIR.
A NULL pointer dereference can occur in tcp_ao_finish_connect() during a
connect() system call on a socket with a TCP-AO key added and TCP_REPAIR
enabled.
The function is called with skb being NULL and attempts to dereference it
on tcp_hdr(skb)->seq without a prior skb validation.
Fix this by checking if skb is NULL before dereferencing it. If skb is
not NULL, the ao->risn is set to tcp_hdr(skb)->seq. If skb is NULL,
ao->risn is set to 0 to keep compatibility with calls made from
tcp_rcv_synsent_state_process().
int main(void){
struct sockaddr_in sockaddr;
struct tcp_ao_add tcp_ao;
int sk;
int one = 1;
memset(&sockaddr,'\0',sizeof(sockaddr));
memset(&tcp_ao,'\0',sizeof(tcp_ao));
sk = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
sockaddr.sin_family = AF_INET;
memcpy(tcp_ao.alg_name,"cmac(aes128)",12);
memcpy(tcp_ao.key,"ABCDEFGHABCDEFGH",16);
tcp_ao.keylen = 16;
memcpy(&tcp_ao.addr,&sockaddr,sizeof(sockaddr));
setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY, &tcp_ao,
sizeof(tcp_ao));
setsockopt(sk, IPPROTO_TCP, TCP_REPAIR, &one, sizeof(one));
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htobe16(123);
inet_aton("127.0.0.1", &sockaddr.sin_addr);
connect(sk,(struct sockaddr *)&sockaddr,sizeof(sockaddr));
return 0;
}
$ gcc tcp-ao-nullptr.c -o tcp-ao-nullptr -Wall
$ unshare -Urn
# ip addr add 127.0.0.1 dev lo
# ./tcp-ao-nullptr
BUG: kernel NULL pointer dereference, address: 00000000000000b6
PGD 1f648d067 P4D 1f648d067 PUD 1982e8067 PMD 0
Oops: Oops: 0000 [#1] SMP NOPTI
Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop
Reference Platform, BIOS 6.00 11/12/2020
RIP: 0010:tcp_ao_finish_connect (net/ipv4/tcp_ao.c:1182)
Code: 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 66 0f 1f 00 0f 1f
44 00 00 41 54 55 53 48 8b af 00 09 00 00 48 85 ed 74 3e <0f> b7 86 b6 00
00 00 48 8b 96 c8 00 00 00 49 89 fc 8b 44 02 04 c7
All code
========
0: 90 nop
1: 90 nop
2: 90 nop
3: 90 nop
4: 90 nop
5: 90 nop
6: 90 nop
7: 90 nop
8: 90 nop
9: 90 nop
a: 90 nop
b: 90 nop
c: 90 nop
d: 90 nop
e: 90 nop
f: 90 nop
10: 90 nop
11: 66 0f 1f 00 nopw (%rax)
15: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
1a: 41 54 push %r12
1c: 55 push %rbp
1d: 53 push %rbx
1e: 48 8b af 00 09 00 00 mov 0x900(%rdi),%rbp
25: 48 85 ed test %rbp,%rbp
28: 74 3e je 0x68
2a:* 0f b7 86 b6 00 00 00 movzwl 0xb6(%rsi),%eax
<-- trapping instruction
31: 48 8b 96 c8 00 00 00 mov 0xc8(%rsi),%rdx
38: 49 89 fc mov %rdi,%r12
3b: 8b 44 02 04 mov 0x4(%rdx,%rax,1),%eax
3f: c7 .byte 0xc7
Code starting with the faulting instruction
===========================================
0: 0f b7 86 b6 00 00 00 movzwl 0xb6(%rsi),%eax
7: 48 8b 96 c8 00 00 00 mov 0xc8(%rsi),%rdx
e: 49 89 fc mov %rdi,%r12
11: 8b 44 02 04 mov 0x4(%rdx,%rax,1),%eax
15: c7 .byte 0xc7
RSP: 0018:ffffcf7a858f3a50 EFLAGS: 00010282
RAX: 0000000000000000 RBX: ffff8e51e8150000 RCX: 0000000000000002
RDX: ffffcf7a858f3a1f RSI: 0000000000000000 RDI: ffff8e51e8150000
RBP: ffff8e51c1509e80 R08: ffff8e51e81506bc R09: 0000000000000001
R10: 0000000000000000 R11: ffff8e51e8150000 R12: 0000000000000000
R13: ffff8e51c7019680 R14: ffff8e51d20d1cc0 R15: ffff8e51e8150000
FS: 00007faa5e4dc740(0000) GS:ffff8e533e55f000(0000) knlGS:00000000000000
00
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00000000000000b6 CR3: 000000016d3e0003 CR4: 00000000003706f0
Call Trace:
<TASK>
tcp_finish_connect (net/ipv4/tcp_input.c:6267)
tcp_connect (net/ipv4/tcp_output.c:4141)
tcp_v4_connect (net/ipv4/tcp_ipv4.c:345 (discriminator 1))
__inet_stream_connect (net/ipv4/af_inet.c:677)
? release_sock (./include/linux/list.h:373 (discriminator 2) ./include/
linux/wait.h:127 (discriminator 2) net/core/sock.c:3733 (discriminator 2))
inet_stream_connect (net/ipv4/af_inet.c:749)
__sys_connect (./include/linux/file.h:62 (discriminator 1) ./include/linux
/file.h:83 (discriminator 1) net/socket.c:2095 (discriminator 1))
__x64_sys_connect (net/socket.c:2111 (discriminator 1) net/socket.c:2108
(discriminator 1) net/socket.c:2108 (discriminator 1))
do_syscall_64 (arch/x86/entry/syscall_64.c:63 (discriminator 1) arch/x86/
entry/syscall_64.c:94 (discriminator 1))
? do_read_fault (mm/memory.c:5565)
? handle_pte_fault (mm/memory.c:6047)
? do_fault (mm/memory.c:5707)
? __handle_mm_fault (mm/memory.c:5963 mm/memory.c:6131)
? count_memcg_events (mm/memcontrol.c:839 (discriminator 4))
? handle_mm_fault (mm/memory.c:6237 mm/memory.c:6390)
? do_user_addr_fault (arch/x86/mm/fault.c:1337)
? clear_bhb_loop (arch/x86/entry/entry_64.S:1548)
? clear_bhb_loop (arch/x86/entry/entry_64.S:1548)
? clear_bhb_loop (arch/x86/entry/entry_64.S:1548)
entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130)
RIP: 0033:0x7faa5e54d77e
Code: 4d 89 d8 e8 d4 bc 00 00 4c 8b 5d f8 41 8b 93 08 03 00 00 59 5e 48 83
f8 fc 74 11 c9 c3 0f 1f 80 00 00 00 00 48 8b 45 10 0f 05 <c9> c3 83 e2 39
83 fa 08 75 e7 e8 13 ff ff ff 0f 1f 00 f3 0f 1e fa
All code
========
0: 4d 89 d8 mov %r11,%r8
3: e8 d4 bc 00 00 call 0xbcdc
8: 4c 8b 5d f8 mov -0x8(%rbp),%r11
c: 41 8b 93 08 03 00 00 mov 0x308(%r11),%edx
13: 59 pop %rcx
14: 5e pop %rsi
15: 48 83 f8 fc cmp $0xfffffffffffffffc,%rax
19: 74 11 je 0x2c
1b: c9 leave
1c: c3 ret
1d: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
24: 48 8b 45 10 mov 0x10(%rbp),%rax
28: 0f 05 syscall
2a:* c9 leave <-- trapping instruction
2b: c3 ret
2c: 83 e2 39 and $0x39,%edx
2f: 83 fa 08 cmp $0x8,%edx
32: 75 e7 jne 0x1b
34: e8 13 ff ff ff call 0xffffffffffffff4c
39: 0f 1f 00 nopl (%rax)
3c: f3 0f 1e fa endbr64
Code starting with the faulting instruction
===========================================
0: c9 leave
1: c3 ret
2: 83 e2 39 and $0x39,%edx
5: 83 fa 08 cmp $0x8,%edx
8: 75 e7 jne 0xfffffffffffffff1
a: e8 13 ff ff ff call 0xffffffffffffff22
f: 0f 1f 00 nopl (%rax)
12: f3 0f 1e fa endbr64
RSP: 002b:00007ffc0e35e350 EFLAGS: 00000202 ORIG_RAX: 000000000000002a
RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007faa5e54d77e
RDX: 0000000000000010 RSI: 00007ffc0e35e4e0 RDI: 0000000000000003
RBP: 00007ffc0e35e360 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000202 R12: 00007ffc0e35e628
R13: 0000000000000001 R14: 00007faa5e717000 R15: 0000000000402e00
</TASK>
Modules linked in: rfkill nft_fib_inet nft_fib_ipv4 nft_fib_ipv6 nft_fib
nft_reject_inet nf_reject_ipv4 nf_reject_ipv6 nft_reject nft_ct
nft_chain_nat nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 nf_tables
qrtr intel_rapl_msr intel_rapl_common intel_uncore_frequency_common
intel_pmc_core pmt_telemetry pmt_class intel_pmc_ssram_telemetry
intel_vsec rapl vmw_balloon pktcdvd i2c_piix4 i2c_smbus joydev loop
nfnetlink vsock_loopback vmw_vsock_virtio_transport_common
vmw_vsock_vmci_transport vsock zram vmw_vmci lz4hc_compress lz4_compress
xfs polyval_clmulni ghash_clmulni_intel sha512_ssse3 sha1_ssse3 vmwgfx
drm_ttm_helper vmxnet3 nvme nvme_tcp ata_generic ttm nvme_fabrics
pata_acpi nvme_core nvme_keyring nvme_auth serio_raw sunrpc be2iscsi bnx2i
cnic uio cxgb4i cxgb4 tls cxgb3i cxgb3 mdio libcxgbi libcxgb qla4xxx
iscsi_boot_sysfs iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi
scsi_dh_rdac scsi_dh_emc scsi_dh_alua fuse i2c_dev dm_multipath
CR2: 00000000000000b6
---[ end trace 0000000000000000 ]---
RIP: 0010:tcp_ao_finish_connect (net/ipv4/tcp_ao.c:1182)
Code: 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 66 0f 1f 00 0f 1f
44 00 00 41 54 55 53 48 8b af 00 09 00 00 48 85 ed 74 3e <0f> b7 86 b6 00
00 00 48 8b 96 c8 00 00 00 49 89 fc 8b 44 02 04 c7
All code
========
0: 90 nop
1: 90 nop
2: 90 nop
3: 90 nop
4: 90 nop
5: 90 nop
6: 90 nop
7: 90 nop
8: 90 nop
9: 90 nop
a: 90 nop
b: 90 nop
c: 90 nop
d: 90 nop
e: 90 nop
f: 90 nop
10: 90 nop
11: 66 0f 1f 00 nopw (%rax)
15: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
1a: 41 54 push %r12
1c: 55 push %rbp
1d: 53 push %rbx
1e: 48 8b af 00 09 00 00 mov 0x900(%rdi),%rbp
25: 48 85 ed test %rbp,%rbp
28: 74 3e je 0x68
2a:* 0f b7 86 b6 00 00 00 movzwl 0xb6(%rsi),%eax
<-- trapping instruction
31: 48 8b 96 c8 00 00 00 mov 0xc8(%rsi),%rdx
38: 49 89 fc mov %rdi,%r12
3b: 8b 44 02 04 mov 0x4(%rdx,%rax,1),%eax
3f: c7 .byte 0xc7
Code starting with the faulting instruction
===========================================
0: 0f b7 86 b6 00 00 00 movzwl 0xb6(%rsi),%eax
7: 48 8b 96 c8 00 00 00 mov 0xc8(%rsi),%rdx
e: 49 89 fc mov %rdi,%r12
11: 8b 44 02 04 mov 0x4(%rdx,%rax,1),%eax
15: c7 .byte 0xc7
RSP: 0018:ffffcf7a858f3a50 EFLAGS: 00010282
RAX: 0000000000000000 RBX: ffff8e51e8150000 RCX: 0000000000000002
RDX: ffffcf7a858f3a1f RSI: 0000000000000000 RDI: ffff8e51e8150000
RBP: ffff8e51c1509e80 R08: ffff8e51e81506bc R09: 0000000000000001
R10: 0000000000000000 R11: ffff8e51e8150000 R12: 0000000000000000
R13: ffff8e51c7019680 R14: ffff8e51d20d1cc0 R15: ffff8e51e8150000
FS: 00007faa5e4dc740(0000) GS:ffff8e533e55f000(0000) knlGS:0000000000000
000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00000000000000b6 CR3: 000000016d3e0003 CR4: 00000000003706f0
note: tcp-ao-nullptr[41065] exited with irqs disabled
Fixes: 7c2ffaf ("net/tcp: Calculate TCP-AO traffic keys")
Signed-off-by: Anderson Nascimento <anderson@...elesecurity.com>
---
Changes in v2:
- Wrap the description at 75 columns
- Add full decoded stack trace
- Link to v1: https://lore.kernel.org/all/20250911013052.2233-1-anderson@allelesecurity.com/
net/ipv4/tcp_ao.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/net/ipv4/tcp_ao.c b/net/ipv4/tcp_ao.c
index bbb8d5f0eae7..abe913de8652 100644
--- a/net/ipv4/tcp_ao.c
+++ b/net/ipv4/tcp_ao.c
@@ -1178,7 +1178,11 @@ void tcp_ao_finish_connect(struct sock *sk, struct sk_buff *skb)
if (!ao)
return;
- WRITE_ONCE(ao->risn, tcp_hdr(skb)->seq);
+ /* sk with TCP_REPAIR_ON does not have skb in tcp_finish_connect */
+ if (skb)
+ WRITE_ONCE(ao->risn, tcp_hdr(skb)->seq);
+ else
+ WRITE_ONCE(ao->risn, 0);
ao->rcv_sne = 0;
hlist_for_each_entry_rcu(key, &ao->head, node, lockdep_sock_is_held(sk))
--
2.51.0
Powered by blists - more mailing lists