Re: Page Fault Handler Hijacking and Oops

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Aug 04, 2005 at 11:50:45 +0000, Vincenzo Mallozzi wrote:
> 
> > As a side note: I hope you use the macros in linux/list.h, so it's not
> > a stupid thinko in the list walking code somewhere.
> > 
> 
> Oh! No, I'm not using the macros in linux/list.h. I've used a simple C list. 
> The definition of this list is:
> 
> 
>  1.  struct mtpmc_wrprotected_pages{
>  2.   unsigned long address;
>  3.   struct mtpmc_wrprotected_pages *next_page;
>  4.  };
>  5.
>  6.  struct mtpmc_vm_wrprotected{
>  7.   unsigned long vm_start;
>  8.   unsigned long vm_end;
>  9.  
> 10.   struct mtpmc_wrprotected_pages *pages;
> 11.   struct mtpmc_vm_wrprotected *vm_next;
> 12.  };
> 13.  
> 14.  static struct mtpmc_vm_wrprotected *mtpmc_mm_wrprotected;
> 
> in which I records the vmas and the corresponding pages that I've 
> write-protected.
> Now I post also the other pieces of code I'm using:

I have written something like this several times and always had a bug in
it at at least one place. Then I found linux/list.h and started using
that -- and never had a bug in it again. It's a lot more safer and
cleaner. Though it may not be the bug, I suggest you rewrite the code
using list.h -- it is quite a bit safer than by hand.

> The exception handler function hijacked:
> 
> 15.  static asmlinkage void mtpmc_handler(struct pt_regs * regs,
>     long  error_code)
> 16.  {
> 17.   unsigned long address;
> 18.   struct mm_struct *mm;
> 19.   struct mtpmc_address_fault *temp;
> 20.  
> 21.   unsigned long pid = current->pid;
> 22.   int hijack = 0;
> 23.    
> 24.   /* store the old_exception handler pointer in mtpmc_old_int_handler */
> 25.   void (*mtpmc_old_int_handler)(struct pt_regs *,long) =                  
>                                             (void*)mtpmc_old_handler;

Why is this line actually here? Can't you call it directly from the
global variable?

> 26.    
> 27.   /* get the address */
> 28.   __asm__("movl %%cr2,%0":"=r" (address));
> 29.  
> 30.   mm = current->mm;
> 31.   if ((current->pid>=mtpmc_min_pid) && (current->pid<=mtpmc_max_pid))
> 32.    if ((error_code & 3) == 3)
> 33.     if (mtpmc_protected_by_us(address) == 1) /*ERROR IN CALLING THIS 
>         FUNCTION*/
> 34.     {
> 35.      send_sig(SIGSTOP, current, 1);
> 36.      hijack = 1;*/
> 37.     }
> 38.   
> 39.   if (hijack != 1)
> 40.    (*mtpmc_old_int_handler)(regs,error_code);/*call the original handler*/

I am not actually sure this is supposed to work. asmlinkage changes the
calling convention so I would expect simply calling it to not work. But
I don't know the calling convention tricks well enough to be sure. Also
note, that in 2.6.9 it is asmlinkage, but in 2.6.11 it is fastcall.

Also are you sure %%cr2 does not get destroyed before you call this. It
shouldn't be, but anyway.

> 41.   
> 42.   return;
> 43.  }
> 
> 
> The line that causes the error is the 33.th, when during the call to the 
> mtpmc_protected_by_us() function. This function scan the list created by me 
> in which I store the value of memory pages write-protected by me.
> 
> 44.  #define INSIDE(a, b, c)  ( ((c) <= (b)) && ((c) >= (a)) )
> 45.  
> 46.  int mtpmc_protected_by_us(unsigned long addr)
> 47.  {
> 48.   struct mtpmc_vm_wrprotected *wr_vma;
> 49.   struct mtpmc_wrprotected_pages *wr_page;
> 50.  
> 51.   for (wr_vma=mtpmc_mm_wrprotected; wr_vma!=NULL; wr_vma=wr_vma->vm_next)
> 52.    if (INSIDE(wr_vma->vm_start, wr_vma->vm_end, addr)){
> 53.     for (wr_page=wr_vma->pages; wr_page!=NULL; wr_page=wr_page->next_page)
> 54.      if ((addr >= wr_page->address) && (addr <(wr_page->address + 
>          PAGE_SIZE)))
> 55.       return 1;
> 56.     return 0;      
> 57.    } 
> 58.   
> 59.   return 0;
> 60.  }

Now this is plain ugly. It would look quite a bit more readable if it was using
list_foreach macro.

Anyway, I suspect the problem might be the call to the original handler.

Also make sure you properly lock the list with irqsaving spinlocks (ie.
spin_lock_irqsave/spin_unlock_irqrestore outside the handler and
spin_lock/spin_unlock inside.

-------------------------------------------------------------------------------
						 Jan 'Bulb' Hudec <bulb@xxxxxx>

Attachment: signature.asc
Description: Digital signature


[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux