kernelnewbies.kernelnewbies.org archive mirror
 help / color / mirror / Atom feed
From: chrishell <chris@chrishell.de>
To: kernelnewbies@kernelnewbies.org
Subject: linked list within a kernel probe
Date: Tue, 3 Jan 2023 19:52:02 +0100	[thread overview]
Message-ID: <75bc2d47-a2f9-187b-8ac8-e0ee2c10226a@chrishell.de> (raw)

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@kernelnewbies.org
https://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies

             reply	other threads:[~2023-01-03 22:09 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-01-03 18:52 chrishell [this message]
2023-01-08 22:24 ` linked list within a kernel probe chrishell
2023-01-09 16:15   ` Billie Alsup (balsup)
2023-01-12 14:48     ` chrishell
2023-01-09 17:56   ` Tom Mitchell
2023-01-12 15:05     ` chrishell

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=75bc2d47-a2f9-187b-8ac8-e0ee2c10226a@chrishell.de \
    --to=chris@chrishell.de \
    --cc=kernelnewbies@kernelnewbies.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).