前言
我们正在测试一些基于主机的 IPS。在此测试用例中,我们的应用程序正在监听环回,并且该应用程序正在以明文形式接收流量。我们正在使用 nginx 或 haproxy 终止公共接口上的 TLS。我们的 IDP 将监视环回,以便它可以看到未加密的流量。
我们的 IDP 看到了格式错误/不正确的日期,因此我们开始深入挖掘。
[更新 2]正如 @kasperd 提到的,tcpdump 正在从操作系统获取时间戳。也就是说,事实证明,除了 tcpdump 之外,这个错误实际上还会使 IDP 出错。它看到了 connection_established,但未能看到有效的 http 会话,因为 syn-ack 无效。
redhat.com 和 centos.org 上已记录了一个错误。
观察
回环上的第一个 syn-ack 总是有一个接近纪元开始的日期,或者在虚拟机上是 2 年之内。这与1970 年 12 月到1973 年 2 月在虚拟机上以及未来的裸机 Xeon 服务器上。 NTP 正确在我们所有的虚拟机和裸机服务器上,漂移均小于 50 毫秒。
这只发生在环回上。我们从未在服务器上的 bond0 或虚拟机上的 eth0 上看到过这种情况。
测试服务器和笔记本电脑
操作系统:CentOS 7
平台:
Dell 20 Core Xeon 服务器(裸机主机操作系统)
HP 20 核 Xeon 服务器(裸机主机操作系统)
MacOS 上的 VirtualBox
联想 P50 上的 Windows 10 Enterprise 上的 Hyper-V 具有 6 个虚拟核心。
一个基于赛扬 4 核 1.6 GHz 的路由器(无法在赛扬上复制)
重现步骤
在每个平台上,我们在环回端口 80 上启动一个 Web 监听器。
./simple_python 127.0.0.1 &
上面的代码是这里
然后我们启动 tcpdump
tcpdump -p -NNnn -XXxx -tttt -vv -s0 -c2 -i lo &
然后我们 curl 到 localhost
curl -s -o /dev/null http://127.0.0.1/
输出
2018-04-10 21:05:30.087769 IP (tos 0x0, ttl 127, id 49233, offset 0, flags [DF], proto TCP (6), length 60)
127.0.0.1.25134 > 127.0.0.1.80: Flags [S], cksum 0xfe30 (incorrect -> 0xce27), seq 4053136920, win 65495, options [mss 65495,sackOK,TS val 22951497 ecr 0,nop,wscale 13], length 0
0x0000: 0000 0000 0000 0000 0000 0000 0800 4500 ..............E.
0x0010: 003c c051 4000 7f06 3d68 7f00 0001 7f00 .<.Q@...=h......
0x0020: 0001 622e 0050 f195 f618 0000 0000 a002 ..b..P..........
0x0030: ffd7 fe30 0000 0204 ffd7 0402 080a 015e ...0...........^
0x0040: 3649 0000 0000 0103 030d 6I........
1973-02-14 22:12:10.785902 IP (tos 0x0, ttl 127, id 0, offset 0, flags [DF], proto TCP (6), length 60)
127.0.0.1.80 > 127.0.0.1.25134: Flags [S.], cksum 0xfe30 (incorrect -> 0x2f28), seq 3928063281, ack 4053136921, win 65483, options [mss 65495,sackOK,TS val 22951497 ecr 22951497,nop,wscale 13], length 0
0x0000: 0000 0000 0000 0000 0000 0000 0800 4500 ..............E.
0x0010: 003c 0000 4000 7f06 fdb9 7f00 0001 7f00 .<..@...........
0x0020: 0001 0050 622e ea21 7d31 f195 f619 a012 ...Pb..!}1......
0x0030: ffcb fe30 0000 0204 ffd7 0402 080a 015e ...0...........^
0x0040: 3649 015e 3649 0103 030d 6I.^6I....
在每种情况下,VM 上的 syn-ack 总是 1970 年至 1973 年之间的某个日期,而 Xeon 上的 syn-ack 则是未来的某个日期。
- 我可以重现这个100%在每个平台上,除了赛扬之外,都花费了不少时间。我们在数据中心不使用赛扬。我只是想找到不受影响的东西。
我还尝试过什么方法来消除这种情况?
- 我曾尝试使用将应用程序固定到核心
taskset
。 - 我尝试设置影响 libc 的不同变量,例如 TZ、LANG、LC_ALL 等...
- 我尝试禁用接口的所有卸载功能,尽管它是一个环回,但这些功能实际上不应该执行任何操作。
- 我尝试了几个不同的 sysctl 设置。
- 我尝试在 tcpdump 中使用不同的 snaplen。(我知道 snaplength 存在一些历史问题)
- 我验证了硬件时钟是正确的。
我还没尝试过
- 我没有尝试设置接收流控制,因为如果没有充分的理由,我们不会在我们的数据中心这样做。
- 我可能还可以尝试无数其他的事情,但这看起来确实像是某种 libc / 缓冲区 / 竞争条件错误。
您对 Linux 代码中可能发生这种情况有什么想法吗?由于我不是 C 开发人员,所以我不太愿意深入研究 glibc。
[更新]它出现@jackthecoiner 发现其他人也遇到了这个问题,但目前还没有在 Redhat 网站上收到任何反馈。
答案1
我已将此提交给CentOS 错误追踪很快得到了确认,他们建议我将其移至Redhat 内核错误追踪器
从那时起,Redhat 开发人员就指出,这个漏洞是bz1473533,已修复于内核-3.10.0-703.el7对于 CentOS 来说,确认的此问题已在 7.5 beta 内核(830.el7)中修复。