C语言 从dentry_path_raw获取绝对路径

koaltpgm  于 2022-12-11  发布在  其他
关注(0)|答案(1)|浏览(503)

bounty将在4天后过期。回答此问题可获得+50声望奖励。Maxime B.希望吸引更多人关注此问题。

我试图获取内核模块中符号链接dentries的目标,即我的dentry所指向的dentry。
我采用这种方法:

int print_dentry(struct dentry *d) {
    struct path p;
    char *buffer, *path_name;
    int ret;
    buffer = (char *)__get_free_page(GFP_KERNEL);
    if (!buffer)
        return -ENOMEM;
    path_name = dentry_path_raw(d, buffer, PAGE_SIZE);

    if (IS_ERR(path_name))
        printk(KERN_ERR "ERR");

    if ((ret=kern_path(path_name, LOOKUP_FOLLOW, &p))) {
        printk("kern_path returned %d for path_name \"%s\", inode %ld\n", ret, path_name, d->d_inode->i_ino);
        return 0;
    }
    printk_once(KERN_INFO "Path %s -> dentry_uid %ld\n", path_name, p.dentry->d_inode->i_ino);
    free_page((unsigned long)buffer);
    return 0;
}

但是,dentry_path_raw不返回绝对路径,而是返回相对于vfsmount的路径。
因此,当有vfsmount时,我会收到类似这样的错误。

kern_path returned -2 for path_name "/self", inode 4026531841

它对应于/proc/self

ls -ial /proc/self 
4026531841 lrwxrwxrwx 1 root root 0  5 déc.  04:28 /proc/self -> 1341

有没有办法得到绝对路径,这样我就可以把它给kern_path()了?或者有没有其他方法可以跟踪符号链接并得到关联的dentry?
我认为我不能直接使用d_absolute_pathprepend_path,因为它们将struct path*char*作为输入,而我只能访问struct dentry*char*

cvxl0en2

cvxl0en21#

查看源代码here,当您调用dentry_path_raw()时,它实际上调用了另一个函数,该函数执行以下操作:

/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Write full pathname from the root of the filesystem into the buffer.
 */
static char *__dentry_path(const struct dentry *d, struct prepend_buffer *p)
{
    const struct dentry *dentry;
    struct prepend_buffer b;
    int seq = 0;

    rcu_read_lock();
restart:
    dentry = d;
    b = *p;
    read_seqbegin_or_lock(&rename_lock, &seq);
    while (!IS_ROOT(dentry)) {
        const struct dentry *parent = dentry->d_parent;

        prefetch(parent);
        if (!prepend_name(&b, &dentry->d_name))
            break;
        dentry = parent;
    }
    if (!(seq & 1))
        rcu_read_unlock();
    if (need_seqretry(&rename_lock, seq)) {
        seq = 1;
        goto restart;
    }
    done_seqretry(&rename_lock, seq);
    if (b.len == p->len)
        prepend_char(&b, '/');
    return extract_string(&b);
}

所有的东西都在这个函数的描述中,它把完整的路径写入缓冲区,而不是返回值,它和dentry_path_raw()共享它的返回。
因此,您应该使用推入buffer的值,而不是file_namefile_name只是函数dentry_path_raw()返回的名称。
注意:dentry_path_raw()不能解析符号链接,如果你真的想解析它们,你应该使用dentry_path()

相关问题