rpms/kernel/devel linux-2.6.31-modules-ro-nx.patch, NONE, 1.1 kernel.spec, 1.1795, 1.1796

Dave Jones davej at fedoraproject.org
Fri Sep 11 15:40:08 UTC 2009


Author: davej

Update of /cvs/pkgs/rpms/kernel/devel
In directory cvs1.fedora.phx.redhat.com:/tmp/cvs-serv19549

Modified Files:
	kernel.spec 
Added Files:
	linux-2.6.31-modules-ro-nx.patch 
Log Message:
Apply NX/RO to modules

linux-2.6.31-modules-ro-nx.patch:
 include/linux/module.h |    3 +
 kernel/module.c        |  126 +++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 126 insertions(+), 3 deletions(-)

--- NEW FILE linux-2.6.31-modules-ro-nx.patch ---
>From davej  Fri Sep 11 11:06:50 2009
Return-Path: linux-kernel-owner at vger.kernel.org
X-Spam-Checker-Version: SpamAssassin 3.2.5 (2008-06-10) on
	gelk.kernelslacker.org
X-Spam-Level: 
X-Spam-Status: No, score=-5.5 required=5.0 tests=AWL,BAYES_00,
	RCVD_IN_DNSWL_MED,SARE_MSGID_LONG40,UNPARSEABLE_RELAY autolearn=ham
	version=3.2.5
Received: from mail.corp.redhat.com [10.5.5.51]
	by gelk.kernelslacker.org with IMAP (fetchmail-6.3.9)
	for <davej at localhost> (single-drop); Fri, 11 Sep 2009 11:06:50 -0400 (EDT)
Received: from zmta03.collab.prod.int.phx2.redhat.com (LHLO
 zmta03.collab.prod.int.phx2.redhat.com) (10.5.5.33) by
 mail04.corp.redhat.com with LMTP; Thu, 10 Sep 2009 22:51:21 -0400 (EDT)
Received: from localhost (localhost.localdomain [127.0.0.1])
	by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id E57644F1AB;
	Thu, 10 Sep 2009 22:51:20 -0400 (EDT)
Received: from zmta03.collab.prod.int.phx2.redhat.com ([127.0.0.1])
	by localhost (zmta03.collab.prod.int.phx2.redhat.com [127.0.0.1]) (amavisd-new, port 10024)
	with ESMTP id PqMpQop0Dbp5; Thu, 10 Sep 2009 22:51:20 -0400 (EDT)
Received: from int-mx03.intmail.prod.int.phx2.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.16])
	by zmta03.collab.prod.int.phx2.redhat.com (Postfix) with ESMTP id A56F64F1AA;
	Thu, 10 Sep 2009 22:51:20 -0400 (EDT)
Received: from mx1.redhat.com (ext-mx08.extmail.prod.ext.phx2.redhat.com [10.5.110.12])
	by int-mx03.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id n8B2pDoM001214;
	Thu, 10 Sep 2009 22:51:13 -0400
Received: from vger.kernel.org (vger.kernel.org [209.132.176.167])
	by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id n8B2jC2e031184;
	Thu, 10 Sep 2009 22:51:01 -0400
Received: (majordomo at vger.kernel.org) by vger.kernel.org via listexpand
	id S1753321AbZIKCur (ORCPT <rfc822;mrezanin at redhat.com> + 41 others);
	Thu, 10 Sep 2009 22:50:47 -0400
Received: (majordomo at vger.kernel.org) by vger.kernel.org id S1752432AbZIKCuq
	(ORCPT <rfc822;linux-kernel-outgoing>);
	Thu, 10 Sep 2009 22:50:46 -0400
Received: from mail-yw0-f174.google.com ([209.85.211.174]:34234 "EHLO
	mail-yw0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org
	with ESMTP id S1752401AbZIKCup (ORCPT
	<rfc822;linux-kernel at vger.kernel.org>);
	Thu, 10 Sep 2009 22:50:45 -0400
Received: by ywh4 with SMTP id 4so897627ywh.5
        for <multiple recipients>; Thu, 10 Sep 2009 19:50:47 -0700 (PDT)
DKIM-Signature: 	v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=gamma;
        h=domainkey-signature:mime-version:received:date:message-id:subject
         :from:to:cc:content-type;
        bh=p3+H2ZvljQZotPAF9Gb+FxecqVT3MH9YeBjUUKwwvY0=;
        b=JTV6NmVCgyrG6SVi/FbmJR4FeIQuc44rC3EV0D1A8qPb+xMwNYK5QlD8do+3+FKgbc
         CH/kgCjakj8e5v4ipROLQjPEiN/TETq15ITPKToCOHKve4jS1GMgkZYyYScpBfOj7N9R
         VaWi9sbsNBvUtf1wS83Uqy4GBjZ88MEoBetrs=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=gmail.com; s=gamma;
        h=mime-version:date:message-id:subject:from:to:cc:content-type;
        b=Ksz1JD3HRA+cyDH560RvcyHLpdr4+4Tost2JUGQV5a1m/XC/zwqLdXWNlkWTsuNVvJ
         n+vlXd8VrHE+9h54vf+BMqmK+3LB6Q1iV3nLFpRoU7qaEdnPrWdRcCi8Ot6vIzLrHLf2
         Xu6y7fJWaLQ+cbIGNY2LGR5UlkBul7kaj1API=
MIME-Version: 1.0
Received: by 10.150.17.5 with SMTP id 5mr3930758ybq.195.1252637447825; Thu, 10 
	Sep 2009 19:50:47 -0700 (PDT)
Date: 	Thu, 10 Sep 2009 22:50:47 -0400
Message-ID: <817ecb6f0909101950v2fc6dc6u5cbc40cd9a9dde77 at mail.gmail.com>
Subject: [PATCH v6] RO/NX protection for loadable kernel modules
From: Siarhei Liakh <sliakh.lkml at gmail.com>
To: linux-kernel at vger.kernel.org, linux-security-module at vger.kernel.org,
        linux-next at vger.kernel.org
Cc: Arjan van de Ven <arjan at infradead.org>, James Morris <jmorris at namei.org>,
        Andrew Morton <akpm at linux-foundation.org>, Andi Kleen <ak at muc.de>,
        Thomas Gleixner <tglx at linutronix.de>, "H. Peter Anvin" <hpa at zytor.com>,
        Ingo Molnar <mingo at elte.hu>, Rusty Russell <rusty at rustcorp.com.au>,
        Stephen Rothwell <sfr at canb.auug.org.au>
Content-Type: text/plain; charset=ISO-8859-1
Sender: linux-kernel-owner at vger.kernel.org
Precedence: bulk
List-ID: <linux-kernel.vger.kernel.org>
X-Mailing-List: 	linux-kernel at vger.kernel.org
X-RedHat-Spam-Score: -4  (RCVD_IN_DNSWL_MED)
X-Scanned-By: MIMEDefang 2.67 on 10.5.11.16
X-Scanned-By: MIMEDefang 2.67 on 10.5.110.12
Status: RO
Content-Length: 8042
Lines: 260

This patch is a logical extension of the protection provided by
CONFIG_DEBUG_RODATA to LKMs. The protection is provided by splitting
module_core and module_init into three logical parts each and setting
appropriate page access permissions for each individual section:

 1. Code: RO+X
 2. RO data: RO+NX
 3. RW data: RW+NX

In order to achieve proper protection, layout_sections() have been
modified to align each of the three parts mentioned above onto page
boundary. Next, the corresponding page access permissions are set
right before successful exit from load_module(). Further, free_module()
and sys_init_module have been modified to set module_core and
module_init as RW+NX right before calling module_free().

By default, the original section layout is preserved and RO/NX is
enforced only for whole pages of same content.
However, when compiled with CONFIG_DEBUG_RODATA=y, the patch
will page-align each group of sections to ensure that each page contains
only one type of content.
RO/NX enforcement is active on x86 only.

v1: Initial proof-of-concept patch.

v2: The patch have been re-written to reduce the number of #ifdefs and
to make it architecture-agnostic. Code formatting have been corrected also.

v3: Opportunistic RO/NX protectiuon is now unconditional. Section
page-alignment is enabled when CONFIG_DEBUG_RODATA=y.

v4: Removed most macros and improved coding style.

v5: Changed page-alignment and RO/NX section size calculation

v6: Fixed comments. Restricted RO/NX enforcement to x86 only

The patch have been developed for Linux 2.6.30 by Siarhei Liakh
<sliakh.lkml at gmail.com> and Xuxian Jiang <jiang at cs.ncsu.edu>.

---

Signed-off-by: Siarhei Liakh <sliakh.lkml at gmail.com>
Signed-off-by: Xuxian Jiang <jiang at cs.ncsu.edu>
Acked-by: Arjan van de Ven <arjan at linux.intel.com>

diff --git a/include/linux/module.h b/include/linux/module.h
index 627ac08..5ba770e 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -293,6 +293,9 @@ struct module
 	/* The size of the executable code in each section.  */
 	unsigned int init_text_size, core_text_size;

+	/* Size of RO sections of the module (text+rodata) */
+	unsigned int init_ro_size, core_ro_size;
+
 	/* Arch-specific module values */
 	struct mod_arch_specific arch;

diff --git a/kernel/module.c b/kernel/module.c
index e797812..660278a 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -54,6 +54,7 @@
 #include <linux/async.h>
 #include <linux/percpu.h>
 #include <linux/kmemleak.h>
+#include <linux/pfn.h>
 
 #if 0
 #define DEBUGP printk
@@ -63,6 +64,26 @@
 #define ARCH_SHF_SMALL 0
 #endif

+/*
+ * Modules' sections will be aligned on page boundaries
+ * to ensure complete separation of code and data, but
+ * only when CONFIG_DEBUG_RODATA=y
+ */
+#ifdef CONFIG_DEBUG_RODATA
+#define debug_align(X) ALIGN(X, PAGE_SIZE)
+#else
+#define debug_align(X) (X)
+#endif
+
+/*
+ * Given BASE and SIZE this macro calculates the number of pages the
+ * memory regions occupies
+ */
+#define NUMBER_OF_PAGES(BASE, SIZE) ((SIZE > 0) ?		\
+		(PFN_DOWN((unsigned long)BASE + SIZE - 1) -	\
+			 PFN_DOWN((unsigned long)BASE) + 1)	\
+		: (0UL))
+
 /* If this is set, the section belongs in the init part of the module */
 #define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1))

@@ -1471,6 +1492,69 @@ static int __unlink_module(void *_mod)
 	return 0;
 }

+/*
+ * LKM RO/NX protection: protect module's text/ro-data
+ * from modification and any data from execution.
+ */
+static void set_section_ro_nx(void *base,
+			unsigned long text_size,
+			unsigned long ro_size,
+			unsigned long total_size)
+{
+#ifdef CONFIG_X86
+	/* begin and end PFNs of the current subsection */
+	unsigned long begin_pfn;
+	unsigned long end_pfn;
+
+	/*
+	 * Set RO for module text and RO-data:
+	 * - Always protect first page.
+	 * - Do not protect last partial page.
+	 */
+	if (ro_size > 0) {
+		begin_pfn = PFN_DOWN((unsigned long)base);
+		end_pfn = PFN_DOWN((unsigned long)base + ro_size);
+		if (end_pfn > begin_pfn)
+			set_memory_ro(begin_pfn << PAGE_SHIFT,
+						end_pfn - begin_pfn);
+	}
+
+	/*
+	 * Set NX permissions for module data:
+	 * - Do not protect first partial page.
+	 * - Always protect last page.
+	 */
+	if (total_size > text_size) {
+		begin_pfn = PFN_UP((unsigned long)base + text_size);
+		end_pfn = PFN_UP((unsigned long)base + total_size);
+		if (end_pfn > begin_pfn)
+			set_memory_nx(begin_pfn << PAGE_SHIFT,
+						end_pfn - begin_pfn);
+	}
+#endif
+}
+
+/* Setting memory back to RW+NX before releasing it */
+void unset_section_ro_nx(struct module *mod, void *module_region)
+{
+#ifdef CONFIG_X86
+	unsigned long total_pages;
+
+	if (mod->module_core == module_region) {
+		/* Set core as NX+RW */
+		total_pages = NUMBER_OF_PAGES(mod->module_core, mod->core_size);
+		set_memory_nx((unsigned long)mod->module_core, total_pages);
+		set_memory_rw((unsigned long)mod->module_core, total_pages);
+
+	} else if (mod->module_init == module_region) {
+		/* Set init as NX+RW */
+		total_pages = NUMBER_OF_PAGES(mod->module_init, mod->init_size);
+		set_memory_nx((unsigned long)mod->module_init, total_pages);
+		set_memory_rw((unsigned long)mod->module_init, total_pages);
+	}
+#endif
+}
+
 /* Free a module, remove from lists, etc (must hold module_mutex). */
 static void free_module(struct module *mod)
 {
@@ -1493,6 +1577,7 @@ static void free_module(struct module *mod)
 	ftrace_release(mod->module_core, mod->core_size);

 	/* This may be NULL, but that's OK */
+	unset_section_ro_nx(mod, mod->module_init);
 	module_free(mod, mod->module_init);
 	kfree(mod->args);
 	if (mod->percpu)
@@ -1505,6 +1590,7 @@ static void free_module(struct module *mod)
 	lockdep_free_key_range(mod->module_core, mod->core_size);

 	/* Finally, free the core (containing the module structure) */
+	unset_section_ro_nx(mod, mod->module_core);
 	module_free(mod, mod->module_core);
 }

@@ -1678,8 +1764,19 @@ static void layout_sections(struct module *mod,
 			s->sh_entsize = get_offset(mod, &mod->core_size, s, i);
 			DEBUGP("\t%s\n", secstrings + s->sh_name);
 		}
-		if (m == 0)
+		switch (m) {
+		case 0: /* executable */
+			mod->core_size = debug_align(mod->core_size);
 			mod->core_text_size = mod->core_size;
+			break;
+		case 1: /* RO: text and ro-data */
+			mod->core_size = debug_align(mod->core_size);
+			mod->core_ro_size = mod->core_size;
+			break;
+		case 3: /* whole core */
+			mod->core_size = debug_align(mod->core_size);
+			break;
+		}
 	}

 	DEBUGP("Init section allocation order:\n");
@@ -1696,8 +1793,19 @@ static void layout_sections(struct module *mod,
 					 | INIT_OFFSET_MASK);
 			DEBUGP("\t%s\n", secstrings + s->sh_name);
 		}
-		if (m == 0)
+		switch (m) {
+		case 0: /* executable */
+			mod->init_size = debug_align(mod->init_size);
 			mod->init_text_size = mod->init_size;
+			break;
+		case 1: /* RO: text and ro-data */
+			mod->init_size = debug_align(mod->init_size);
+			mod->init_ro_size = mod->init_size;
+			break;
+		case 3: /* whole init */
+			mod->init_size = debug_align(mod->init_size);
+			break;
+		}
 	}
 }

@@ -2291,6 +2399,18 @@ static noinline struct module *load_module(void __user *umod,
 	/* Get rid of temporary copy */
 	vfree(hdr);

+	/* Set RO and NX regions for core */
+	set_section_ro_nx(mod->module_core,
+				mod->core_text_size,
+				mod->core_ro_size,
+				mod->core_size);
+
+	/* Set RO and NX regions for init */
+	set_section_ro_nx(mod->module_init,
+				mod->init_text_size,
+				mod->init_ro_size,
+				mod->init_size);
+
 	/* Done! */
 	return mod;

@@ -2598,6 +2598,7 @@ SYSCALL_DEFINE3(init_module, void __user
 	mutex_lock(&module_mutex);
 	/* Drop initial reference. */
 	module_put(mod);
+	unset_section_ro_nx(mod, mod->module_init);
 	trim_init_extable(mod);
 	module_free(mod, mod->module_init);
 	mod->module_init = NULL;
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/



Index: kernel.spec
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/devel/kernel.spec,v
retrieving revision 1.1795
retrieving revision 1.1796
diff -u -p -r1.1795 -r1.1796
--- kernel.spec	11 Sep 2009 15:31:52 -0000	1.1795
+++ kernel.spec	11 Sep 2009 15:40:07 -0000	1.1796
@@ -668,6 +668,7 @@ Patch680: linux-2.6-rt2x00-asus-leds.pat
 Patch681: linux-2.6-mac80211-age-scan-results-on-resume.patch
 
 Patch700: linux-2.6.31-nx-data.patch
+Patch701: linux-2.6.31-modules-ro-nx.patch
 
 Patch800: linux-2.6-crash-driver.patch
 
@@ -1299,6 +1300,8 @@ ApplyPatch linux-2.6-ahci-export-capabil
 
 # Mark kernel data as NX
 ApplyPatch linux-2.6.31-nx-data.patch
+# Apply NX/RO to modules
+ApplyPatch linux-2.6.31-modules-ro-nx.patch
 
 # /dev/crash driver.
 ApplyPatch linux-2.6-crash-driver.patch
@@ -2024,6 +2027,9 @@ fi
 
 %changelog
 * Fri Sep 11 2009 Dave Jones <davej at redhat.com>
+- Apply NX/RO to modules
+
+* Fri Sep 11 2009 Dave Jones <davej at redhat.com>
 - Mark kernel data section as NX
 
 * Fri Sep 11 2009 Ben Skeggs <bskeggs at redhat.com>




More information about the fedora-extras-commits mailing list