在给定文件路径的情况下检索inode结构

时间:2015-01-09 21:30:40

标签: linux-kernel

我已经看到很多关于从它的inode获取文件路径的问题,但几乎没有关于做反向的问题。我的内核模块需要这样做才能获得有关传递给open()的请求主题的更多信息,例如文件标志或它是否是设备。从我能够从邮件列表,手册页和Linux源代码中搜集到的东西,我想出了这个小功能:

struct inode* get_inode_from_pathname(const char *pathname) {
    struct path path;
    kern_path(pathname, LOOKUP_FOLLOW, &path);
    return path.dentry->d_inode;
}

尝试在我的替换系统调用中使用它会使内核消息打印到控制台,但是:

struct inode *current_inode;
...
asmlinkage int custom_open(char const *__user file_name, int flags, int mode) {
    current_inode = get_inode_from_pathname(file_name);
    printk(KERN_INFO "intercepted: open(\"%s\", %X, %X)\n", file_name, flags, mode);
    printk(KERN_INFO "i_mode of %s:%hu\n", file_name, current_inode->i_mode);
    return real_open(file_name, flags, mode);
}

有更好的方法吗?我几乎是肯定的,我的方式是错的。

2 个答案:

答案 0 :(得分:6)

您可以使用kern_path内核API从路径字符串中获取inode信息。该函数依次调用执行路径查找操作的do_path_lookup()函数。您可以通过打印从kern_path函数获得的inode的inode编号(inode结构的i_ino字段)并将其与inode编号匹配来验证get_inode_from_pathname函数的结果来自ls命令(ls -i <path of the file>

我制作了以下内核模块,它没有崩溃内核。我正在使用2.6.39内核。

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h> 
#include <linux/mount.h>
#include <linux/path.h>
#include <linux/namei.h>
#include <linux/fs.h>
#include <linux/namei.h>

char *path_name = "/home/shubham/test_prgs/temp.c";

int myinit(void)
{
    struct inode *inode;
    struct path path;
    kern_path(path_name, LOOKUP_FOLLOW, &path);
    inode = path.dentry->d_inode;
    printk("Path name : %s, inode :%lu\n", path_name, inode->i_ino);
    return 0;
}


void myexit(void)
{
    return;
}

module_init(myinit); 
module_exit(myexit);

//MODULE_AUTHOR("Shubham");
//MODULE_DESCRIPTION("Module to get inode from path");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL v2");

你能发送崩溃堆栈跟踪吗?

答案 1 :(得分:2)

我想作者已经解决了他的问题,但这个问题是谷歌搜索结果中的第一个链接,所以我会进一步解释。

问题代码的问题是使用__user指针。 当你挂钩一个处理__user指针的函数时,你要做的第一件事就是将内容复制到你自己的内核缓冲区,在那里你将处理它或确保指针在你处理它时不会变得无效。 / p>

要将其复制到缓冲区,您可以使用copy_from_user函数

char path[MAX_PATH] = {0};

if (copy_from_user(path, user_path, strlen_user(user_path))
{
  //error
}
//success

如果你挂钩sys_open,你可以使用getname / putname函数,就像在do_sys_open函数中一样:

1010 long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
1011 {
1012         struct open_flags op;
1013         int fd = build_open_flags(flags, mode, &op);
1014         struct filename *tmp;
1015 
1016         if (fd)
1017                 return fd;
1018 
1019         tmp = getname(filename);
1020         if (IS_ERR(tmp))
1021                 return PTR_ERR(tmp);
1022 
1023         fd = get_unused_fd_flags(flags);
1024         if (fd >= 0) {
1025                 struct file *f = do_filp_open(dfd, tmp, &op);
1026                 if (IS_ERR(f)) {
1027                         put_unused_fd(fd);
1028                         fd = PTR_ERR(f);
1029                 } else {
1030                         fsnotify_open(f);
1031                         fd_install(fd, f);
1032                 }
1033         }
1034         putname(tmp);
1035         return fd;
1036 }

ps:来自S_S的答案的代码不会崩溃,因为事实上它为内核中的路径分配了缓冲区,因此在模块使用它时它不会变为无效。