Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

For an antirootkit student project, I want to get a list of filenames of a given directory in a kernel module. I know file IO is usually a bad idea in kernel space but this is a special case.

I used filp_open to get a struct file of the directory. With this I have a struct dentry which has the list d_subdirs which should consist of all files in the given directory.

When I traverse the list and printk all d_iname of the struct dentry which should be the short name of the struct dentry, there are non-ASCII symbols and some files in the directory are missing. There is no rootkit running which could hide those. The dmesg output looks like this:

<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         

There is for example the folder DCIM which is missing or a file called android_module1.ko. I don't see anything special with these files.

This is the code of my kernel module:

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

}

When I try to access the inodes when traversing the list, android crashes. Can I somehow list all the files this way?

Edit:

Interestingly, If I try to manually correct the curdentry pointer like this in the loop:

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

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

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

curdentry = (struct dentry *)testchar;

Wow, this looks ugly, but with this the random symbols are gone. I just do not see where this pointer mismatch comes from. Am I using the list functions correctly?

like image 755
hasnoroot Avatar asked Jan 18 '26 22:01

hasnoroot


1 Answers

You are using wrong field that contains name: d_iname is just a buffer to save allocations that could be not used for large filenames. Actually you seek for d_name.name.

Also you incorrectly traverse list (I wonder how you get any results from it). d_subdirs is a head of list and used as 2nd argument in list_for_each_entry(), but in third argument you should put node, not head which in case of d_entry is d_child field (d_u.d_child in older kernels).

Here are your code after some polishing:

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

I checked it on vanilla Linux 3.12.

like image 86
myaut Avatar answered Jan 20 '26 10:01

myaut