How can I get a filename from a file descriptor inside a kernel module?

15,283

Don't call SYS_readlink - use the same method that procfs does when one of those links is read. Start with the code in proc_pid_readlink() and proc_fd_link() in fs/proc/base.c.

Broadly, given an int fd and a struct files_struct *files from the task you're interested in (which you have taken a reference to), you want to do:

char *tmp;
char *pathname;
struct file *file;
struct path *path;

spin_lock(&files->file_lock);
file = fcheck_files(files, fd);
if (!file) {
    spin_unlock(&files->file_lock);
    return -ENOENT;
}

path = &file->f_path;
path_get(path);
spin_unlock(&files->file_lock);

tmp = (char *)__get_free_page(GFP_KERNEL);

if (!tmp) {
    path_put(path);
    return -ENOMEM;
}

pathname = d_path(path, tmp, PAGE_SIZE);
path_put(path);

if (IS_ERR(pathname)) {
    free_page((unsigned long)tmp);
    return PTR_ERR(pathname);
}

/* do something here with pathname */

free_page((unsigned long)tmp);

If your code is running in process-context (eg. invoked through a syscall) and the file descriptor is from the current process, then you can use current->files for the current task's struct files_struct *.

Share:
15,283

Related videos on Youtube

Siddhant
Author by

Siddhant

I'm an experienced software developer located in Munich, Germany. I've been writing Python code close to 10 years now. I've had the chance to use it at almost all the companies where I've worked so far, and also currently maintain a few open source projects written in the language. The technologies I'm currently focusing on include Python, Tornado, Django, Vue.js, Terraform, SaltStack, AWS, and a few others in the Backend/DevOps space.

Updated on June 04, 2022

Comments

  • Siddhant
    Siddhant almost 2 years

    I need to get the name of a file from a given file descriptor, inside a small linux kernel module that I wrote. I tried the solution given at Getting Filename from file descriptor in C, but for some reason, it prints out garbage values (on using readlink on /proc/self/fd/NNN as mentioned in the solution). How can I do it?

  • Siddhant
    Siddhant over 12 years
    Nice. That worked. Thanks! Quick question though. What purpose do the path_get and path_put calls serve (because removing them doesn't have much of an effect on my program)? Also, any idea why wouldn't sys_readlink work?
  • caf
    caf over 12 years
    @Siddhant: The path_get() and path_put() calls are required for correctness, because they pin the path so that it doesn't go away while you are trying to work with it (all the struct path contains is a pair of pointers, to a struct vfsmount and a struct dentry).
  • sherrellbc
    sherrellbc almost 9 years
    Also, why is it necessary to call path_get and get a reference to the path structure?
  • sherrellbc
    sherrellbc almost 9 years
    Is there a reason or benefit of allocating a single page from memory as opposed to using kmalloc? Is it simply because you know a page would fit the worst-case requirement for the path data? It seems that the whole mess witih IS_ERR and PTR_ERR could be avoided by simply using the latter memory allocation method.
  • caf
    caf almost 9 years
    @sherrellbc: Right, the pagesize is an upper limit on the possible size of the pathname, so there's no point in using kmalloc() - the return value of d_path() has to be tested with IS_ERR() regardless. It is necessary to call path_get() to prevent the path from going away after we release ->file_lock (because at that point, the file could be closed by another thread in parallel). We don't want to keep ->file_lock held for longer than necessary because it's a spinlock.
  • caf
    caf almost 9 years
    In fact I'm not even sure if it's allowed to call d_path() while holding a spinlock.
  • Nitinkumar Ambekar
    Nitinkumar Ambekar over 8 years
    If your code is running in process-context ... then you can use current->files for the current task's files_struct. See this answer.
  • wallek876
    wallek876 over 4 years
    Wouldn't be possible in this case to use, rcu_read_lock()/rcu_read_unlock(), instead of spin_lock/spin_unlock? it seems that is only reading the values of the files struct without updating them.
  • caf
    caf over 4 years
    @wallek876: I believe that using RCU protection for this would require taking a reference on the struct file itself instead, because the file reference count can be decremented to zero while the RCU lock is held.
  • teknopaul
    teknopaul almost 3 years
    Whats wrong with just strcpy(n, file->f_path.dentry->d_name.name);
  • caf
    caf almost 3 years
    @teknopaul: That will only look at the final component of the path, not the full pathname. It also races with dcache modifications like renames.