为什么我在android内核中遍历内核模块中目录的dentry时不能正确提取所有文件名?

Why can't I extract all filenames correctly when I traverse the dentry of a directory in a kernel module in the android kernel?

对于一个 antirootkit 学生项目,我想获取内核模块中给定目录的文件名列表。我知道文件 IO 在内核 space 中通常不是一个好主意,但这是一个特例。

我用 filp_open 得到了目录的 struct file。有了这个,我有一个 struct dentry,它有一个列表 d_subdirs,它应该包含给定目录中的所有文件。

当我遍历列表并打印出 struct dentry 的所有 d_iname 应该是 struct dentry 的短名称时,其中有非 ASCII 符号和一些文件目录丢失。没有可以隐藏这些的 rootkit 运行。 dmesg 输出如下所示:

<6>Filename: �đ�@�Y�android_module17.ko 
<6>Filename: <��� 
<6>Filename: <� 
<6>Filename: <��� 
<6>Filename: <�����android_module15.ko 
<6>Filename: <��؀ŋ�android_module14.ko 
<6>Filename: <���@Nj�android_module13.ko 
<6>Filename: <��� 
<6>Filename: <����ʋ�k 
<6>Filename: <��؀̋�android_module11.ko 
<6>Filename: <���@΋�android_module10.ko 
<6>Filename: <���@���android_module9.ko 
<6>Filename: <��� 
<6>Filename: <�����android_module7.ko 
<6>Filename: <Ê؀���android_module6.ko 
<6>Filename: <Ċ�@���android_module5.ko 
<6>Filename: <Ŋ� 
<6>Filename: <Ɗ�����10-__rttest 
<6>Filename: <NJ؀���__rttest 
<6>Filename: <Ȋ�@���proctest.ko 
<6>Filename: <ʊ� 
<6>Filename: <ˊ�����rt.ko 
<6>Filename: <̊؀���android_module4.ko 
<6>Filename: <͊�@���anmo.ko 
<6>Filename: <��� 
<6>Filename: ������Z�LOST.DIR 
<6>Filename: �҉�@�Z�Android         

例如,缺少文件夹 DCIM 或名为 android_module1.ko 的文件。我看不出这些文件有什么特别之处。

这是我的内核模块的代码:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/namei.h>
#include <asm/uaccess.h> 

//replace the "" with angular brackets
int init_module(void)
{
    struct file * fi;

    printk(KERN_INFO "Hello android kernel...\n");

    fi = filp_open("/sdcard/", O_RDONLY, 0);

    //struct path testpath = fi->f_path;
    struct dentry * thedentry;
    thedentry = fi->f_dentry;
    struct dentry * curdentry;

    unsigned char * curname = NULL;

    list_for_each_entry(curdentry, &thedentry->d_subdirs, d_subdirs) {
        curname = curdentry->d_iname;

        printk(KERN_INFO "Filename: %s \n", curname);
    }
    filp_close(fi, NULL);

    return 0;
}

void cleanup_module(void)
{
printk(KERN_INFO "Goodbye android kernel...\n");

}

当我在遍历列表时尝试访问 inode 时,android 崩溃了。我能以某种方式列出所有文件吗?

编辑:

有趣的是,如果我尝试在循环中像这样手动更正当前指针:

testchar = (char *)curdentry;
testchar = testchar + 8;

curdentry = (struct dentry *)testchar;
curname = curdentry->d_iname;

testchar = (char *)curdentry;
testchar = testchar - 8;

curdentry = (struct dentry *)testchar;

哇,这看起来很难看,但是随机符号不见了。我只是看不出这个指针不匹配是从哪里来的。我是否正确使用列表函数?

您使用了包含名称的错误字段:d_iname 只是一个用于保存不能用于大文件名的分配的缓冲区。实际上你在寻找 d_name.name.

你还错误地遍历了列表(我想知道你是如何从中得到任何结果的)。 d_subdirs 是列表的 head 并用作 list_for_each_entry() 中的第二个参数,但在第三个参数中你应该放置 node ,而不是 head,在 d_entry 的情况下是 d_child 字段(旧内核中的 d_u.d_child)。

这是经过一些润色后的代码:

struct file * fi;
struct dentry * thedentry;
struct dentry * curdentry;
const char * curname = NULL;

printk(KERN_INFO "Hello android kernel...\n");

fi = filp_open("/root/", O_RDONLY, 0);
thedentry = fi->f_dentry;

list_for_each_entry(curdentry, &thedentry->d_subdirs, d_u.d_child) {
    curname = curdentry->d_name.name;

    printk(KERN_INFO "Filename: %s \n", curname);
}

filp_close(fi, NULL);

我在原版上查看过 Linux 3.12.