环回时第一次 syn-ack 的随机时间戳

环回时第一次 syn-ack 的随机时间戳

前言

我们正在测试一些基于主机的 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)中修复。

相关内容