TGTGInsighttelegram intelligenceLIVE / telegram public index
← Welcome to the Black Parade
Welcome to the Black Parade avatar

TGINSIGHT POST

Post #1024

@TheB1ackParade

Welcome to the Black Parade

Views765Post view count
PostedMar 2403/24/2026, 09:19 AM
Post content

Post content

cgroup/sock_release (BPF_PROG_TYPE_CGROUP_SOCK - BPF_CGROUP_INET_SOCK_RELEASE) 这个 bpf hook 实在太坑了,不管怎么读文档 (https://docs.ebpf.io/linux/program-type/BPF_PROG_TYPE_CGROUP_SOCK/) 能应该理解成这是 struct sock 生命周期结束的 hook,参数也是 struct sock 没有问题。 但是!仔细阅读内核发现它的调用路径大致是这样的: close(fd) -> sock_release() -> inet_release() -> BPF_CGROUP_RUN_PROG_INET_SOCK_RELEASE(sk) -> tcp_close(sk, timeout) 这就已经暴露出两个问题了: 1. cgroup sock release hook 是和用户态进程 close(fd) 挂钩的,也就是说如果没有用户态 fd 光有内核态 sk 的时候,并不会触发 cgroup hook。 什么时候没有用户态 fd 只有内核态 sk?太多了,几乎发生在每一次三次握手,因为 3whs 和 accept syscall 是两个步骤,三次握手在内核态完成后就有了 sk,但等到不知何时用户态调用 accept 才会有 fd,在此期间如果进程崩溃,sk 直接从内核态关闭,不会触发 cgroup hook。 2. cgroup hook 运行在前,而 tcp_close(sk) 运行在后,这里有个微小的 race condition,在两者之间如果有 bpf iter 扫描 sk,这些 sk 虽然看起来正常,skc->skc_state == TCP_ESTABLISHED,但实际已经处于关闭路径上,而且已经调用过了 cgroup hook。这个 window 看起来微小,实际上在稍大点的集群上跑起来很容易就遇到了。 反思一下,其实 cgroup sock release 的正确语义是 “struct socket 销毁的 hook” 而不是 "struct sock 销毁的 hook”,两者的微小语义差别(其实挺大的)导致若没有准确理解触发时机就会惊喜连连。内核实在太美好了,不写文档,全靠信息差成为专家,没错一定是这样的。 bonus: tp_btf/tcp_destroy_sock