Hello out there, I have an issue with a linked list which holds pointers
to memory pages for a kprobe. The linked list get initialised but I
cannot use it within the kprobe.
I use main or head pointer to hold everything in one place:
struct kprobe_head {
struct list_head *p_mem_cache;
struct kprobe_fsops *pfops;
struct kprobe *pProbe;
};
and the pointer to access everything:
static struct kprobe_head *pHead;
then I have the structure which this list is made of:
struct kprobe_mem_cache {
void *p_page;
__u32 size;
__u8 dirty;
struct list_head list_element;
};
the list looks like:
____________________ _________________
| |<-| |<-|
pHead->p_mem_cache->| kprobe_mem_cache |->| krobe_mem_cache |->| ...
-------------------- -------------------
the p_page pointer is the pointer to the alloacted page. Therefore each
element of that linked list holds a pointer to allocated memory segment.
in the __init function I do, among other things, allocate some memory
for that structure, thought a static struct would be also sufficient.
/* create the head storage record */
pHead = (struct kprobe_head*) kzalloc(sizeof(struct kprobe_head),
GFP_KERNEL);
if(pHead == NULL)
return -ENOMEM;
then I create the linked list with this function:
static __u8 _kprobe_setup_cache_elements( struct kprobe_head *pHead,
__u16 elements, __u32 size)
{
unsigned int count = 0;
__u8 rc = 0;
struct list_head local_head;
INIT_LIST_HEAD(&local_head);
if(pHead != NULL) {
pr_err("create list with %p\n", pHead);
//INIT_LIST_HEAD(pHead->p_mem_cache);
for(count=0; count<elements; count++) {
struct kprobe_mem_cache *new = kzalloc(sizeof(struct
kprobe_mem_cache), GFP_KERNEL);
if(NULL == new) {
pr_err("error: kzalloc issue");
return -ENOMEM;
}
/* allocate memory for one page */
new->p_page = vmalloc(size);
if(NULL == new->p_page) {
pr_err("error: vmalloc issue");
return -ENOMEM;
}
else {
pr_err("List Element %d added Size: %u addr: %p \n", count, size,
new->p_page);
}
new->size = size;
new->dirty = 0;
list_add_tail(&new->list_element, &local_head);
}
pHead->p_mem_cache = &local_head;
}
return rc;
}
right after that, still in the __init function I traverse trough this
linked list, just to see if its work.
if(pHead->p_mem_cache != NULL)
{
pr_err("within loop %p %p\n", pHead, pHead->p_mem_cache);
list_for_each(local_head, pHead->p_mem_cache) {
local_page = list_entry(local_head, struct kprobe_mem_cache,
list_element);
if(local_page->size)
pr_err("address: %u \n", local_page->size );
}
}
And here it works.
The problem now is that this is a kprobe kernel module and I defined a
kprobe function as pre_handler function called submit_bio_pre which is
evoked whenever the block layer function submit_bio is called by the
kernel. Within that function however the access to that linked list failed
int submit_bio_pre(struct kprobe *p_submit_bio, struct pt_regs *regs)
{
int rc = 0;
struct bio *bio = NULL;
static unsigned int len = 0;
static unsigned int counter;
struct kprobe_mem_cache *tmp = NULL;
struct kprobe_mem_cache *local_page = NULL;
struct list_head *local_head = NULL;
bio = (struct bio*) regs_get_kernel_argument(regs, 0);
if(pHead != NULL)
pr_err("#### pHead is initialized %p #####\n", pHead);
if(pHead->p_mem_cache != NULL)
pr_err("#### pHead->p_mem_cache is initialized %p #######\n",
pHead->p_mem_cache);
if(pHead->p_mem_cache != NULL && counter == 0)
{
spin_lock(&sl);
pr_err("within loop submit_bio_pre \n");
list_for_each(local_head, pHead->p_mem_cache) {
local_page = list_entry(local_head, struct kprobe_mem_cache,
list_element);
if(local_page->size)
pr_err("address bio: %u \n", local_page->size );
}
spin_unlock(&sl);
counter++;
}
As it seems is the head pointer valid and has the same address as in the
init function. Also the head pointer to the linked list is a valid one.
But traversing through the linked list is not possible any more. As you
can see I added a spin_lock to that kprobe function, albeit I only read
from the linked list. This function does something completely different
normally anyway.
When I load this module, the initialisation of the linked list works,
also the following walk through the list, but within the kprobe function
sometimes I can see the first and second pr_err. But after that the
kernel breaks:
[ 191.460196] Unable to handle kernel paging request at virtual address
000323bfa8c17bf5
[ 191.669571] Call trace:
[ 191.672021] submit_bio_pre+0xcc/0x150
[ 191.676641] kprobe_breakpoint_handler+0x100/0x190
[ 191.681445] call_break_hook+0x68/0x80
[ 191.685201] brk_handler+0x1c/0x60
So can anybody tell me, what is the reason that the linked list doesn't
work within the kprobe?
Thank you in advance
BR Christian
_______________________________________________
Kernelnewbies mailing list
Kernelnewbies@xxxxxxxxxxxxxxxxx
https://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies