TCP SACK PANIC - 内核安全漏洞 - CVE-2019-11477、CVE-2019-11478 和 CVE-2019-11479
此信息是否有帮助?
概述
在 Linux 内核处理 TCP 网络数据的操作中发现了三个相关的安全漏洞。 其最严重的安全漏洞会被远程攻击者利用在运行受影响软件的系统上触发一个内核崩溃,从而影响到系统的可用性。
这些问题已被记录为以下 CVE: CVE-2019-11477(严重性级别为Important(重要)), CVE-2019-11478 和 CVE-2019-11479 (严重性级别为Moderate(中度))。
其中前两个与 SACK(Selective Acknowledgement,选择性确认)数据包和 MSS(Maximum Segment Size,最大分段长度)相关,第三个只与 MSS 相关。
这些问题可以通过使用相应的缓解方案或对内核进行打补丁来解决。 相应的缓解方案信息及 RHSA 公告的链接包括在此文档的解决方案页中。
问题详情及背景信息
在 Linux 内核处理 TCP SACK(Selective Acknowledgement,选择性确认)及具有小的 MSS 值的逻辑中发现了三个相关的安全漏洞。到目前为止,这些安全漏洞的影响还只限于 DoS 攻击。目前还没有发现这些安全漏洞会导致访问权限升级及信息泄露的问题。
本文档中介绍的缓解方案会对防范这些安全漏洞起到作用,但可能也会影响到需要较小 MSS 值进行传输的正常网络操作及系统性能。请在使用缓解方案前评估它是否适合于您具体的系统环境。
什么是选择性确认?
TCP 选择性确认(Selective Acknowledgment,简称 SACK)是一种确认机制,数据接收方通过它告知发送方已被成功接受的所有数据段。这样,发送方就可以重新发送那些没有出现在 ‘known good’ 数据中的数据段。如果 TCP SACK 被禁用,则需要在某些数据丢失时重新发送包括大量数据的所有数据流。
什么是 MSS
MSS(maximum segment size,最大分段长度)是在数据包的 TCP 报头中设置的一个参数,它指定了在一个重新构建的 TCP 数据段中数据的总量。
当数据包通过不同路由进行传输的过程中可能会被分隔为多个数据段,主机需要把 MSS 设置为和主机可以处理的最大 IP 数据报中实际数据量相同的值。一个大的 MSS 值可能意味着一个数据包流在传输到目的地址过程中被分隔为多个数据段,对于较小的数据包,这可以确保较少的数据段,但可能会导致一些无用的资源消耗。
操作系统及传输类型可能会默认使用特定的 MSS 值。具有特定权限的攻击者可以创建一组带有精心设计的 MSS 选项的数据包对系统进行攻击。
TCP SACK:
TCP 是一种面向连接的协议。当两方希望通过 TCP 连接进行通信时,需要通过交换一些信息来创建一个连接,例如请求启动(SYN)连接,初始序列号,确认号,MSS,发送并处理 SACK 的权限等。该连接建立过程被称为三次握手。
TCP 通过一个被称为段(Segment)的数据单元来发送并接收用户数据。一个 TCP 段包括 TCP 报头(header),选项和用户数据。
每个TCP 段都有一个序列号(SEQ)和确认号(ACK)。
这些 SEQ 和 ACK 号被用来跟踪哪些段已被接收者成功接收到。ACK 号代表接收者期望接收到的下一个段。
例如:用户“A”通过每个为 100 个字节的 13 个段发送 1K 数据(每个段包括 20 字节的报头数据,所以需要 13 个段)。在接收端,用户“B”接收到段1、2、4、6 及 8-13,段 3、5 和 7 丢失没有被用户“B”接收到。
通过使用 ACK 号,用户“B”指示它正期待接收段3,而用户“A”会理解为用户“B”没有接收到段 2 后的数据,因此将重新发送从段 3 开始的所有数据段,即使段 4、6 和 8-13 已被用户“B”成功接收到。用户“B”无法明确告知用户“A”实际的情况。这将会导致降低网络的使用效率。
选择性确认:SACK
为了克服以上问题,在 RFC-2018 中定义了一个选择性确认(SACK)机制。通过使用 SACK,上例中的用户 ‘B’ 可以使用 TCP 选项来告知用户 ‘A’ 段 1、2、4、6 和 8-13 已被成功接收到,因此用户 ‘A’ 只需要重新发送段 3、5 和 7。这样,就可以大大节省带宽资源并减少网络阻塞的问题。
CVE-2019-11477 SACK Panic:
Socket Buffers(SKB):
Socket Buffer (SKB) 是 Linux TCP/IP 实现中使用的一个中央化数据结构。它是一组包含网络数据包的缓冲区链接列表。这个列表可以作为传输(Transmission)队列、接收(Receive)队列、SACK(SACK’d) 队列及重新传输队列等。SKB 以段的形式保存数据包的数据。Linux SKB 可以保存最多 17 个段。
linux/include/linux/skbuff.h
define MAX_SKB_FRAGS (65536/PAGE_SIZE + 1) => 17
在 x86 系统上每个段最多可以保存 32KB 数据(在 PowerPC 上可以保存最多64KB)。当数据包需要被发送时,它会被放置到发送(Send)队列中,它的详细信息会保存在一个中央的控制缓冲结构中:
linux/include/linux/skbuff.h
struct tcp_skb_cb {
__u32 seq; /* Starting sequence number */
__u32 end_seq; /* SEQ + FIN + SYN + datalen */
__u32 tcp_tw_isn;
struct {
u16 tcp_gso_segs;
u16 tcp_gso_size;
};
__u8 tcp_flags; /2* TCP header flags. (tcp[13]) */
…
}
其中,‘tcp_gso_segs’ 和 ‘tcp_gso_size’ 被用来告诉设备驱动关于段卸载(segmentation offload)的信息。
当同时启用了段卸载和 SACK 机制时,因为会出现数据包丢失并选择性地重新发送一些数据包的情况,因此 SKB 可能会出现保存多个数据包的情况(由 ‘tcp_gso_segs’ 记录)。列表中多个这样的 SKB 可以被合并为一个,以便有效地处理不同的 SACK 块。这会涉及到把数据从列表中的一个 SKB 移到另一个的情况。在移动数据的过程中,SKB 结构可能会达到它的 17 段的最大极限,‘tcp_gso_segs’ 参数就可能出现溢出并调用以下的 BUG_ON() 功能并最终可能导致内核崩溃的问题。
static bool tcp_shifted_skb (struct sock *sk, …, unsigned int pcount, ...)
{
...
tcp_skb_pcount_add(prev, pcount);
BUG_ON(tcp_skb_pcount(skb) < pcount); <= SACK panic
tcp_skb_pcount_add(skb, -pcount);
…
}
一个远程用户可以通过把 TCP 连接的 MSS 值设置为最低的 48 字节,并发送一组经过特殊设计的 SACK 数据包来触发以上介绍的问题。在使用最小的 MSS 值时,每个段只为数据提供 8 字节的空间,从而增加了需要发送所有数据的 TCP 段的数量。
致谢
Jonathan Looney (Netflix Information Security)
参考资源
RFC-2018 - TCP selective acknowledgments
How SKB’s work
Netflix (reporters) original report.
受影响的产品
红帽产品安全团队已把此更新的安全影响级别定为“Important(重要)”。
以下红帽产品版本会受到影响:
直接受影响的产品
- Red Hat Enterprise Linux 8
- Red Hat Enterprise Linux 7
- Red Hat Enterprise Linux 6
- Red Hat Enterprise Linux 5
- Red Hat Atomic Host
- Red Hat Enterprise MRG 2
- Red Hat OpenShift Container Platform 4 (RHEL CoreOS)
- Red Hat OpenShift Online
- Red Hat OpenShift Dedicated (及依赖的服务)
- OpenShift on Azure (ARO)
- Red Hat OpenStack Platform (镜像所带的内核)
- Red Hat Virtualization (RHV-H)
间接受影响的产品(底层平台需要被更新)
- Red Hat Virtualization (RHV)
- Red Hat OpenStack Platform
- Red Hat OpenShift Container Platform 3
虽然红帽的 Linux 容器不会直接受到内核安全漏洞的影响,但是它们的安全性依赖于所在主机的内核环境。红帽建议您使用最新版本的容器镜像。Container Health Index(Red Hat Container Catalog 的一部分)可以用来检查红帽容器的安全状态。为了保护所有容器的隐私,需要确保所使用的容器主机(例如,Red Hat Enterprise Linux,CoreOS 或 Atomic Host)已进行了可以解决这个安全问题的更新。红帽已发布了一个可以解决这个问题的 Atomic Host 更新版本。
受影响的红帽产品(按 CVE 分类)
CVE-2019-11477 重要 | CVE-2019-11478 中度 | CVE-2019-11479 中度 | |
RHEL 8 (kernel, kernel-rt) | 受影响 - 将会修复所有有效的版本 | 受影响 - 将会修复所有有效的版本 | 受影响 - 将会修复所有有效的版本 |
RHEL 7 (kernel, kernel-rt) | 受影响 - 将会修复所有有效的版本 | 受影响 - 将会修复所有有效的版本 | 受影响 - 将会修复所有有效的版本 |
RHEL 6 | 受影响 - 将会修复所有有效的版本 | 受影响 - 将会修复所有有效的版本 | 受影响 - 将会修复所有有效的版本 |
RHEL 5 | 不受影响 | 受影响(将不会修复,已超出支持的范围) | 受影响(将不会修复,已超出支持的范围) |
问题详情及背景信息
研究人员报告了以下三个安全漏洞。以下是每个安全漏洞的简短说明及其影响。
CVE-2019-11477
这个 Linux 内核的安全漏洞是由 16 位 TCP_SKB_CB(skb)->tcp_gso_segs 中的一个整数溢出造成的。一个远程攻击者可以利用这个问题使系统崩溃,从而导致 DoS。
CVE-2019-11478
攻击者可以利用这个 Linux 内核安全漏洞,发送一组经过精心设计的 SACK 数据包来使 TCP 重新发送队列被分段。攻击者再利用分段的队列,使系统在处理使用相同 TCP 连接所接收到的后续 SACK 数据包时消耗大量资源。 这将导致 CPU 花费大量时间来重新构建数据列,从而最终出现 DoS 问题。
CVE-2019-11479
攻击者可以利用这个 Linux 内核的安全漏洞,发送一组经过精心设计的、带有低 MSS 值的数据包来致使系统消耗大量资源对它们进行处理。攻击者可以强制 Linux 内核把它的响应分为多个 TCP 段,每个段只包括 8 字节数据。这会极大增加在处理相同的数据量时所需要的带宽。另外,这还会导致需要消耗其他额外的资源(CPU 和 NIC 的处理资源)。利用这个漏洞进行攻击需要攻击者持续不断地进行操作,而其带来的影响会在攻击者停止发送攻击数据后的短时间内结束。 在攻击进行期间,系统的可用资源将会减少,对于一些用户可能会出现 DoS 问题。
诊断漏洞
使用检测脚本来检测您的系统目前是否受到该漏洞的影响。要验证脚本的真实性,请下载GPG 签名。
采取行动
我们强烈建议,使用受影响版本的红帽产品的用户在相关勘误可用时马上进行更新。用户需要在相应更新可用时尽快对系统进行更新,并根据自己的情况在适当的时候进行相应的缓解方案。
一个 kpatch 将为运行支持的 Red Hat Enterprise Linux 7 版本及更高版本的用户提供。请创建一个支持问题单以获取这个 kpatch。
关于 kpatch 的详细信息: RHEL 7 及更新版本是否支持 kpatch?
受影响产品的更新
产品 | 软件包 | 公告/更新 |
Red Hat Enterprise Linux 8 (z-stream) | kernel | RHSA-2019:1479 |
Red Hat Enterprise Linux 8 | kernel-rt | RHSA-2019:1480 |
Red Hat Enterprise Linux 7 (z-stream) | kernel | RHSA-2019:1481 |
Red Hat Enterprise Linux 7 | kernel-rt | RHSA-2019:1486 |
Red Hat Enterprise Linux 7.5 Extended Update Support [1] | kernel | RHSA-2019:1482 |
Red Hat Enterprise Linux 7.4 Extended Update Support [1] | kernel | RHSA-2019:1483 |
Red Hat Enterprise Linux 7.3 Update Services for SAP Solutions, & Advanced Update Support [2], [3] | kernel | RHSA-2019:1484 |
Red Hat Enterprise Linux 7.2 Update Services for SAP Solutions, & Advanced Update Support [2], [3] | kernel | RHSA-2019:1485 |
Red Hat Enterprise Linux 6 (z-stream) | kernel | RHSA-2019:1488 |
Red Hat Enterprise Linux 6.6 Advanced Update Support [2] | kernel | RHSA-2019:1489 |
Red Hat Enterprise Linux 6.5 Advanced Update Support [2] | kernel | RHSA-2019:1490 |
Red Hat Enterprise Linux 5 Extended Lifecycle Support [5] | kernel | 参见以下部分 |
RHEL Atomic Host [4] | kernel | respin 待定 |
Red Hat Enterprise MRG 2 | kernel-rt | RHSA-2019:1487 |
Red Hat Virtualization 4 | virtualization host | 待定 |
[1] 需要一个有效的 EUS 订阅才可以获得这个补丁。 如果您还没有一个有效的 EUS 订阅,请联系红帽的销售人员或您的销售代表。
什么是 Red Hat Enterprise Linux Extended Update Support 订阅?
[2] 需要一个有效的 AUS 订阅才可以获得 RHEL AUS 中的这个补丁。
什么是 Advanced mission critical Update Support (AUS)?
[3] 需要一个有效的 Update Services for SAP Solutions Add-on 或 TUS 订阅才可以获得 RHEL E4S / TUS 中的这个补丁。
[4] 如需了解如何更新 Red Hat Enterprise Atomic Host 的详细信息,请参阅部署一个特定版本的 Red Hat Enterprise Atomic Host。
FAQ: Red Hat Enterprise Linux 5 Extended Life Cycle Support (ELS) Add-On
[5] 目前,基于这些安全漏洞的严重程度,虽然 Red Hat Enterprise Linux 5 仍然处于支持生命周期内,RHEL5 中的相关问题将不会被解决。 如有需要,请联系红帽支持以获取升级及其他选择的信息。
缓解方案
为了缓解 CVE-2019-11477 和 CVE-2019-11478 的影响,可以禁用存在安全漏洞的组件[选择 1],或通过防火墙丢弃那些使用可以被漏洞利用的 MSS 值的连接[选择 2]。
选择 1
在系统范围内对所有新建立的 TCP 连接禁用选择性确认(SACK)。
# echo 0 > /proc/sys/net/ipv4/tcp_sack
或
# sysctl -w net.ipv4.tcp_sack=0
此选项将禁用选择性确认,但可能会增加发生错误时需要重新正确发送数据流所需要的带宽。
为了使这个设置在重启后仍然有效,在 /etc/sysctl.d/ 中创建带有以下内容的文件,如 /etc/sysctl.d/99-tcpsack.conf :
# CVE-2019-11477 & CVE-2019-11478
net.ipv4.tcp_sack=0
对于 Red Hat OpenShift Container Platform (OCP) 4.x,node tuning operators 可以用来使 sysctl 设置在多个节点上具有持久性。对于一个默认的 OCP 4.1 安装,可以通过在 ‘openshift’ 默认的 tuned 配置档案中添加 sysctl 以使设置在所有节点上生效。
$ oc edit tuned/default -n openshift-cluster-node-tuning-operator
...
spec:
profile:
- data: |
[main]
summary=Optimize systems running OpenShift (parent profile)
...
[sysctl]
net.ipv4.tcp_sack=0
...
name: openshift
详情请参阅产品文档。
选择 2 通过禁止在新连接中使用小的 MSS 来缓解CVE-2019-11477、CVE-2019-11478 和 CVE-2019-11479 的影响。
Red Hat Enterprise Linux 7 和 8 中默认的防火墙配置是 firewalld。 使用以下命令通过 firewalld 禁止在新连接中使用小的 MSS 值。
# firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -p tcp --tcp-flags SYN SYN -m tcpmss --mss 1:500 -j DROP
# firewall-cmd --permanent --direct --add-rule ipv6 filter INPUT 0 -p tcp --tcp-flags SYN SYN -m tcpmss --mss 1:500 -j DROP
# firewall-cmd --reload
# firewall-cmd --permanent --direct --get-all-rules
这个 firewall-cmd 命令会在系统重新启动后仍然有效。
如果在 Red Hat Enterprise Linux 中使用 iptables 作为防火墙,相应的 iptables 命令如下:
# iptables -I INPUT -p tcp --tcp-flags SYN SYN -m tcpmss --mss 1:500 -j DROP
# ip6tables -I INPUT -p tcp --tcp-flags SYN SYN -m tcpmss --mss 1:500 -j DROP# iptables -nL -v
# ip6tables -nL -v
这个方法会丢弃所有 MSS 的值在 1 和 500 之间的连接。请注意,这也可能会导致拒绝一些有效的连接。这个缓解方案在 net.ipv4.tcp_mtu_probing 被禁用时有效。
为了确保系统重新启动后相关的 iptables 命令仍然有效,请参阅此文档。
Ansible playbook
另外,以下还提供了一个 Ansible playbook(disable_tcpsack_mitigate.yml)。这个 playbook 会禁用 SACK 功能并使这个变化具有持久性。在使用这个 playbook 时,需要使用 HOSTS 参数指定禁用 SACK 的主机:
ansible-playbook -e HOSTS=web,mail,ldap04 disable_tcpsack_mitigate.yml
为了验证 playbook 的真实性,请下载 GPG 签名。
Comments