Linux内核相对路径转绝对路径:sys_open/sys_execve挂钩参数解析难题
解决Linux 2.6.32内核中路径规范化的问题
我刚好熟悉这个内核版本的路径处理逻辑,帮你梳理下怎么把相对路径/带../的路径转成绝对路径:
首先,你不需要直接去啃__link_path_walk的源码——内核已经提供了更直接的工具函数来完成这个需求,核心思路是先把用户传入的路径解析成内核的struct path结构,再通过d_path()生成规范化的绝对路径。
具体步骤(以sys_open挂钩为例)
把用户空间的路径拿到内核空间
sys_open的第一个参数是用户态的指针const char __user *filename,你需要用getname()把它拷贝到内核内存中(这个函数会自动处理用户态地址的合法性,比直接copy_from_user更省心),用完记得用putname()释放。解析路径为内核的struct path
用user_path_at()函数,它会基于当前进程的工作目录处理相对路径,自动解析../、./这些特殊组件,最终返回对应的struct path(包含了文件的dentry和vfs Mount信息)。函数参数说明:AT_FDCWD:表示以当前进程的工作目录作为解析基准LOOKUP_FOLLOW:如果路径包含符号链接,会自动跟随到最终目标(不需要的话可以换成LOOKUP_NOFOLLOW)
生成规范化的绝对路径
调用d_path(),传入刚才得到的struct path和一个足够大的缓冲区,它会直接返回处理后的绝对路径字符串——比如/root/Desktop/../Downloads会被转换成/root/Downloads。
示例代码片段(内核模块中)
asmlinkage long my_hooked_sys_open(const char __user *filename, int flags, umode_t mode) { char *kernel_path; struct path path; char *buf = kmalloc(PATH_MAX, GFP_KERNEL); // 用kmalloc避免栈溢出 char *abs_path; int err; if (!buf) { return -ENOMEM; } // 从用户空间获取路径 kernel_path = getname(filename); if (IS_ERR(kernel_path)) { kfree(buf); return PTR_ERR(kernel_path); } // 解析路径为struct path err = user_path_at(AT_FDCWD, kernel_path, LOOKUP_FOLLOW, &path); if (err) { putname(kernel_path); kfree(buf); return err; } // 生成绝对路径 abs_path = d_path(&path, buf, PATH_MAX); // 这里就可以用abs_path做你的参数收集了,比如打印、存储 // 释放资源 path_put(&path); putname(kernel_path); kfree(buf); // 调用原系统调用 return original_sys_open(filename, flags, mode); }
针对sys_execve的处理
sys_execve的第一个参数同样是路径,处理逻辑和sys_open完全一致——把filename参数按上面的步骤走一遍就能得到规范化的绝对路径,剩下的argv、envp参数不影响这个路径处理流程。
注意事项
- 内存安全:内核栈空间有限,建议用
kmalloc分配缓冲区而不是直接在栈上声明大数组,避免栈溢出 - 错误处理:每一步都要检查返回值(比如
getname、user_path_at都可能失败),否则容易导致内核崩溃 - 符号链接:如果不需要跟随符号链接,把
LOOKUP_FOLLOW换成LOOKUP_NOFOLLOW即可 - 版本兼容性:这些函数在2.6.32-754.el6内核中都是稳定存在的,不需要担心兼容性问题
内容的提问来源于stack exchange,提问作者PRIME GEEK
相关产品推荐
相关产品推荐

