6

I've seen lots of questions about getting a file's path from it's inode, but almost none about doing the reverse. My kernel module needs to do this to get further information about the subjects of requests passed to open(), such as its file flags or whether or not it's a device. From what I was able to scrounge together from mailing lists, manual pages, and the Linux source code, I came up with this small function:

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

Trying to use it in my replacement system call makes kernel messages get printed to the console, though:

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);
}

Is there a better way to do this? I'm almost positive my way is wrong.

Melab
  • 2,594
  • 7
  • 30
  • 51
  • Sorry but `get_inode_from_pathname` function creates local struct `path` and you return its member and in `custom_open` you use that data. Isn't that info cleared from stack when you are accessing with `current_inode->i_mode` ? – Fredrick Gauss Jan 10 '19 at 13:55
  • @FredrickGauss I have no idea. – Melab Jan 11 '19 at 20:18
  • Note that you need to call `path_put()` after you're done using the inode (which makes your helper function nearly impossible to use). – Jonathon Reinhart Mar 29 '21 at 03:17

2 Answers2

8

You can use the kern_path kernel API to get the inode information from the path string. This function in turn calls the do_path_lookup() function which performs the path look up operation. You can verify the results of the kern_path function by printing the inode number (i_ino field of the inode structure) of the inode you get from your get_inode_from_pathname function and matching it with the inode number from an ls command (ls -i <path of the file>)

I made the following kernel module and it's not crashing the kernel. I am using 2.6.39 kernel.

#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");

Can you send the crash stack trace?

Jonathon Reinhart
  • 132,704
  • 33
  • 254
  • 328
S_S
  • 138
  • 6
  • That's what my code currently does, but it's causing my module to crash. – Melab Jan 12 '15 at 16:31
  • I have added my module to get the inode number in my reply above. – S_S Jan 13 '15 at 07:10
  • I'm using a minimal setup in a virtual machine, so I'll have to figure out some way to capture the crash stack trace (what is that specifically?). I'm running kernel version 3.16.7 and it's probably due to this being used in a hijacked system call, but I'll see what I get. – Melab Jan 13 '15 at 17:28
  • I tried my module on a 3.16.3 kernel as well but did not get any crash. When you say that your module crashes what exactly happens? – S_S Jan 13 '15 at 17:37
3

I guess the author has already fixed his problem, but this question was the first link in google's search results, so I'll explain it further.

The problem with the code from the question was using __user pointer. When you hook a function that deals with __user pointers, first thing you have to make is to copy content to your own kernel buffer where you will deal with it or make sure that pointer won't become invalid while you are dealing with it.

To copy it to your buffer you could use copy_from_user function

char path[MAX_PATH] = {0};

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

If you hook sys_open, you can use getname/putname functions, as it is done in do_sys_open function:

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: code from S_S's answer won't crash because in fact it allocated buffer for path inside kernel, so it couldn't become invalid while the module is working with it.

fetch
  • 108
  • 7
  • I do not have access to my source code at the moment, but I am sure it wasn't a problem with `__user`. – Melab Jul 25 '16 at 17:22