拦截Linux系统调用时无法printk输出用户空间字符串参数的问题
问题根源
你遇到的-14错误对应内核标准错误码EFAULT,表示传入的用户空间地址filename不合法:要么地址不属于当前进程的用户空间映射范围,要么没有可读权限。
解决方案
不要手动调用strncpy_from_user/copy_from_user处理文件名,直接使用内核原生专门用于读取用户空间文件路径的getname接口,该接口会自动完成地址合法性校验、缺页处理、内存分配等逻辑,用完调用putname释放内存即可,修改后的代码如下:
static inline long hacked_open(const char __user *filename, int flags, umode_t mode) { const char *kname = getname(filename); if (!IS_ERR(kname)) { printk("%s\n", kname); putname(kname); } else { printk("---err len : %ld ---\n", PTR_ERR(kname)); } orig_func a = (orig_func)orig_open; return a(filename, flags, mode); }
额外排查项
如果修改后仍然大量出现EFAULT错误,需要检查你的Hook逻辑是否符合以下要求:
- 确保你拿到的
filename参数是正确的:64位Linux系统调用通过寄存器传参,如果你使用kprobe/ftrace等方式Hook,要确认参数提取逻辑没有拿错寄存器值 - 确保Hook逻辑是在触发open系统调用的进程上下文中执行,不能在中断上下文、其他进程上下文访问当前进程的用户空间地址
- 确认内核版本适配:5.x以上内核的
access_ok接口删除了第一个参数,如果你手动校验地址要注意接口适配
内容的提问来源于stack exchange,提问作者gemini
相关产品推荐
相关产品推荐

