All of lore.kernel.org
 help / color / mirror / Atom feed
From: Konstantin Khlebnikov <khlebnikov@openvz.org>
To: linux-kernel@vger.kernel.org
Cc: x86@kernel.org, Arjan van de Ven <arjan@linux.intel.com>,
	"H. Peter Anvin" <hpa@zytor.com>
Subject: [PATCH] x86/test_nx: update testing module after recent kernel changes
Date: Fri, 14 Dec 2012 15:01:49 +0400	[thread overview]
Message-ID: <20121214110149.9548.37883.stgit@zurg> (raw)

"test_nx" isn't uptodate, kernel has been changed since its last revision.
For now it only able to crash kernel on loading.

exception tables are relative since commit v3.4-rc3-33-g7062765
("x86, extable: Switch to relative exception table entries")

Exception entries now unusable for this test, because exception table cannot
lays farther than 2gb from covering address. This patch adds DIE_PAGE_FAULT
notifier into no_context() function in arch/x86/mm/fault.c and handles these
exceptions manually.

modules' data sections now can be ro/nx protected since v2.6.37-rc2-3-g84e1c6b
("x86: Add RO/NX protection for loadable kernel modules")
thus fourth testcase can be enabled.

Signed-off-by: Konstantin Khlebnikov <khlebnikov@openvz.org>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: x86@kernel.org

---

sample oops on module loading before this patch:

[    2.343411] Testing NX protection
[    2.343457] kernel tried to execute NX-protected page - exploit attempt? (uid: 0)
[    2.343494] BUG: unable to handle kernel paging request at ffff88007c951da5
[    2.343590] IP: [<ffff88007c951da5>] 0xffff88007c951da4
[    2.343657] PGD 1e0c063 PUD 1fffc067 PMD 800000007c8001e3
[    2.343780] Oops: 0011 [#1] SMP
[    2.343872] Modules linked in: test_nx(+) ide_generic eni suni atm mce_inject edac_core ar7part mtd cmd640 sctp cs5520 dccp_ipv6 dccp_ipv4 dccp cs55
35_mfgpt bnep rfcomm bluetooth fuse nfsd exportfs powernow_k8 kvm_amd k8temp i2c_nforce2 evbug pcspkr kvm btrfs zlib_deflate libcrc32c ide_pci_generic
ide_core ata_generic pata_acpi sata_nv [last unloaded: cdc_wdm]
[    2.344363] CPU 1
[    2.344363] Pid: 15140, comm: modprobe Tainted: P             3.7.0-rc8-next-20121211+ #597 Gigabyte Technology Co., Ltd. M52S-S3P/M52S-S3P
[    2.344363] RIP: 0010:[<ffff88007c951da5>]  [<ffff88007c951da5>] 0xffff88007c951da4
[    2.344363] RSP: 0018:ffff88007c951d70  EFLAGS: 00010246
[    2.344363] RAX: 0000000000000000 RBX: 0000000000000001 RCX: ffff88007fc8f328
[    2.344363] RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff88007c951da5
[    2.344363] RBP: ffff88007c951d88 R08: 0000000000000000 R09: 0000000000000000
[    2.344363] R10: ffff88007c951fd8 R11: 0000000000000992 R12: ffff88007c951da5
[    2.344363] R13: 0000000000000000 R14: ffff88007b0553e0 R15: ffff88007c951ee8
[    2.344363] FS:  00007f12352de700(0000) GS:ffff88007fc80000(0000) knlGS:0000000000000000
[    2.344363] CS:  0010 DS: 0000 ES: 0000 CR0: 000000008005003b
[    2.344363] CR2: ffff88007c951da5 CR3: 000000007a23b000 CR4: 00000000000007e0
[    2.344363] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[    2.344363] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
[    2.344363] Process modprobe (pid: 15140, threadinfo ffff88007c950000, task ffff880079038000)
[    2.344363] Stack:
[    2.344363]  ffffffffa0bf002f ffffffffa0bf0320 ffffffffa0bf00a0 ffff88007c951db8
[    2.344363]  ffffffffa0bf00d5 ffff88007b0553e0 0090c30000000000 ffffffffa0bf0320
[    2.344363]  ffffffffa0bf00a0 ffff88007c951de8 ffffffff810002da ffffffffa0bf0320
[    2.344363] Call Trace:
[    2.344363]  [<ffffffffa0bf002f>] ? foo_label+0x3/0x74 [test_nx]
[    2.344363]  [<ffffffffa0bf00a0>] ? foo_label+0x74/0x74 [test_nx]
[    2.344363]  [<ffffffffa0bf00d5>] test_NX+0x35/0x120 [test_nx]
[    2.344363]  [<ffffffffa0bf00a0>] ? foo_label+0x74/0x74 [test_nx]
[    2.344363]  [<ffffffff810002da>] do_one_initcall+0x11a/0x170
[    2.344363]  [<ffffffff810a28ad>] load_module+0x196d/0x1e40
[    2.344363]  [<ffffffff8109e8f0>] ? __unlink_module+0x30/0x30
[    2.344363]  [<ffffffff810a2e46>] sys_init_module+0xc6/0xf0
[    2.344363]  [<ffffffff81801a12>] system_call_fastpath+0x16/0x1b
[    2.344363] Code: bf a0 ff ff ff ff a0 00 bf a0 ff ff ff ff b8 1d 95 7c 00 88 ff ff d5 00 bf a0 ff ff ff ff e0 53 05 7b 00 88 ff ff 00 00 00 00 00 <c3> 90 00 20 03 bf a0 ff ff ff ff a0 00 bf a0 ff ff ff ff e8 1d
[    2.344363] RIP  [<ffff88007c951da5>] 0xffff88007c951da4
[    2.344363]  RSP <ffff88007c951d70>
[    2.344363] CR2: ffff88007c951da5
---
 arch/x86/kernel/test_nx.c |   82 +++++++++++++++++++--------------------------
 arch/x86/mm/fault.c       |    4 ++
 2 files changed, 39 insertions(+), 47 deletions(-)

diff --git a/arch/x86/kernel/test_nx.c b/arch/x86/kernel/test_nx.c
index 3f92ce0..98020bc 100644
--- a/arch/x86/kernel/test_nx.c
+++ b/arch/x86/kernel/test_nx.c
@@ -12,6 +12,7 @@
 #include <linux/module.h>
 #include <linux/sort.h>
 #include <linux/slab.h>
+#include <linux/kdebug.h>
 
 #include <asm/uaccess.h>
 #include <asm/asm.h>
@@ -27,48 +28,30 @@ extern int rodata_test_data;
  *
  * To do this, the test code tries to execute memory in stack/kmalloc/etc,
  * and then checks if the expected trap happens.
- *
- * Sadly, this implies having a dynamic exception handling table entry.
- * ... which can be done (and will make Rusty cry)... but it can only
- * be done in a stand-alone module with only 1 entry total.
- * (otherwise we'd have to sort and that's just too messy)
  */
 
+static void *exception_label;
 
+void fixup_label(void);
 
-/*
- * We want to set up an exception handling point on our stack,
- * which means a variable value. This function is rather dirty
- * and walks the exception table of the module, looking for a magic
- * marker and replaces it with a specific function.
- */
-static void fudze_exception_table(void *marker, void *new)
+static int die_notify(struct notifier_block *nb, unsigned long val, void *data)
 {
-	struct module *mod = THIS_MODULE;
-	struct exception_table_entry *extable;
+	struct die_args *args = data;
+	struct pt_regs *regs = args->regs;
 
-	/*
-	 * Note: This module has only 1 exception table entry,
-	 * so searching and sorting is not needed. If that changes,
-	 * this would be the place to search and re-sort the exception
-	 * table.
-	 */
-	if (mod->num_exentries > 1) {
-		printk(KERN_ERR "test_nx: too many exception table entries!\n");
-		printk(KERN_ERR "test_nx: test results are not reliable.\n");
-		return;
+	if (val == DIE_PAGE_FAULT &&
+	    regs->ip == (unsigned long)exception_label) {
+		regs->ip = (unsigned long)fixup_label;
+		return NOTIFY_STOP;
 	}
-	extable = (struct exception_table_entry *)mod->extable;
-	extable[0].insn = (unsigned long)new;
-}
 
+	return NOTIFY_DONE;
+}
 
-/*
- * exception tables get their symbols translated so we need
- * to use a fake function to put in there, which we can then
- * replace at runtime.
- */
-void foo_label(void);
+struct notifier_block die_notify_block = {
+	.notifier_call = die_notify,
+	.priority = INT_MAX, /* Highest priority */
+};
 
 /*
  * returns 0 for not-executable, negative for executable
@@ -81,23 +64,20 @@ static noinline int test_address(void *address)
 {
 	unsigned long result;
 
-	/* Set up an exception table entry for our address */
-	fudze_exception_table(&foo_label, address);
+	/* Set up an exception label for our address */
+	exception_label = address;
+
 	result = 1;
 	asm volatile(
-		"foo_label:\n"
-		"0:	call *%[fake_code]\n"
-		"1:\n"
+		"	call *%[fake_code]\n"
 		".section .fixup,\"ax\"\n"
-		"2:	mov %[zero], %[rslt]\n"
+		"fixup_label:\n"
+		"	mov %[zero], %[rslt]\n"
 		"	ret\n"
 		".previous\n"
-		_ASM_EXTABLE(0b,2b)
 		: [rslt] "=r" (result)
 		: [fake_code] "r" (address), [zero] "r" (0UL), "0" (result)
 	);
-	/* change the exception table back for the next round */
-	fudze_exception_table(address, &foo_label);
 
 	if (result)
 		return -ENODEV;
@@ -108,10 +88,14 @@ static unsigned char test_data = 0xC3; /* 0xC3 is the opcode for "ret" */
 
 static int test_NX(void)
 {
-	int ret = 0;
 	/* 0xC3 is the opcode for "ret" */
 	char stackcode[] = {0xC3, 0x90, 0 };
 	char *heap;
+	int ret;
+
+	ret = register_die_notifier(&die_notify_block);
+	if (ret)
+		return ret;
 
 	test_data = 0xC3;
 
@@ -126,8 +110,10 @@ static int test_NX(void)
 
 	/* Test 2: Check if the heap is executable */
 	heap = kmalloc(64, GFP_KERNEL);
-	if (!heap)
-		return -ENOMEM;
+	if (!heap) {
+		ret = -ENOMEM;
+		goto out;
+	}
 	heap[0] = 0xC3; /* opcode for "ret" */
 
 	if (test_address(heap)) {
@@ -153,14 +139,16 @@ static int test_NX(void)
 	}
 #endif
 
-#if 0
+#ifdef CONFIG_DEBUG_SET_MODULE_RONX
 	/* Test 4: Check if the .data section of a module is executable */
 	if (test_address(&test_data)) {
 		printk(KERN_ERR "test_nx: .data section is executable\n");
 		ret = -ENODEV;
 	}
-
 #endif
+
+out:
+	unregister_die_notifier(&die_notify_block);
 	return ret;
 }
 
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 027088f..0d2665e 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -664,6 +664,10 @@ no_context(struct pt_regs *regs, unsigned long error_code,
 	if (is_errata93(regs, address))
 		return;
 
+	if (notify_die(DIE_PAGE_FAULT, "page fault", regs, error_code,
+				X86_TRAP_PF, signal) == NOTIFY_STOP)
+		return;
+
 	/*
 	 * Oops. The kernel tried to access some bad page. We'll have to
 	 * terminate things with extreme prejudice:


                 reply	other threads:[~2012-12-14 11:02 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

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=20121214110149.9548.37883.stgit@zurg \
    --to=khlebnikov@openvz.org \
    --cc=arjan@linux.intel.com \
    --cc=hpa@zytor.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=x86@kernel.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.