Skip to content

Kernel NULL pointer dereference when MPTCP socket creation is attempted #99

Description

@raphaelcoeffic

Since version 1.24, Go now defaults to opening MPTCP sockets for listeners when it believes this is supported by the kernel (see https://go-review.googlesource.com/c/go/+/607715).

This is a bit unfortunate as the kernel will crash immediately when TSI-highjacking is used:

[GIN-debug] Listening and serving HTTP on 0.0.0.0:3000
[   35.475734] tsi_create (463): problem creating inet socket
[   35.475829] BUG: kernel NULL pointer dereference, address: 0000000000000020
[   35.475907] #PF: supervisor read access in kernel mode
[   35.476048] #PF: error_code(0x0000) - not-present page
[   35.476248] PGD 4ac9067 P4D 4ac9067 PUD 4aca067 PMD 0 
[   35.476359] Oops: Oops: 0000 [#1] PREEMPT SMP NOPTI
[   35.476567] CPU: 3 UID: 0 PID: 463 Comm: ebuild Not tainted 6.12.20 #1
[   35.476656] RIP: 0010:tsi_create.part.0.cold+0x30/0x7a
[   35.476838] Code: 00 48 c7 c6 10 28 c8 81 48 c7 c7 d0 03 e4 81 e8 4e c7 fc ff 48 8b 7c 24 08 48 8b 47 20 48 8b 40 10 ff d0 0f 1f 00 48 8b 3c 24 <48> 8b 47 20 48 8b 40 10 ff d0 0f 1f 00 e9 58 b7 f9 ff 41 8b 95 c0
[   35.477722] RSP: 0018:ffffc90000d9be70 EFLAGS: 00010246
[   35.478107] RAX: 000000000000002e RBX: 00000000ffffffa3 RCX: 0000000000000003
[   35.478211] RDX: 0000000000000000 RSI: 0000000000000003 RDI: 0000000000000000
[   35.478311] RBP: ffff8880054c2700 R08: 0000000000000000 R09: ffffc90000d9bd08
[   35.478411] R10: ffff88807ffc7fa8 R11: 0000000000000003 R12: ffff8880045a8000
[   35.478508] R13: ffff888002b78000 R14: ffff8880054c2700 R15: ffffffff82261b80
[   35.478596] FS:  00007f5e7e7fc6c0(0000) GS:ffff88807fcc0000(0000) knlGS:0000000000000000
[   35.478683] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   35.478776] CR2: 0000000000000020 CR3: 00000000037f4003 CR4: 0000000000370eb0
[   35.478866] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[   35.479046] DR3: 0000000000000000 DR6: 00000000ffff07f0 DR7: 0000000000000400
[   35.479185] Call Trace:
[   35.479207]  <TASK>
[   35.479235]  ? show_trace_log_lvl+0x148/0x1b0
[   35.479309]  ? show_trace_log_lvl+0x148/0x1b0
[   35.479366]  ? __die+0x4d/0x89
[   35.479422]  ? page_fault_oops+0x8b/0xe0
[   35.479498]  ? prb_read_valid+0x12/0x20
[   35.479563]  ? exc_page_fault+0x60/0xc0
[   35.479605]  ? asm_exc_page_fault+0x22/0x30
[   35.479643]  ? tsi_create.part.0.cold+0x30/0x7a
[   35.479742]  ? alloc_inode+0x31/0xc0
[   35.479817]  ? __sock_create+0xe3/0x190
[   35.479893]  ? __sys_socket+0x7a/0x100
[   35.479968]  ? __x64_sys_socket+0xe/0x20
[   35.480024]  ? do_syscall_64+0x47/0x110
[   35.480086]  ? entry_SYSCALL_64_after_hwframe+0x76/0x7e
[   35.480143]  </TASK>
[   35.480189] CR2: 0000000000000020
[   35.480270] ---[ end trace 0000000000000000 ]---
[   35.480338] RIP: 0010:tsi_create.part.0.cold+0x30/0x7a
[   35.480415] Code: 00 48 c7 c6 10 28 c8 81 48 c7 c7 d0 03 e4 81 e8 4e c7 fc ff 48 8b 7c 24 08 48 8b 47 20 48 8b 40 10 ff d0 0f 1f 00 48 8b 3c 24 <48> 8b 47 20 48 8b 40 10 ff d0 0f 1f 00 e9 58 b7 f9 ff 41 8b 95 c0
[   35.480586] RSP: 0018:ffffc90000d9be70 EFLAGS: 00010246
[   35.480628] RAX: 000000000000002e RBX: 00000000ffffffa3 RCX: 0000000000000003
[   35.480684] RDX: 0000000000000000 RSI: 0000000000000003 RDI: 0000000000000000
[   35.480742] RBP: ffff8880054c2700 R08: 0000000000000000 R09: ffffc90000d9bd08
[   35.480797] R10: ffff88807ffc7fa8 R11: 0000000000000003 R12: ffff8880045a8000
[   35.480850] R13: ffff888002b78000 R14: ffff8880054c2700 R15: ffffffff82261b80
[   35.480919] FS:  00007f5e7e7fc6c0(0000) GS:ffff88807fcc0000(0000) knlGS:0000000000000000
[   35.480974] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   35.481037] CR2: 0000000000000020 CR3: 00000000037f4003 CR4: 0000000000370eb0
[   35.481140] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[   35.481226] DR3: 0000000000000000 DR6: 00000000ffff07f0 DR7: 0000000000000400
[   35.481322] note: ebuild[463] exited with irqs disabled

This can be reproduced easily with a Go program along these lines:

package main

import (
    "fmt"
    "net/http"
)

func hello(w http.ResponseWriter, req *http.Request) {
    fmt.Fprintf(w, "hello\n")
}

func main() {
    http.HandleFunc("/hello", hello)
    http.ListenAndServe(":8090", nil)
}

The current work-around is to start with GODEBUG="multipathtcp=0". It would be better though to either return EPROTONOSUPPORT or disable MPTCP in the provided configurations (see https://cs.opensource.google/go/go/+/refs/tags/go1.25.1:src/net/mptcpsock_linux.go;l=36).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions