前些日子遇到一个故障案例,现象是云主机上的机器网络丢失,通过命令无法正常启动网卡,导致各项业务中断,OPS反馈机器只能通过云控制台输入口令进入系统。故障的影响还是比较大的,和OPS一起解决故障并恢复业务后,回家用虚拟机模拟环境来找找根本原因。
故障处理
本文内容使用虚拟机复现故障场景,为了更好地记录,这里先描述故障现象和如何处理。
故障出现后,OPS同步的故障现象信息是机器启动后网络丢失,通过命令无法正常启动网卡:
1)通过ifconfig
看不见业务使用的网卡,通过ip a
可以看到业务网卡,但无网络配置:
1 | 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 |
2)手工通过ifup
启动网卡,但出现报错:
1 | ifup ens33 |
3)在/usr/lib64
下未找到libdns-export.so.100
:
1 | ls -lrt /usr/lib64/libdns-export* |
到了这里可以看出,因为SO库缺失的原因,已经无法启动网卡。这个时候OPS提出了先尝试临时配置静态IP看看是否可用的方案:
1 | 方式一 |
配置完以后,ping网关和同网段内主机均正常,此前中断的SSH恢复。但还需要将缺失的SO从其他机器拷贝一份,让网卡正常启动。
经过一番查找,我们在CentOS 7.5.1804、7.6.1810都找到了libdns-export.so.100
1 | ls -lrt /usr/lib64/libdns-export* |
我们将libdns-export.so.100.1.1
拷贝到故障机器上,并创建软链:
1 | 正常CentOS 7.5 |
完成上述步骤后,通过ifup ens33
尝试启动网卡时出现了新的SO库缺失问题:
1 | ifup ens33 |
同理,在CentOS 7.5.1804、7.6.1810也都找到了libisc-export.so.95
1 | $ ls -lrt /usr/lib64/libisc-export* |
与处理libdns-export.so.100.1.1
的方式相同,对libisc-export.so.95.2.1
进行同样的处理。
1 | 正常CentOS 7.5 |
再次通过ifup ens33
尝试启动网卡,已经能够正常执行,未有错误抛出。systemctl restart network
也启动正常。
另外,如果机器的dhclient在运行中,这一步可能会遇到失败的现象,抛出类似dhclient(22421) is already running - exiting.
的错误,同时systemctl restart network
也无法正常启动。遇到该问题的话,可以通过kill掉dhclient相关进程后再次尝试重启网络解决。
故障复盘
在故障处理完,恢复业务后,还是需要分析下到底什么操作导致了故障出现。
复现环境: CentOS 7.5.1804、CentOS 7.6.1810、CentOS 7.9.2009各一台虚拟机。
已知信息:某项业务部署在CentOS 7.9.2009出现故障,部署在CentOS 7.5.1804、CentOS 7.6.1810状态正常。
出现问题的SO库libdns-export
和libisc-export
经过简单的查询可以确认和DHCP、BIND依赖有关。在业务部署脚本中也确认通过rpm安装了dhcp的几个依赖。
1 | dhcp-common-4.2.5-68.el7.centos.x86_64 |
经过对比,这几个RPM版本是CentOS 7.5.1804、CentOS 7.6.1810中的默认版本。之所以安装这几个RPM的原因是为了自动在低于CentOS 7.5.1804的版本上修复漏洞CVE-2018-1111,该漏洞公开时恰好CentOS 7.5.1804刚发布不久。由于部署脚本日积月累,低于CentOS 7.5.1804的系统目前已经基本不再使用,但这一步骤仍保持着。
系统对比
通过rpm2cpio可以确认,上面的三个rpm并未包含libdns-export
和libisc-export
。于是将目标放在了bind相关的rpm上。
到这里,我们还需要确认libdns-export
和libisc-export
在不同系统上是哪个依赖包释放的。
首先看下CentOS 7.5.1804正常运行的:
1 | rpm -qa | grep bind |
再看下CentOS 7.9.2009出现故障的:
1 | rpm -qa | grep bind |
可以看出,CentOS 7.9.2009和CentOS 7.5.1804的bind依赖包相比,主要有几处不同:
- bind*系列的版本,CentOS 7.9.2009较CentOS 7.5.1804高2个版本
- CentOS 7.9.2009多出一个bind-export-libs
- CentOS 7.9.2009下
libdns-export
和libisc-export
单独存在于/usr/lib64/bind9-export/
中
到此,CentOS 7.9.2009出现故障的原因可以确认是由于部署脚本中安装了修复CVE-2018-1111的几个rpm,导致相关的依赖版本降级后又缺失对应的SO库,造成网卡服务异常。
这里还需要确认一些问题,各个版本的libdns-export
和libisc-export
是由哪个RPM释放的。通过查找对应版本的RPM,利用rpm2cpio,可以看到下面的结果:
在CentOS 7.5.1804中分别由bind-libs-lite和bind-libs释放:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25rpm2cpio bind-libs-lite-9.9.4-61.el7.x86_64.rpm | cpio -idv
./usr/lib64/libdns-export.so.100
./usr/lib64/libdns-export.so.100.1.1
./usr/lib64/libirs-export.so.90
./usr/lib64/libirs-export.so.90.0.1
./usr/lib64/libisc-export.so.95
./usr/lib64/libisc-export.so.95.2.1
./usr/lib64/libisccfg-export.so.90
./usr/lib64/libisccfg-export.so.90.0.7
3550 blocks
rpm2cpio bind-libs-9.9.4-61.el7.x86_64.rpm | cpio -idv
./usr/lib64/libbind9.so.90
./usr/lib64/libbind9.so.90.0.8
./usr/lib64/libdns.so.100
./usr/lib64/libdns.so.100.1.1
./usr/lib64/libisc.so.95
./usr/lib64/libisc.so.95.2.1
./usr/lib64/libisccc.so.90
./usr/lib64/libisccc.so.90.0.4
./usr/lib64/libisccfg.so.90
./usr/lib64/libisccfg.so.90.0.7
./usr/lib64/liblwres.so.90
./usr/lib64/liblwres.so.90.0.5
5294 blocks而在CentOS 7.9.2009中,bind-libs-lite和bind-libs的作用有调整,export相关移动到bind-export-libs释放:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34rpm2cpio bind-libs-lite-9.11.4-26.P2.el7.x86_64.rpm | cpio -idv
./usr/lib64/libdns.so.1102
./usr/lib64/libdns.so.1102.1.2
./usr/lib64/libirs.so.160
./usr/lib64/libirs.so.160.0.5
./usr/lib64/libisc.so.169
./usr/lib64/libisc.so.169.0.3
./usr/lib64/libisccfg.so.160
./usr/lib64/libisccfg.so.160.2.1
6049 blocks
rpm2cpio bind-libs-9.11.4-26.P2.el7.x86_64.rpm | cpio -idv
./usr/lib64/libbind9.so.160
./usr/lib64/libbind9.so.160.0.8
./usr/lib64/libisccc.so.160
./usr/lib64/libisccc.so.160.0.3
./usr/lib64/liblwres.so.160
./usr/lib64/liblwres.so.160.0.2
372 blocks
rpm2cpio bind-export-libs-9.11.4-26.P2.el7.x86_64.rpm | cpio -idv
./etc/ld.so.conf.d/bind-export-x86_64.conf
./usr/lib64/bind9-export
./usr/lib64/bind9-export/libdns-export.so.1102
./usr/lib64/bind9-export/libdns-export.so.1102.1.2
./usr/lib64/bind9-export/libirs-export.so.160
./usr/lib64/bind9-export/libirs-export.so.160.0.5
./usr/lib64/bind9-export/libisc-export.so.169
./usr/lib64/bind9-export/libisc-export.so.169.0.3
./usr/lib64/bind9-export/libisccfg-export.so.160
./usr/lib64/bind9-export/libisccfg-export.so.160.2.1
./usr/share/licenses/bind-export-libs-9.11.4
./usr/share/licenses/bind-export-libs-9.11.4/COPYRIGHT
5879 blocks
故障复现
1、首先在CentOS 7.9.2009上复现这个故障非常的简单:
1)拷贝以下几个rpm并强制安装:
1 | dhcp-common-4.2.5-68.el7.centos.x86_64 |
2)禁用NetworkManager
1 | systemctl stop NetworkManager |
3)systemctl restart network
无法正常重启,journalctl -xe
可以看到SO库缺失
2、另外这里进行了思考,是不是说只要系统版本是CentOS 7.5.1804或者CentOS 7.6.1810就一定没问题呢?经过测试,其实不是的。用刚装好的CentOS 7.5.1804或CentOS 7.6.1810执行完yum update
后,按相同的步骤即可复现。以CentOS 7.5.1804举例:
1)更新前:
1 | rpm -qa | grep bind |
2)执行yum update
,在列表中可以看到如下更新:
1 | Updating: |
可以看出,这里升级完的版本和CentOS 7.9.2009上自带的版本是一致的。在升级完成后执行reboot
,让系统重启一次。再通过上面CentOS 7.9.2009复现的步骤,即可复现出同样的故障。
结束
写到这里故障复盘就结束了,本意是多年前为了修复漏洞的一个操作,在多年以后却成了一个隐患。带来的一些警示:
- 在部署脚本中对于漏洞修复这种敏感场景要标明一个操作是为什么要做,CVE编号是什么,影响的范围是哪里
- 定期审视一些老旧代码是否仍具备合理性
- 定位问题时除了报错和日志,要尽可能的多的收集环境信息,比如系统版本、可怀疑的组件版本等
参考
1、https://zh.wikipedia.org/wiki/CentOS
2、https://access.redhat.com/security/vulnerabilities/3442151
3、https://mobile.mirrors.ustc.edu.cn/centos-vault/centos/7.5.1804/os/x86_64/Packages/