linked list within a kernel probe

Tom Mitchell niftylinkern at niftyegg.com
Mon Jan 9 12:56:29 EST 2023


On Sun, Jan 8, 2023 at 2:24 PM chrishell <chris at chrishell.de> wrote:
>
> To shorten my probblem description: I created a linked list within a
> function, which is called in the module _init function. Right after
> leaving this function I tested this list within the _init function,
> which worked. But within the kprobe function, the access to that linked
> list leads to kernel oops or even kernel panics
>
> Hope there is someone who can give me a hint.
>
Hint.
Inside the kernel always address the issue of concurrency.
Adding and removing from lists commonly needs a protective mutual
exclusive lock.
Look for like data structures and use the macro/standard tools to get
it ALL correct including cache coherency.

There are two strategies -- a data lock or a code monitor.
https://www.geeksforgeeks.org/deadlock-starvation-and-livelock/

> >
> > 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 at kernelnewbies.org
> > https://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies
> >
>
>
> _______________________________________________
> Kernelnewbies mailing list
> Kernelnewbies at kernelnewbies.org
> https://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies



More information about the Kernelnewbies mailing list