Linux崩溃了先别慌,掌握这些技巧就能淡定应对
创始人
2024-09-02 07:55:17
0

Linux崩溃了,你能干什么

如果你发现你的Linux机器重启了,你能查出来是什么原因导致的吗。

绝大多数人是束手无策的,今天,本文(结合真实案例)教你怎么做。

一、首先你要有dump文件

接触过Linux的,大概知道有个core dump的,很多人以为这是核心转储,nonono,它是内存转储的意思,core来源于早年间磁芯存储器的那个磁芯(core)。

实现core dump机制有很多工具,kdump技术是目前最可靠、最常用的,已被主要的Linux厂商选用。当Linux内核崩溃时,kdump工具捕获当时内存等状态信息,生成转储文件(vmcore),保留现场证据,然后才重启。

当然,如果要用kdump,需要安装kdump工具、修改内核启动参数、修改kdump配置文件参数、启动kdump服务功能。

二、怎么解析dump文件

如果你装了kdump,Linux崩溃重启后,你会在/var/crash目录发现vmcore文件,恭喜你,你可以用它来发现根因了。

为了分析core dump,你需要安装crash工具,crash工具是RedHat公司提供的一个开源的内核分析工具,它在gdb的基础上实现了解析内核的功能。

你还需要安装Linux内核相应版本的debuginfo包,这个包安装好后会在操作系统上生成一个vmlinux文件,该文件包含完整的符号信息,用于提供调试信息。

三、怎么使用crash工具

crash工具包括了很多命令,包括查看内核日志的log命令、查看调用栈的bt命令、查看进程情况的ps命令、查看某个地址对应符号的sym命令、查看文件系统信息的files命令等。

总之,有了这个大杀器,你再有一点操作系统知识,有一点编程知识,就能干一般人干不了的事了。

比如,有一天,你发现你的若干台服务器意外重启了,你一脸懵,你的领导责令你务必找到根因。

你就可以悠然打开crash工具,来一趟探因之旅:

crash /usr/lib/debug/lib/modules/2.6.32-754.35.1.el6.x86_64/vmlinux /var/crash/vmcore

上面那个vmlinux,是调试所需的内核镜像;上面那个vmcore,就是core dump。

四、用sys命令看看基本信息

用crash打开vmcore文件后,使用sys命令,你可以看到系统内核的基本信息,比如崩溃时系统中的进程数量、系统内核版本、内存大小、系统崩溃时的报错信息等。

比如,报错信息是:BUG: unable to handle kernel paging request at ffffffffa0395070

懂的人都懂,这是内核分页请求报错。

可能的原因是:错误的内存访问、内存不足、硬件故障等等。

当然最可能的是:错误的内存访问。

下面,我们用bt命令看看内核崩溃的调用栈信息。

所谓调用栈,就是谁调用了谁,谁又进一步调用了谁。

五、用bt命令查看进程信息

这一步是非常重要的,毕竟,我们非常想看到,机器是怎么一步步崩溃的。

使用crash工具的bt命令(栈跟踪backtrace的缩写)查看调用栈信息,显示信息如下:

crash> bt

第1行 PID: 177488 TASK: ffff880435b92ab0 CPU: 2 COMMAND: "ss"

第2行 #0 [ffff880437c0b7e0] machine_kexec at ffffffff8104179b

第3行 #1 [ffff880437c0b840] crash_kexec at ffffffff810d7a52

第4行 #2 [ffff880437c0b910] oops_end at ffffffff81560310

……

第10行 #8 [ffff880437c0bb40] page_fault at ffffffff8155f265

第11行 [exception RIP: strnlen+9]

第12行 RIP: ffffffff812ae3a9 RSP: ffff880437c0bbf8 RFLAGS: 00010286

……

第25行 #15 [ffff880437c0be70] proc_reg_read at ffffffff8120faf0

第26行 #16 [ffff880437c0bec0] vfs_read at ffffffff811a3447

第27行 #17 [ffff880437c0bf00] sys_read at ffffffff811a3791

第28行 #18 [ffff880437c0bf50] system_call_fastpath at ffffffff81566391

不用细看,bt在第一行就说了,崩溃就是“ss”这个程序引起的。从第28行开始,ss调用了system_call_fastpath、然后是sys_read(第27行)、然后是我这里省略了的一连串调用,然后是第10行令人胆战心惊的page_fault,然后是oops_end(哦,要完蛋了,第4行)、crash_kexec(准备kdump,第3行)、machine_kexec(调起一个新内核采集信息,第1行),然后kdump就生成了core dump文件:vmcore。

注意第25行,可以看出ss干了一件事,调用了proc_reg_read,这表明它读了proc文件系统。

proc是一个虚拟文件系统,提供了内核和进程的运行信息。

ss读proc文件是正常的,因为要读取一些内核层面的信息,但正是这个读,导致了崩溃。

注:ss是一个用于查看和分析Linux系统中的网络连接和套接字(socket)状态的工具。它是 netstat命令的替代品,通常比netstat更加高效和快速。

下面我们看看ss这个进程的具体信息。

六、用ps命令查看都有哪些进程

使用crash工具的ps命令查询内核崩溃前所有进程的状态信息

比如:

crash> ps

PID PPID CPU TASK ST %MEM VSZ RSS COMM

...

177488 64302 1 ffff880436662ab0 RU 0.0 6280 568 ss

...

当然,崩溃时的进程有很多了,这里只显示ss进程,可以看到它的进程号为177488。

有了ss的进程信息,现在我们看看ss到底调用了哪个文件。

七、用files命令查看进程访问了哪个文件

一般是使用struct file命令查看某进程访问文件的信息。

刚才我们用ps命令查到ss的进程地址为ffff880436662ab0,用它作为struct file的输入参数。

crash> struct file.f_path ffff880436662ab0

f_path = {

mnt = 0xffff880432adbe80,

dentry = 0xffff880101cae5c0

}

该命令显示了ss进程访问文件路径的结构信息,mnt表示文件所在的挂载点,dentry表示文件名在地址ffff880101cae5c0。

接下来使用files命令来解析这个dentry地址。

crash> files -d 0xffff880101cae5c0

DENTRY INODE SUPERBLK TYPE PATH

ffff880101cae5c0 ffff880101c1d598 ffff88043a23e800 REG /proc/slabinfo

此时可以得知,故障时,ss进程访问的文件是/proc/slabinfo。

注:/proc/slabinfo文件包含了当前内核中所有slab内存的详细信息。

八、使用sym命令看故障相关源码

从前面bt命令的调用栈信息看到,异常报错位置为[exception RIP: strnlen+9](第11行),RIP指向异常调用地址为ffffffff812ae3a9(第12行)。

使用sym命令,看看这个异常地址是个啥。

crash> sym ffffffff812ae3a9

ffffffff812ae3a9 (T) strnlen+9 /usr/src/debug/kernel-2.6.32-754.35.1.el6/ linux-2.6.32-754.35.1.el6.x86_64/lib/string.c: 407

这个命令很牛,它告诉我们,这个异常地址,对应的源码(string.c)和行号(第407行)都告诉我们了。

我第一次见到这个的时候,不禁惊呼,这么牛啊,从内存dump能看出问题源码在哪?

对,就这么牛,kdump很牛,debuginfo也很牛,一个用于调试,一个提供调试信息,程序员不会亏待自己的。

注:当你调试一个内核时,需要安装对应版本的debuginfo包,如下:

debuginfo-install kernel-debuginfo-common-2.6.32-754.35.1.el6.x86_64.rpm

当然,看到源码并不稀奇,Linux是开源的嘛!(如果你玩Windows,如果机器崩溃了,那就崩溃了吧。)

这段完整代码如下:

size_t strlen(const char *s) {

const char *sc;

for (sc = s; *sc != '\0'; ++sc)/*这就是那个第407行*/;

return sc - s;

}

这段代码通过for循环,从输入字符串初始字符s开始,遍历其所指的内容,循环直到遇到字符串结尾的空字符'\0',最后返回字符串长度。

那个*sc就是读sc这个地址里的内容。

但是,读着读着,就崩溃了,因为读到翔了。

九、用log命令查更多的内容

使用log命令查到的信息如下:

crash> log

...

VMAGENTMOD: 3846: init_module: get into init_module, syshook_enable:1

VMAGENTMOD: 177350: cleanup_module: get into cleanup_module

...

可以看出,内核崩溃前,有加载和卸载某个驱动模块的动作。相关的进程号是3846和177350。

经查询,这2个进程号都属于防病毒工具的进程。它调用的cleanup_module是内核函数,用于卸载驱动模块。

用crash的mod -t命令,显示内核模块加载的详细信息:

crash> mod -t

NAME TAINTS

syshook_linux (U)

vmsecmod (U)

在log命令的输出中,还可以看到“[last unloaded: vmsecmod]”,这说明,内核最后卸载的驱动模块就是vmsecmod。

另外,防病毒工具的本地日志也显示,服务器重启前刚刚执行了停止防病毒进程的操作。

这些信息都告诉我们,这次崩溃的发生,防病毒工具有相当的嫌疑。

注:mod的-t选项,是显示taints信息。所谓taints(污点),是内核运行时的一个标志,用来指示内核在运行过程中遇到了某些潜在问题或非标准情况。如果taints是U,表明该模块是未经签名的,是用户开发的。

十、回到sys命令

我们最开始使用sys命令查到有如下的报错信息:

BUG: unable to handle kernel paging request at ffffffffa0395070

用sym命令看看这个地方到底是何方神圣。

crash> sym ffffffffa0395070

ffffffffa0395070 (r) hash_info_mempool_name [vmsecmod]

可以看到,这个地址来自vmsecmod驱动,对应的源码是hash_info_mempool_name。

现在基本可以判断出来是怎么回事:

防病毒工具申请并使用了slab分配器提供的内存,相关信息记录在/proc/slabinfo中,ss进程会去查询slabinfo,获取必要的信息。就是在访问slabinfo时,造成了内核崩溃。

有人在崩溃前卸载了防病毒的驱动,停止了防病毒服务,按道理,防病毒申请的slab内存应该也释放掉,slabinfo中也不会有对应信息。但是,ss进程居然还在访问这块数据,说明防病毒进程申请的slab内存未正常释放!

知识普及:slab主要用于内核态中的内存分配,可高效分配和管理小块内存。在/proc/slabinfo这个虚拟文件中,记录了系统中所有slab内存块的信息,如对象数量和内存使用量等。ss读取/proc/slabinfo,获取与网络套接字相关的内存使用和分配信息,提供详细的网络连接状态。

十一、原来是防病毒工具的bug

把上述信息给到防病毒厂商,他们的研发工程师分析确认,确实是防病毒客户端有bug,导致了这次重启。

bug很简单,就是在卸载vmsecmod驱动时,应该同步释放所申请的slab内存区,但程序员没有这么做。

在重启的服务器上,有服务器管理工具,它会定期调用ss命令,ss会读取slabinfo,防病毒没有释放slab内存,所以ss仍然可以读取slabinfo中的指针,该指针却指向了已经释放了内存区(vmsecmod驱动曾经用过的地方)。

由于指针指向的内存已经释放,所以这就是访问非法地址,其实就是分页机制无法将该地址映射到物理地址,此时处理器就会向操作系统发出一个“page fault”错误,如果处理器此时处于超级用户模式,系统就会产生一个Oops,哦,完蛋了。

注:如果在用户态访问了非法地址,那么,你大概会得到一个经典的Segmentation fault(初级程序员的噩梦)。

十二、当时发生了什么?

那天,某个工程师做了一件事,更新防病毒工具的许可,这个防病毒工具是企业版的,有一个管理端,还有运行在若干台服务器上的防病毒客户端。

他先在防病毒管理端导入软件许可,接着管理端将软件许可分发给每台服务器上的客户端,由客户端本地更新许可文件。

在客户端更新许可文件时,会先停止防病毒客户端进程(更新完许可文件后,再启动进程),停止进程会导致vmsecmod驱动模块的卸载,由于有bug,清理动作不完善,残留了无主的slab内存。

而服务器上部署的自动化工具,会定时执行ss命令,ss遍历slabinfo信息时,读取了在野的指针,引发page fault,内核崩溃。

后记

Linux这么稳定的内核都会崩溃。

做一个内核稳定的人,很不容易呢。

注:本文是一个简单的介绍,相对完整的分析见《小白也能看懂的Linux崩溃分析大法》 作者:卫剑钒 首发:2024.7.17

最后浅浅地插播一条广告。

各位读者如果想深入了解 Linux 内核底层技术原理,请阅读下文:

做难而正确的事情,成为技术书里的“黑神话”

相关内容

韩国AI初创公司CEO:目...
【CNMO科技消息】CNMO从韩媒获悉,韩国AI初创企业Liner...
2025-07-14 18:42:15
AI“竞岗”华尔街高端职位...
▲资料图:位于华尔街的纽约证券交易所 图源/视觉中国 从“AI...
2025-07-13 20:11:43
因为微软,OpenAI收购...
OpenAI收购AI编程助手Windsurf的谈判因微软知识产权担...
2025-07-12 13:14:23
美工课程视频讲解:零基础也...
你是不是也这样:收藏夹里塞满了各种“美工入门教程”、“PS速成课”...
2025-07-12 13:14:12
告别“无效阅读”,AI正在...
学校管理者为零散的阅读活动、无法量化的成果而苦恼; 一线教师在“选...
2025-07-12 12:42:00
驱动智能转型 业界推动AI...
人民网北京7月11日电(记者许维娜)清晨7点,一家钢铁企业的班前会...
2025-07-12 12:41:51

热门资讯

原创 2... #春日生活好物种草季#近年来,笔记本电脑市场迎来技术爆发期,尤其在手机厂商跨界入局后,轻薄本在性能、...
AMD锐龙AI 9 HX 37... 2024年6月3日,AMD正式发布全新的锐龙AI 300系列处理器。该系列处理器一经发布就引发大家的...
骁龙本这么猛?联想YOGA A... 在人人都是自媒体的时代,一部手机可以解决出镜拍摄问题,而商务出差、大量码字、图像处理等需求用笔记本则...
5个AI模特生成软件推荐 当前AI模特生成软件市场提供了多样化的解决方案,以下是几款备受推崇的工具: 触站AI:强烈推荐!...
2023年CentOS与Ubu... CentOS与Ubuntu的市场格局与技术特性探讨 在服务器操作系统领域,CentOS与Ubuntu...
苹果macOS 15.1:允许... 苹果公司在其最新的macOS 15.1版本中,推出了一项引人注目的新功能——允许用户将Mac App...
原创 苹... 前言 IQUNIX在做好看的桌面产品上,一直都给我留下非常深刻的印象。而且早期和苹果产品的设计风格...
原创 华... 想在竞争残酷的市场中发力,必须要带来一些激进的卖点,但是随着功能特性的提升,硬件也必须要进行给力才可...
原创 华... 在2024年这个被誉为"AI元年"的关键时刻,随着生成式AI的流行,各家手机厂商都在积极备战AI手机...