3. 模拟启动故障:模拟磁盘损坏导致的启动失败
磁盘损坏是生产环境中导致系统启动失败的常见硬件故障之一。在 QEMU 环境中,我们可以通过构造损坏的磁盘镜像或修改磁盘控制器参数,精确复现“磁盘不可读”、“分区表损坏”以及“MBR 引导扇区失效”等典型场景。本节将演示如何创建故障磁盘、配置 QEMU 启动参数,并通过调试手段定位故障根因。
3.1 磁盘损坏的典型表现与分类
当磁盘出现物理或逻辑损坏时,系统启动过程会在不同阶段表现出异常。下表总结了三种常见磁盘故障类型及其在启动过程中的典型现象:
| 故障类型 | 模拟方法 | 启动阶段 | 典型错误信息 |
|---|---|---|---|
| MBR 引导扇区损坏 | 使用 dd 清零磁盘前 512 字节 |
BIOS/UEFI 加载引导程序 | Boot failed: not a bootable disk |
| 分区表损坏 | 修改 GPT/MBR 分区表关键字段 | 引导加载程序读取分区表 | Invalid partition table |
| 文件系统超级块损坏 | 使用 dd 覆盖文件系统元数据区域 |
内核挂载根文件系统 | VFS: Unable to mount root fs |
调试要点: 在 QEMU 中模拟磁盘故障时,建议保留一份原始完好磁盘镜像的备份。通过对比正常启动与故障启动的日志输出,可以快速定位故障发生的精确阶段。
3.2 模拟 MBR 引导扇区损坏
MBR(主引导记录)位于磁盘的第一个扇区(LBA 0),包含引导代码和分区表。损坏 MBR 将导致 BIOS 无法找到可引导设备。以下是完整的模拟与调试步骤:
- 准备磁盘镜像: 使用
qemu-img创建一块 1GB 的原始格式磁盘,并安装一个最小化 Linux 系统。 - 备份原始 MBR:
dd if=disk.img of=mbr_backup.bin bs=512 count=1 - 损坏 MBR:
dd if=/dev/zero of=disk.img bs=512 count=1 conv=notrunc - 启动 QEMU 并观察故障:
qemu-system-x86_64 \
-drive file=disk.img,format=raw,if=ide \
-m 1024 \
-boot order=c \
-serial stdio \
-d cpu_reset,int \
-D qemu_debug.log
启动后,QEMU 控制台将输出类似以下信息:
Booting from Hard Disk...
Boot failed: not a bootable disk
No bootable device.
调试分析: 从 QEMU 的
-d cpu_reset,int 日志中可以看到,CPU 在尝试执行 MBR 代码时立即触发异常(#PF 页故障),因为前 512 字节已被清零,CPU 读取到的是全零指令(非法操作码)。通过 info registers 监控 CPU 的 CS:EIP 寄存器,可以确认 CPU 停留在 0xFFFF0(BIOS 入口)与 0x7C00(MBR 加载地址)之间循环。
3.3 模拟分区表损坏
分区表损坏通常发生在 MBR 或 GPT 头部被篡改的场景。以下示例演示如何破坏 GPT 主分区表,导致 GRUB 无法识别磁盘布局:
# 使用 hexdump 查看 GPT 头部(LBA 1)
dd if=disk.img bs=512 skip=1 count=1 | hexdump -C
# 破坏 GPT 头部的签名("EFI PART" 位于偏移 0x00)
printf '\x00\x00\x00\x00\x00\x00\x00\x00' | \
dd of=disk.img bs=1 seek=512 conv=notrunc count=8
启动 QEMU 后,GRUB 将输出:
error: invalid signature.
Entering rescue mode...
grub rescue>
| 损坏区域 | 偏移位置 | QEMU 调试方法 |
|---|---|---|
| GPT 签名 | LBA 1, 偏移 0x00 | pmemsave 0x7c00 0x200 dump.bin |
| GPT 分区表项 | LBA 2-33 | info mtree -f 查看内存映射 |
| MBR 分区表 | LBA 0, 偏移 0x1BE | xp /16xb 0x7c00+0x1BE |
3.4 模拟文件系统超级块损坏
当内核成功加载并尝试挂载根文件系统时,如果超级块损坏,将触发内核 panic。模拟方法如下:
# 确定 ext4 超级块位置(通常位于偏移 1024 字节处)
dd if=/dev/urandom of=disk.img bs=1024 seek=1 count=1 conv=notrunc
启动 QEMU 并添加 -kernel 和 -append 参数以捕获完整内核日志:
qemu-system-x86_64 \
-drive file=disk.img,format=raw,if=ide \
-kernel /boot/vmlinuz \
-append "root=/dev/sda1 console=ttyS0" \
-serial stdio \
-d trace:ext4_* \
-D ext4_trace.log
内核日志将显示:
[ 1.234567] EXT4-fs (sda1): bad geometry: block count exceeds size of device
[ 1.234567] VFS: Cannot open root device "sda1" or unknown-block(8,1): error -5
[ 1.234567] Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(8,1)
3.5 磁盘故障启动流程 SVG 图
下图展示了从 BIOS 到内核挂载根文件系统的完整启动链路,并标注了三种磁盘故障的触发位置:
3.6 使用 QEMU Monitor 进行故障诊断
当磁盘故障导致系统卡死或 panic 时,QEMU Monitor 是定位问题的核心工具。以下是在故障场景下的常用诊断命令:
关键命令速查表:
| QEMU Monitor 命令 | 用途 | 故障场景示例 |
|---|---|---|
info block |
查看块设备状态 | 确认磁盘是否被正确识别 |
xp /16xb 0x7c00 |
查看物理内存中的 MBR 内容 | MBR 损坏时显示全零 |
info registers |
查看 CPU 寄存器状态 | CS:EIP 是否指向 0x7C00 |
gdbserver |
启动 GDB 远程调试 | 单步跟踪引导代码执行 |
pmemsave |
保存物理内存到文件 | 导出 MBR 或分区表进行分析 |
3.7 自动化故障注入脚本
为了在课程实验中快速切换不同故障场景,建议使用以下 Shell 脚本进行自动化故障注入:
#!/bin/bash
# disk_fault_injector.sh - 磁盘故障注入工具
DISK_IMG="disk.img"
BACKUP_DIR="./backups"
inject_mbr_fault() {
echo "[*] 注入 MBR 损坏故障..."
dd if=/dev/zero of=${DISK_IMG} bs=512 count=1 conv=notrunc
echo "[+] MBR 已损坏,启动后将显示 'Boot failed'"
}
inject_gpt_fault() {
echo "[*] 注入 GPT 分区表损坏故障..."
printf '\x00\x00\x00\x00\x00\x00\x00\x00' | \
dd of=${DISK_IMG} bs=1 seek=512 conv=notrunc count=8
echo "[+] GPT 签名已清除,GRUB 将进入救援模式"
}
inject_superblock_fault() {
echo "[*] 注入 ext4 超级块损坏故障..."
dd if=/dev/urandom of=${DISK_IMG} bs=1024 seek=1 count=1 conv=notrunc
echo "[+] 超级块已损坏,内核将 panic"
}
restore_disk() {
echo "[*] 从备份恢复磁盘..."
cp ${BACKUP_DIR}/disk_clean.img ${DISK_IMG}
echo "[+] 磁盘已恢复"
}
case "$1" in
mbr) inject_mbr_fault ;;
gpt) inject_gpt_fault ;;
super) inject_superblock_fault ;;
restore) restore_disk ;;
*) echo "用法: $0 {mbr|gpt|super|restore}" ;;
esac
实验注意事项:
- 在执行故障注入前,务必使用
restore命令恢复磁盘到初始状态,避免累积损坏导致不可预期行为。 - 建议在 QEMU 启动参数中添加
-serial stdio和-d int,以捕获完整的异常中断序列。 - 对于超级块损坏场景,内核 panic 后可使用
info qtree查看设备树,确认磁盘控制器是否正常响应。
3.8 故障复现与调试总结
通过本节实验,我们掌握了三种磁盘损坏场景的模拟方法及其对应的调试手段。核心要点总结如下:
- MBR 损坏 导致 BIOS 无法引导,QEMU 输出
Boot failed,通过xp /16xb 0x7c00可确认 MBR 内容是否被清零。 - 分区表损坏 导致 GRUB 无法读取磁盘布局,进入救援模式,通过
pmemsave导出 GPT 头部进行分析。 - 超级块损坏 导致内核无法挂载根文件系统,触发 Kernel panic,通过
-d trace:ext4_*可捕获文件系统层的详细错误。 - QEMU Monitor 的
info block、info registers和gdbserver是定位磁盘故障的三大核心工具。