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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With