[PATCH] exporting address to the page fault notifier

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

 



I made a module using the notifier scheme which already exists inside the kernel. The problem is that the page fault notifier doesn't show the address which happened the fault.

This little patch increments this functionality. I chose to break the ABI putting a new field in 'die_args' instead build a new struct only for it. The patch and the module notifier comes attached.

my regards


--
Tiago Vignatti
C3SL - Centro de Computação Científica e Software Livre
www.c3sl.ufpr.br
diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c
index 01ffdd4..c405802 100644
--- a/arch/i386/mm/fault.c
+++ b/arch/i386/mm/fault.c
@@ -47,14 +47,15 @@ int unregister_page_fault_notifier(struct notifier_block *nb)
 }
 EXPORT_SYMBOL_GPL(unregister_page_fault_notifier);
 
-static inline int notify_page_fault(struct pt_regs *regs, long err)
+static inline int notify_page_fault(struct pt_regs *regs, long err, unsigned long address)
 {
 	struct die_args args = {
 		.regs = regs,
 		.str = "page fault",
 		.err = err,
 		.trapnr = 14,
-		.signr = SIGSEGV
+		.signr = SIGSEGV,
+		.address = address
 	};
 	return atomic_notifier_call_chain(&notify_page_fault_chain,
 	                                  DIE_PAGE_FAULT, &args);
@@ -330,7 +331,7 @@ fastcall void __kprobes do_page_fault(struct pt_regs *regs,
 	if (unlikely(address >= TASK_SIZE)) {
 		if (!(error_code & 0x0000000d) && vmalloc_fault(address) >= 0)
 			return;
-		if (notify_page_fault(regs, error_code) == NOTIFY_STOP)
+		if (notify_page_fault(regs, error_code, address) == NOTIFY_STOP)
 			return;
 		/*
 		 * Don't take the mm semaphore here. If we fixup a prefetch
@@ -339,7 +340,7 @@ fastcall void __kprobes do_page_fault(struct pt_regs *regs,
 		goto bad_area_nosemaphore;
 	}
 
-	if (notify_page_fault(regs, error_code) == NOTIFY_STOP)
+	if (notify_page_fault(regs, error_code, address) == NOTIFY_STOP)
 		return;
 
 	/* It's safe to allow irq's after cr2 has been saved and the vmalloc
diff --git a/include/linux/kdebug.h b/include/linux/kdebug.h
index 5db38d6..e8005c2 100644
--- a/include/linux/kdebug.h
+++ b/include/linux/kdebug.h
@@ -9,6 +9,7 @@ struct die_args {
 	long err;
 	int trapnr;
 	int signr;
+	unsigned long address;
 };
 
 int register_die_notifier(struct notifier_block *nb);
/* 
 * Author: Tiago Vignatti <vignatti (at) c3sl ufpr br>
 * 2007 - code under GPL 
 */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/notifier.h>
#include <linux/kdebug.h>

/* 
 * error_code:
 *      bit 0 == 0 means no page found, 1 means protection fault
 *      bit 1 == 0 means read, 1 means write
 *      bit 2 == 0 means kernel, 1 means user-mode
 *      bit 3 == 1 means use of reserved bit detected
 *      bit 4 == 1 means fault was an instruction fetch
 */
static int pf_notify (struct notifier_block *self,
                                unsigned long val, void *data)
{
	struct die_args *args = (struct die_args *) data;

	/* You can filter the types of page like this: 
	if (args->err < 4)
		return NOTIFY_DONE;
	*/

	printk("pagefault regs: %p, address: 0x%lx, fault: %lx ",
	       args->regs, args->address, args->err);

	switch (args->err) {
		case 7:
			printk("(write protection fault in user-mode)\n");
			break;
		case 6:
			printk("(write page fault in user-mode)\n");
			break;
		case 5:
			printk("(write protection fault in user-mode)\n");
			break;
		case 4:
			printk("(read page fault in user-mode)\n");
			break;
		case 3:
			printk("(write protection fault in kernel-mode)\n");
			break;
		case 2:
			printk("(write page fault in kernel-mode)\n");
			break;
		case 1:
			printk("(read protection fault in kernel-mode)\n");
			break;
		case 0:
			printk("(read page fault in kernel-mode)\n");
			break;
		default :
			printk("(use of reserved bit detected or fault was an instruction fetch)\n");
			break;
	}

	return NOTIFY_DONE;
}

static struct notifier_block my_nb = {
	.notifier_call = pf_notify,
};

static int __init notifier_init(void)
{
	int ret;

	if ((ret = register_page_fault_notifier(&my_nb)) < 0) {
		printk("register_page_fault_notifier failed, returned %d\n", ret);
		return -1;
	}

	printk("Planted page fault notifier!\n");
	return 0;
}

static void __exit notifier_exit(void)
{
	unregister_page_fault_notifier(&my_nb);
	printk("Page fault notifier unregistered\n");
}

module_init(notifier_init)
module_exit(notifier_exit)
MODULE_LICENSE("GPL");

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux