一次busybox溢出导致的kdump失败问题

  1. 问题背景
  2. 排查
  3. 问题根因

问题背景

有一台centos6的物理机宕机却没有生成kdump,需要排查一下kdump失败原因

排查

  • 环境检查

首先检查一下问题机器的基础环境,centos6.3 os+5.10内核+nvme系统盘

  • 对比正常机器

找一个正常机器进行kdump,对比正常机器与异常机器上的串口日志,发现异常机器fsck和mount失败。

然后对比了正常机器和异常机器上的fsck和mount等binary的md5sum,发现是一模一样的,所以排除了binary的问题

  • 在os内进行mount测试

在kdump起小内核的时候mount失败,那么在大内核(也就是正常的OS环境)中能不能手动moung成功呢?

系统内执行mount -t ext4 UUID=c8ba2795-983c-4dfb-a359-xxxxxxxxxxx /mnt是可以mount成功的

那么此时就怀疑大概率就是因为nvme盘mount失败导致小内核启动有问题,从而导致kdump失败不能产生vmcore

  • 进行fsck和mount等相关实验

发现大内核中本来就是有/mnt这个目录的,所以可以mount成功,如果一个目录本身不存在,就不能mount上

那么是不是小内核中本来没有/mnt这个目录,所以mount失败?看一下/sbin/mkdumprd制作initramfs的过程中mount的代码,怀疑是不是在制作小内核把mount命令的参数传丢了?

像这样,如果$DUMPDEV没有值是不是就会出问题?那这个变量是在哪里赋值的?

从log中我们可以知道DUMP_TARGET是UUID=c8ba2795-983c-4dfb-a359-xxxxxxxxxx

难道是findfs没找到 导致变量是空的?在/sbin/mkdumprd中加了点log打印$DUMPDEV等内容,果然,$DUMPDEV是空值

  • 追踪findfs失败原因

这里就差不多实锤上面的怀疑点,基本就是因为findfs失败了。

那么findfs失败在哪里,为什么失败?

接下来我们重新制作initramfs并把把strace打包进initramfs中(可以查看/etc/kdump.conf中的extra_bins字段),然后修改/sbin/mkdumprd脚本在findfs命令前添加上strace命令。

在大内核中执行/usr/bin/strace findfs UUID=c8ba2795-983c-4dfb-a359-xxxxxxxxxxx获取一下日志,然后手动宕机获取kdump串口日志,对比kdump小内核中的strace日志和正常的starce日志,可以发现kdump小内核中的设备号是有问题的!

正常的nvme设备应该使用BLOCK_EXT_MAJOR设备号,是259,而这里是3??

查看include/uapi/linux/major.h发现设备号3属于一种现代系统中几乎不再使用的block设备。

  • 确认nvme盘使用的驱动驱动

那是不是小内核中驱动有问题?重新加log并重做initramfs然后触发宕机查看日志。

发现驱动没有问题,是nvme驱动。

  • 继续追查设备号不对的原因

查看正常机器和异常机器上的mknod –version,是同一个版本。

在/sbin/mkdumprd中制作打包initramfs的添加set -x,然后触发宕机查看串口日志,发现主设备号是259啊?

大模型助攻一波,提示到,3正好是259 % 256啊,难不成mknod溢出了?

在添加掉日志查看mknod系统调用的时候传的是什么?

在执行mknod的时候主设备号还是259,而系统调用的时候主设备号就变成3了。

所以这里可以实锤是mknod的过程有问题,和内核无关。那么mknod的中间处理过程是怎么导致259溢出变成3的?是环境变量有问题还是mknod本身有问题?为什么大内核中测试mknod是支持259的?

  • 最终追查到busybox上

再次对比大内核和小内核,大内核中which mknod返回的是/bin/mknod

而小内核日志中显示用的是/sbin/mknod

然后查看/sbin/mknod,发现它实际上是一个指向busybox的软链接。

在/sbin/mkdumprd中我们可以看到,在制作initramfs的时候可能是为了尽可能减少initramfs的体积,所以使用busybox代替了很多命令,其中就包括mknod。

修改/sbin/mkdumprd,不使用busybox代替mknod,而就是使用原本的/bin/mknod,重新制作intramfs打包,宕机测试没问题,可以产生vmcore。

问题根因

centos6中kdump小内核在启动的时候,执行init的时候静态执行mknod来为设备创建设备文件。而当前centos6上机器使用的kexec-tools包,在制作kdump的initramfs的时候,其实是使用busybox来代替mknod这个binary的,但是当前的这个busybox的版本比较低,在mknod(也就是busybox)制作设备文件的时候,如果是为nvme(主设备号是259)制作设备文件,会产生溢出,259->3(256溢出),所以最终调用mknod系统调用的时候就变成了制作major为3的设备文件,这时候实际上/dev/nvme0n1p1的主设备号是3,而不是259,而系统就需要依据主设备号去找对应的设备驱动,所以才在kdump小内核启动过程中出现了问题。

雪好大,路好滑,大家小心,天天开心

11st


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 857879363@qq.com