技术知识库

未初始化 fasync 指针可能导致 fasync_insert_entry Oops

未初始化 fasync 指针可能导致 fasync_insert_entry Oops

摘要

实验手册的进阶思考描述:同一份 FASYNC 代码在一位实验者处运行成功,另一位运行 test 后却在 fasync_insert_entry() 中 Oops。当前本地实验运行成功,尚未亲自复现该 Oops;已建立用户态 GCC/GDB 类比实验,后续先练习从崩溃点、调用栈和指针值定位问题,再进入 vmlinux 分析。

参考现象

手册中的关键日志:

Unable to handle kernel paging request at virtual address ...
pc : fasync_insert_entry+0x508/0x918

Call trace:
 fasync_insert_entry
 fasync_add_entry
 fasync_helper
 demodrv_fasync [mydemo_fasync]
 setfl
 do_fcntl
 __se_sys_fcntl

用户程序中的触发点:

fcntl(fd, F_SETFL, flag | FASYNC);

当前源码观察点

设备结构体保存:

struct fasync_struct *fasync;

驱动把该指针的地址交给:

fasync_helper(fd, file, on, &device->fasync);

设备对象的分配发生在:

device = kmalloc(sizeof(struct mydemo_device), GFP_KERNEL);

需要回答该指针在进入 fasync_helper() 前具有什么确定状态,以及 Linux 5.0 fs/fcntl.c::fasync_insert_entry() 对 *fapp 作了什么假设。

源码路径

/home/martin-zou/workspace/runninglinuxkernel_5.0/kmodules/rlk_lab/rlk_basic/chapter_6_device_driver/lab9_mydemodrv_fasync/mydemodrv_fasync.c
/home/martin-zou/workspace/runninglinuxkernel_5.0/fs/fcntl.c
/home/martin-zou/workspace/runninglinuxkernel_5.0/build/arm64/vmlinux

关键位置:

  • mydemodrv_fasync.c:26:device->fasync。
  • mydemodrv_fasync.c:159:fasync_helper()。
  • mydemodrv_fasync.c:199:设备对象分配。
  • fs/fcntl.c:915:fasync_insert_entry()。
  • fs/fcntl.c:921-922:遍历并访问 fa->fa_file。

用户态类比实验

为避免直接让 QEMU 内核 Oops,先使用:

/home/martin-zou/workspace/gcc-lab/debug/fasync-pointer-oops

其中保留两个场景和调试符号,暂未编译或运行:

make
./fasync_pointer_lab xiaoli
./fasync_pointer_lab xiaoming
gdb ./fasync_pointer_lab

调试计划

  1. 保存正常与崩溃场景输出。
  2. 在 GDB 中对 register_async_listener() 下断点。
  3. 检查 device->fasync 和循环变量 entry。
  4. 用 backtrace 建立用户态调用路径。
  5. 把结果映射回 demodrv_fasync() 与 fasync_insert_entry()。
  6. 若需要实际内核定位,再使用与当前 Image 同次构建的 build/arm64/vmlinux。

当前调试环境

主机 gdb:/usr/bin/gdb,已安装
gdb-multiarch:当前未安装
ARM64 vmlinux:存在,带 debug_info,未 strip
内核配置:CONFIG_DEBUG_INFO=y

因此用户态类比实验现在即可使用主机 gdb。真正解析 ARM64 内核的指令、寄存器和源码偏移时,再由用户手动安装 gdb-multiarch,并确保使用与发生 Oops 的 Image 同次构建的 vmlinux。

当前结论

该问题已经定位到 FASYNC 登记阶段及其指针状态,但本地故障复现和 GDB 证据尚未完成,所以保持 seed/pending,不把手册答案当作本地验证结果。

关联

待验证

  • 手动完成 GCC/GDB 类比实验。
  • 保存崩溃行、调用栈和指针值。
  • 再决定是否故意在 QEMU 中复现内核 Oops。