6
  • Given a inode that exists in /proc/**/fd/*
  • And a Linux Kernel Module that needs to find the executable path from the symbolic link /proc/**/exe

How could I implement this so that from a inode number I got the path of the executable using the fd ?

ZedTuX
  • 2,859
  • 3
  • 28
  • 58
  • 1
    In my researches I found a method `proc_fd_link` (http://lxr.free-electrons.com/source/fs/proc/fd.c?a=avr32#L140) but isn't accessible from my kernel module (method not found on compilation. – ZedTuX May 01 '13 at 15:56
  • 1
    I also found macros `PDE` and `PROC_I` (http://lxr.free-electrons.com/source/include/linux/proc_fs.h) but then I don't know how to find the `/proc/**/exe` item. – ZedTuX May 01 '13 at 15:57
  • 1
    An inode might have none or more than one path, and namespaces might result in different paths in different processes. What do you need the path for, and why must this be done from a kernel module? – CL. May 04 '13 at 16:40
  • 1
    @CL. It is not mandatory to do it in the kernel module (and I'm currently implementing it in a userspace application). What did you meant by "What do you need the path for" ? – ZedTuX May 05 '13 at 10:34
  • 2
    So you are reimplementing `lsof`? – CL. May 05 '13 at 10:51
  • 1
    No I'm not, I'm developing a firewall on application layer so I'm filtering per process the outgoing packets. – ZedTuX May 05 '13 at 10:55
  • 1
    Check out how `lsof` does this. – CL. May 05 '13 at 11:23
  • `lsof` is iterating over each `/proc/[PID]/` folders I guess and is a userspace application. I would prefer to do it in the kernel module (even if I'm giving a try to the userspace way) because I can't imagine that there is no `proc_*` method where I could pass the inode number of the socket and I get a pointer to `/proc/[pid]/fd/*` where I could move up to get the `/proc/[pid]/exe`. – ZedTuX May 06 '13 at 09:04

1 Answers1

0

The proc_inode struct and PROC_I macro are both internal. See [PATCH 27/28] proc: Make the PROC_I() and PDE() macros internal toprocfs [RFC].

Instead, what about iterating over the inode's dentry list? You could use dentry_path_raw() to find a /*/fd/* path name:

//struct inode *proc_inode;

struct dentry *dentry;
pid_t pid;
int found_match = 0;

printk(KERN_DEBUG "superblock type name: %s\n", proc_inode->i_sb->s_type->name);

// An inode's dentry list is protected by the i_lock. See:
// - "dcache->d_inode->i_lock protects: i_dentry, d_u.d_alias, d_inode of aliases"
//   http://lxr.free-electrons.com/source/fs/dcache.c?v=4.0#L48
// - The implementation of d_prune_aliases()
//   http://lxr.free-electrons.com/source/fs/dcache.c?v=4.0#L882
spin_lock(&proc_inode->i_lock);
hlist_for_each_entry(dentry, &proc_inode->i_dentry, d_u.d_alias) {
    char buf[64];
    const char *path_raw;
    char c;

    path_raw = dentry_path_raw(dentry, buf, sizeof(buf));

    // dentry_path_raw() places the path into `buf'. If `buf' is not large
    // enough, then continue on to the next dentry.
    if (!(buf <= path_raw && path_raw <= buf + sizeof(buf) - 1)) {
        printk(KERN_DEBUG "`buf' not large enough, dentry_path_raw() returned %ld\n", PTR_ERR(path_raw));
        continue;
    }

    printk(KERN_DEBUG "path_raw = %s\n", path_raw);

    // We're looking to match: ^/(\d*)/fd/

    if (*path_raw++ != '/') continue;

    pid = 0;
    for (c = *path_raw; c; c = *++path_raw) {
        if ('0' <= c && c <= '9') {
            pid = 10 * pid + (c - '0');
        } else {
            break;
        }
    }

    if (*path_raw++ != '/') continue;
    if (*path_raw++ != 'f') continue;
    if (*path_raw++ != 'd') continue;
    if (*path_raw != '/' && *path_raw != '\0') continue;

    // Found a match. Break the dentry list loop.
    found_match = 1;
    printk(KERN_DEBUG "breaking dentry list loop\n");
    break;
}
spin_unlock(&proc_inode->i_lock);

if (found_match) {
    printk(KERN_DEBUG "pid = %d\n", (int)pid);
}

EDIT: I have uploaded a demonstration project to GitHub:
https://github.com/dtrebbien/so16317923-proc-fs-kernel-module

Community
  • 1
  • 1
Daniel Trebbien
  • 38,421
  • 18
  • 121
  • 193