picofix
[kernel/swap-modules.git] / kprobe / dbi_kprobes_deps.c
index 3d97cd1..704720f 100644 (file)
  */
 
 #include <linux/module.h>
+#include <linux/sched.h>
+
+#include <asm/pgtable.h>
 
 #include "dbi_kprobes_deps.h"
 #include "dbi_kdebug.h"
 
 
+#include <linux/slab.h>
+
 unsigned int *sched_addr;
 unsigned int *fork_addr;
 
 
 #define GUP_FLAGS_WRITE                  0x1
-#define GUP_FLAGS_WRITE                  0x1
 #define GUP_FLAGS_FORCE                  0x2
 #define GUP_FLAGS_IGNORE_VMA_PERMISSIONS 0x4
 #define GUP_FLAGS_IGNORE_SIGKILL         0x8
 
-DECLARE_MOD_CB_DEP(kallsyms_search, unsigned long, const char *name);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+struct mm_struct* init_mm_ptr;
+struct mm_struct init_mm;
+#endif
 
+
+DECLARE_MOD_CB_DEP(kallsyms_search, unsigned long, const char *name);
 DECLARE_MOD_FUNC_DEP(access_process_vm, int, struct task_struct * tsk, unsigned long addr, void *buf, int len, int write);
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 32)
+DECLARE_MOD_FUNC_DEP(copy_to_user_page, void, struct vm_area_struct *vma, struct page *page, unsigned long uaddr, void *dst, const void *src, unsigned long len);
+#endif
 
 DECLARE_MOD_FUNC_DEP(find_extend_vma, struct vm_area_struct *, struct mm_struct * mm, unsigned long addr);
 
 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 30)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
 DECLARE_MOD_FUNC_DEP(handle_mm_fault, int, struct mm_struct *mm, struct vm_area_struct *vma, unsigned long address, int write_access);
+#endif
 #else
 DECLARE_MOD_FUNC_DEP(handle_mm_fault, int, struct mm_struct *mm, struct vm_area_struct *vma, unsigned long address, unsigned int flags);
 #endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 30) */
 
 DECLARE_MOD_FUNC_DEP(get_gate_vma, struct vm_area_struct *, struct task_struct *tsk);
+
+#ifdef CONFIG_HUGETLB_PAGE
+DECLARE_MOD_FUNC_DEP(follow_hugetlb_page, int, struct mm_struct *mm, struct vm_area_struct *vma, struct page **pages, struct vm_area_struct **vmas, unsigned long *position, int *length, int i, int write);
+#endif
+
+#ifdef __HAVE_ARCH_GATE_AREA
+DECLARE_MOD_FUNC_DEP(in_gate_area, int, struct task_struct *tsk,unsigned long addr);
+#else
 DECLARE_MOD_FUNC_DEP(in_gate_area_no_task, int, unsigned long addr);
+#endif
 DECLARE_MOD_FUNC_DEP(follow_page, \
                struct page *, struct vm_area_struct * vma, \
                unsigned long address, unsigned int foll_flags);
@@ -85,9 +108,11 @@ IMP_MOD_DEP_WRAPPER (access_process_vm, tsk, addr, buf, len, write)
 IMP_MOD_DEP_WRAPPER (find_extend_vma, mm, addr)
 
 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 30)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
        DECLARE_MOD_DEP_WRAPPER (handle_mm_fault, \
                        int, struct mm_struct *mm, struct vm_area_struct *vma, unsigned long address, int write_access)
 IMP_MOD_DEP_WRAPPER (handle_mm_fault, mm, vma, address, write_access)
+#endif
 #else
        DECLARE_MOD_DEP_WRAPPER (handle_mm_fault, \
                        int, struct mm_struct *mm, struct vm_area_struct *vma, unsigned long address, unsigned int flags)
@@ -98,14 +123,25 @@ IMP_MOD_DEP_WRAPPER (handle_mm_fault, mm, vma, address, flags)
                        struct vm_area_struct *, struct task_struct *tsk)
 IMP_MOD_DEP_WRAPPER (get_gate_vma, tsk)
 
+#ifdef CONFIG_HUGETLB_PAGE
+       DECLARE_MOD_DEP_WRAPPER (follow_hugetlb_page, int, struct mm_struct *mm, struct vm_area_struct *vma, struct page **pages, struct vm_area_struct **vmas, unsigned long *position, int *length, int i, int write)
+       IMP_MOD_DEP_WRAPPER (follow_hugetlb_page, mm, vma, pages, vmas, position, length, i, write)
+#endif
+
+#ifdef __HAVE_ARCH_GATE_AREA
+       DECLARE_MOD_DEP_WRAPPER (in_gate_area, int, struct task_struct *tsk, unsigned long addr)
+       IMP_MOD_DEP_WRAPPER (in_gate_area, tsk, addr)
+#else
        DECLARE_MOD_DEP_WRAPPER (in_gate_area_no_task, int, unsigned long addr)
 IMP_MOD_DEP_WRAPPER (in_gate_area_no_task, addr)
+#endif
 
+#if (LINUX_VERSION_CODE != KERNEL_VERSION(2, 6, 11))
        DECLARE_MOD_DEP_WRAPPER (follow_page, \
                        struct page *, struct vm_area_struct * vma, \
                        unsigned long address, unsigned int foll_flags)
 IMP_MOD_DEP_WRAPPER (follow_page, vma, address, foll_flags)
-
+#endif
        DECLARE_MOD_DEP_WRAPPER (__flush_anon_page, \
                        void, struct vm_area_struct *vma, \
                        struct page *page, unsigned long vmaddr)
@@ -121,14 +157,39 @@ IMP_MOD_DEP_WRAPPER (vm_normal_page, vma, addr, pte)
                        unsigned long uaddr, void *kaddr, unsigned long len, int write)
 IMP_MOD_DEP_WRAPPER (flush_ptrace_access, vma, page, uaddr, kaddr, len, write)
 
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 32)
+       DECLARE_MOD_DEP_WRAPPER(copy_to_user_page, void, struct vm_area_struct *vma, struct page *page, unsigned long uaddr, void *dst, const void *src, unsigned long len)
+IMP_MOD_DEP_WRAPPER (copy_to_user_page, vma, page, uaddr, dst, src, len)
+#endif
+
+
 int init_module_dependencies()
 {
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
+       init_mm_ptr = (struct mm_struct*) kallsyms_search ("init_mm");
+       memcmp(init_mm_ptr, &init_mm, sizeof(struct mm_struct));
+#endif
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
        INIT_MOD_DEP_VAR(handle_mm_fault, handle_mm_fault);
+#endif
+
        INIT_MOD_DEP_VAR(flush_ptrace_access, flush_ptrace_access);
        INIT_MOD_DEP_VAR(find_extend_vma, find_extend_vma);
        INIT_MOD_DEP_VAR(get_gate_vma, get_gate_vma);
+
+#ifdef CONFIG_HUGETLB_PAGE
+       INIT_MOD_DEP_VAR(follow_hugetlb_page, follow_hugetlb_page);
+#endif
+
+#ifdef __HAVE_ARCH_GATE_AREA
+       INIT_MOD_DEP_VAR(in_gate_area, in_gate_area);
+#else
        INIT_MOD_DEP_VAR(in_gate_area_no_task, in_gate_area_no_task);
+#endif
        INIT_MOD_DEP_VAR(follow_page, follow_page);
+
        INIT_MOD_DEP_VAR(__flush_anon_page, __flush_anon_page);
        INIT_MOD_DEP_VAR(vm_normal_page, vm_normal_page);
        INIT_MOD_DEP_VAR(access_process_vm, access_process_vm);
@@ -143,12 +204,21 @@ int init_module_dependencies()
        INIT_MOD_DEP_VAR(put_task_struct, __put_task_struct_cb);
 #endif
 
+
+#if (LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 32))
+       INIT_MOD_DEP_VAR(copy_to_user_page, copy_to_user_page);
+#endif
+
        return 0;
 }
 
+#define GUP_FLAGS_WRITE                  0x1
+#define GUP_FLAGS_FORCE                  0x2
+#define GUP_FLAGS_IGNORE_VMA_PERMISSIONS 0x4
+#define GUP_FLAGS_IGNORE_SIGKILL         0x8
 
-static inline 
-int use_zero_page(struct vm_area_struct *vma)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
+static inline int use_zero_page(struct vm_area_struct *vma)
 {
        /*
         * We don't want to optimize FOLL_ANON for make_pages_present()
@@ -166,7 +236,7 @@ int use_zero_page(struct vm_area_struct *vma)
 }
 
 int __get_user_pages_uprobe(struct task_struct *tsk, struct mm_struct *mm,
-               unsigned long start, int len, int flags,
+                    unsigned long start, int len, int flags,
                struct page **pages, struct vm_area_struct **vmas)
 {
        int i;
@@ -234,13 +304,18 @@ int __get_user_pages_uprobe(struct task_struct *tsk, struct mm_struct *mm,
                }
 
                if (!vma ||
-                               (vma->vm_flags & (VM_IO | VM_PFNMAP)) ||
-                               (!ignore && !(vm_flags & vma->vm_flags)))
+                   (vma->vm_flags & (VM_IO | VM_PFNMAP)) ||
+                   (!ignore && !(vm_flags & vma->vm_flags)))
                        return i ? : -EFAULT;
 
                if (is_vm_hugetlb_page(vma)) {
+#if  LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18)
+                       i = follow_hugetlb_page(mm, vma, pages, vmas,
+                                               &start, &len, i);
+#else
                        i = follow_hugetlb_page(mm, vma, pages, vmas,
-                                       &start, &len, i, write);
+                                               &start, &len, i, write);
+#endif
                        continue;
                }
 
@@ -248,14 +323,17 @@ int __get_user_pages_uprobe(struct task_struct *tsk, struct mm_struct *mm,
                if (pages)
                        foll_flags |= FOLL_GET;
 
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,30)
                if (!write && use_zero_page(vma))
-                       foll_flags |= FOLL_ANON;
+                 foll_flags |= FOLL_ANON;
+#endif
 #endif
 
                do {
                        struct page *page;
 
+#if 0
                        /*
                         * If we have a pending SIGKILL, don't keep faulting
                         * pages and potentially allocating memory, unless
@@ -264,13 +342,14 @@ int __get_user_pages_uprobe(struct task_struct *tsk, struct mm_struct *mm,
                         * we're only unlocking already resident/mapped pages.
                         */
                        if (unlikely(!ignore_sigkill &&
-                                               fatal_signal_pending(current)))
+                                       fatal_signal_pending(current)))
                                return i ? i : -ERESTARTSYS;
+#endif
 
                        if (write)
                                foll_flags |= FOLL_WRITE;
 
-
+                       
                        //cond_resched();
 
                        DBPRINTF ("pages = %p vma = %p\n", pages, vma);
@@ -278,18 +357,39 @@ int __get_user_pages_uprobe(struct task_struct *tsk, struct mm_struct *mm,
                                int ret;
                                ret = handle_mm_fault(mm, vma, start,
                                                foll_flags & FOLL_WRITE);
+
+#if  LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18)
+                               if (ret & VM_FAULT_WRITE)
+                                 foll_flags &= ~FOLL_WRITE;
+                               
+                               switch (ret & ~VM_FAULT_WRITE) {
+                               case VM_FAULT_MINOR:
+                                 tsk->min_flt++;
+                                 break;
+                               case VM_FAULT_MAJOR:
+                                 tsk->maj_flt++;
+                                 break;
+                               case VM_FAULT_SIGBUS:
+                                 return i ? i : -EFAULT;
+                               case VM_FAULT_OOM:
+                                 return i ? i : -ENOMEM;
+                               default:
+                                 BUG();
+                               }
+                               
+#else
                                if (ret & VM_FAULT_ERROR) {
-                                       if (ret & VM_FAULT_OOM)
-                                               return i ? i : -ENOMEM;
-                                       else if (ret & VM_FAULT_SIGBUS)
-                                               return i ? i : -EFAULT;
-                                       BUG();
+                                 if (ret & VM_FAULT_OOM)
+                                   return i ? i : -ENOMEM;
+                                 else if (ret & VM_FAULT_SIGBUS)
+                                   return i ? i : -EFAULT;
+                                 BUG();
                                }
                                if (ret & VM_FAULT_MAJOR)
-                                       tsk->maj_flt++;
+                                 tsk->maj_flt++;
                                else
-                                       tsk->min_flt++;
-
+                                 tsk->min_flt++;
+                               
                                /*
                                 * The VM_FAULT_WRITE bit tells us that
                                 * do_wp_page has broken COW when necessary,
@@ -303,17 +403,24 @@ int __get_user_pages_uprobe(struct task_struct *tsk, struct mm_struct *mm,
                                 * page might get reCOWed by userspace write).
                                 */
                                if ((ret & VM_FAULT_WRITE) &&
-                                               !(vma->vm_flags & VM_WRITE))
-                                       foll_flags &= ~FOLL_WRITE;
-
+                                   !(vma->vm_flags & VM_WRITE))
+                                 foll_flags &= ~FOLL_WRITE;
+                               
                                //cond_resched();
+#endif
+                               
                        }
+
                        if (IS_ERR(page))
                                return i ? i : PTR_ERR(page);
                        if (pages) {
                                pages[i] = page;
 
+#if  LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18)
+                               flush_anon_page(page, start);
+#else
                                flush_anon_page(vma, page, start);
+#endif
                                flush_dcache_page(page);
                        }
                        if (vmas)
@@ -325,6 +432,8 @@ int __get_user_pages_uprobe(struct task_struct *tsk, struct mm_struct *mm,
        } while (len);
        return i;
 }
+#endif
+
 
 int get_user_pages_uprobe(struct task_struct *tsk, struct mm_struct *mm,
                unsigned long start, int len, int write, int force,
@@ -339,22 +448,22 @@ int get_user_pages_uprobe(struct task_struct *tsk, struct mm_struct *mm,
                flags |= GUP_FLAGS_FORCE;
 
        return __get_user_pages_uprobe(tsk, mm,
-                       start, len, flags,
-                       pages, vmas);
+                               start, len, flags,
+                               pages, vmas);
 #else
-       return get_user_pages(tsk, mm,
-                             start, len, write, force,
-                             pages, vmas);
+       return get_user_pages(tsk, mm, start, len, write, force, pages, vmas);
 #endif
 }
 
-int access_process_vm_atomic (struct task_struct *tsk, unsigned long addr, void *buf, int len, int write)
-{
-
 
+int access_process_vm_atomic(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write)
+{
        struct mm_struct *mm;
        struct vm_area_struct *vma;
        void *old_buf = buf;
+       unsigned long addr1 = addr;
+       unsigned int* inst_buf = (unsigned int*)old_buf;
+
 
        mm = get_task_mm(tsk);
        if (!mm)
@@ -369,6 +478,7 @@ int access_process_vm_atomic (struct task_struct *tsk, unsigned long addr, void
 
                ret = get_user_pages_uprobe(tsk, mm, addr, 1,
                                write, 1, &page, &vma);
+
                if (ret <= 0) {
                        /*
                         * Check if this is a VM_IO | VM_PFNMAP VMA, which
@@ -380,7 +490,7 @@ int access_process_vm_atomic (struct task_struct *tsk, unsigned long addr, void
                                break;
                        if (vma->vm_ops && vma->vm_ops->access)
                                ret = vma->vm_ops->access(vma, addr, buf,
-                                               len, write);
+                                                         len, write);
                        if (ret <= 0)
 #endif
                                break;
@@ -394,11 +504,11 @@ int access_process_vm_atomic (struct task_struct *tsk, unsigned long addr, void
                        maddr = kmap(page);
                        if (write) {
                                copy_to_user_page(vma, page, addr,
-                                               maddr + offset, buf, bytes);
+                                                 maddr + offset, buf, bytes);
                                set_page_dirty_lock(page);
                        } else {
                                copy_from_user_page(vma, page, addr,
-                                               buf, maddr + offset, bytes);
+                                                   buf, maddr + offset, bytes);
                        }
                        kunmap(page);
                        page_cache_release(page);
@@ -411,64 +521,47 @@ int access_process_vm_atomic (struct task_struct *tsk, unsigned long addr, void
        mmput(mm);
 
        return buf - old_buf;
-
 }
 
-int page_present (struct mm_struct *mm, unsigned long addr)
+int page_present (struct mm_struct *mm, unsigned long address)
 {
        pgd_t *pgd;
-       pmd_t *pmd;
-       pte_t *pte;
-       int ret = 0;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11)
-       pud_t *pud;
-#endif
-
-       //printk("page_present\n");
-       //BUG_ON(down_read_trylock(&mm->mmap_sem) == 0);
-       down_read (&mm->mmap_sem);
-       spin_lock (&(mm->page_table_lock));
-       pgd = pgd_offset (mm, addr);
-       //printk("pgd %p\n", pgd);
-       if ((pgd != NULL) && pgd_present (*pgd))
-       {
-               //printk("pgd_present\n");
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11)
-               pud = pud_offset (pgd, addr);
-               //printk("pud %p\n", pud);
-               if ((pud != NULL) && pud_present (*pud))
-               {
-                       pmd = pmd_offset (pud, addr);
-#else
-                       {
-                               pmd = pmd_offset (pgd, addr);
-#endif
-                               //printk("pmd %p\n", pmd);
-                               if ((pmd != NULL) && pmd_present (*pmd))
-                               {
-                                       //spinlock_t *ptl;
-                                       //printk("pmd_present\n");
-                                       pte = pte_offset_map (pmd, addr);
-                                       //pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
-                                       //printk("pte %p/%lx\n", pte, addr);
-                                       if ((pte != NULL) && pte_present (*pte))
-                                       {
-                                               ret = 1;
-                                               //printk("pte_present\n");
-                                       }
-                                       pte_unmap (pte);
-                                       //pte_unmap_unlock(pte, ptl);
-                               }
-                       }
-               }
-               spin_unlock (&(mm->page_table_lock));
-               up_read (&mm->mmap_sem);
-               //printk("page_present %d\n", ret);
-               return ret;
-       }
+        pud_t *pud;
+        pmd_t *pmd;
+        pte_t *ptep, pte;
+        unsigned long pfn;
+
+        pgd = pgd_offset(mm, address);
+        if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
+                goto out;
+
+        pud = pud_offset(pgd, address);
+        if (pud_none(*pud) || unlikely(pud_bad(*pud)))
+                goto out;
+
+        pmd = pmd_offset(pud, address);
+        if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
+                goto out;
+
+        ptep = pte_offset_map(pmd, address);
+        if (!ptep)
+                goto out;
+
+        pte = *ptep;
+        pte_unmap(ptep);
+        if (pte_present(pte)) {
+                pfn = pte_pfn(pte);
+                if (pfn_valid(pfn)) {
+                        return 1;
+                }
+        }
+
+out:
+        return 0;
+}
 
 
-EXPORT_SYMBOL_GPL (access_process_vm_atomic);
 EXPORT_SYMBOL_GPL (page_present);
 EXPORT_SYMBOL_GPL (get_user_pages_uprobe);
+EXPORT_SYMBOL_GPL (access_process_vm_atomic);