Skip to contentSkip to conversation

x86: Supervisor Mode Access Prevention

PATCH In review H. Peter Anvin 13 participants 56 messages Sep 21, 2012 – Jan 19, 2013

Subsystems (5)
Documentation x86 ACPI x86 MM +1 more subsystems
lore
Share & tools
lore
#0 lore raw

cover x86: Supervisor Mode Access Prevention

Supervisor Mode Access Prevention (SMAP) is a new security feature disclosed by Intel in revision 014 of the Intel® Architecture Instruction Set Extensions Programming Reference:

http://software.intel.com/sites/default/files/319433-014.pdf

When SMAP is active, the kernel cannot normally access pages that are user space (U=1). Since the kernel does have the need to access user space pages under specific circumstances, an override is provided: the kernel can access user space pages if EFLAGS.AC=1. For system data structures, e.g. descriptor tables, that are accessed by the processor directly, SMAP is active even in CPL 3 regardless of EFLAGS.AC.

SMAP also includes two new instructions, STAC and CLAC, to flip the AC flag more quickly.

Note: patch 01/11 is already in tip:x86/cpufeature.

List of patches:
x86, cpufeature: Add feature bit for SMAP
x86-32, mm: The WP test should be done on a kernel page x86, smap: Add CR4 bit for SMAP
x86, alternative: Use .pushsection/.popsection
x86, alternative: Add header guards to <asm/alternative-asm.h> x86, smap: Add a header file with macros for STAC/CLAC x86, uaccess: Merge prototypes for clear_user/__clear_user x86, smap: Add STAC and CLAC instructions to control user space access x86, smap: Turn on Supervisor Mode Access Prevention
x86, smap: A page fault due to SMAP is an oops
x86, smap: Reduce the SMAP overhead for signal handling

Diff stat:

 Documentation/kernel-parameters.txt    |    6 ++-
 arch/x86/Kconfig                       |   11 ++++
 arch/x86/ia32/ia32_signal.c            |   12 +++--
 arch/x86/ia32/ia32entry.S              |    6 ++
 arch/x86/include/asm/alternative-asm.h |    9 +++-
 arch/x86/include/asm/alternative.h     |   32 ++++++------
 arch/x86/include/asm/cpufeature.h      |    1 +
 arch/x86/include/asm/fpu-internal.h    |   10 ++--
 arch/x86/include/asm/futex.h           |   19 +++++--
 arch/x86/include/asm/processor-flags.h |    1 +
 arch/x86/include/asm/smap.h            |   91 ++++++++++++++++++++++++++++++++
 arch/x86/include/asm/uaccess.h         |   28 ++++++----
 arch/x86/include/asm/uaccess_32.h      |    3 -
 arch/x86/include/asm/uaccess_64.h      |    3 -
 arch/x86/include/asm/xsave.h           |   10 ++--
 arch/x86/kernel/cpu/common.c           |   29 ++++++++++-
 arch/x86/kernel/entry_64.S             |   11 ++++-
 arch/x86/kernel/signal.c               |   24 +++++----
 arch/x86/lib/copy_user_64.S            |    7 +++
 arch/x86/lib/copy_user_nocache_64.S    |    3 +
 arch/x86/lib/getuser.S                 |   10 ++++
 arch/x86/lib/putuser.S                 |    8 +++-
 arch/x86/lib/usercopy_32.c             |   13 ++++-
 arch/x86/lib/usercopy_64.c             |    3 +
 arch/x86/mm/fault.c                    |   18 ++++++
 arch/x86/mm/init_32.c                  |    2 +-
 26 files changed, 301 insertions(+), 69 deletions(-)
#1 lore raw

PATCH 1/11 x86, cpufeature: Add feature bit for SMAP

From: "H. Peter Anvin" <[email protected]>

Add CPUID feature bit for Supervisor Mode Access Prevention (SMAP).

---
 arch/x86/include/asm/cpufeature.h |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
arch/x86/include/asm/cpufeature.h +1 -0
index 6b7ee5f..633b617 100644
@@ -209,6 +209,7 @@
 #define X86_FEATURE_RTM		(9*32+11) /* Restricted Transactional Memory */
 #define X86_FEATURE_RDSEED	(9*32+18) /* The RDSEED instruction */
 #define X86_FEATURE_ADX		(9*32+19) /* The ADCX and ADOX instructions */
+#define X86_FEATURE_SMAP	(9*32+20) /* Supervisor Mode Access Prevention */
 
 #if defined(__KERNEL__) && !defined(__ASSEMBLY__)
 
Signature · 1 line
1.7.6.5
#2 lore raw

PATCH 2/11 x86-32, mm: The WP test should be done on a kernel page

In reply to H. Peter Anvin

From: "H. Peter Anvin" <[email protected]>

PAGE_READONLY includes user permission, but this is a page used exclusively by the kernel; use PAGE_KERNEL_RO instead.

---
 arch/x86/mm/init_32.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
arch/x86/mm/init_32.c +1 -1
index 575d86f..e537b35 100644
@@ -712,7 +712,7 @@ static void __init test_wp_bit(void)
   "Checking if this processor honours the WP bit even in supervisor mode...");
 
 	/* Any page-aligned address will do, the test is non-destructive */
-	__set_fixmap(FIX_WP_TEST, __pa(&swapper_pg_dir), PAGE_READONLY);
+	__set_fixmap(FIX_WP_TEST, __pa(&swapper_pg_dir), PAGE_KERNEL_RO);
 	boot_cpu_data.wp_works_ok = do_test_wp_bit();
 	clear_fixmap(FIX_WP_TEST);
 
Signature · 1 line
1.7.6.5
#3 lore raw

[tip:x86/smap] x86-32, mm: The WP test should be done on a kernel page

Commit-ID:  8bd753be7a96443dd5111cb07ed5907a3787c978
Gitweb:     http://git.kernel.org/tip/8bd753be7a96443dd5111cb07ed5907a3787c978
Author:     H. Peter Anvin <[email protected]>
AuthorDate: Fri, 21 Sep 2012 12:43:06 -0700
Committer:  H. Peter Anvin <[email protected]>
CommitDate: Fri, 21 Sep 2012 12:45:25 -0700

x86-32, mm: The WP test should be done on a kernel page

PAGE_READONLY includes user permission, but this is a page used exclusively by the kernel; use PAGE_KERNEL_RO instead.

---
 arch/x86/mm/init_32.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
arch/x86/mm/init_32.c +1 -1
index 575d86f..e537b35 100644
@@ -712,7 +712,7 @@ static void __init test_wp_bit(void)
   "Checking if this processor honours the WP bit even in supervisor mode...");
 
 	/* Any page-aligned address will do, the test is non-destructive */
-	__set_fixmap(FIX_WP_TEST, __pa(&swapper_pg_dir), PAGE_READONLY);
+	__set_fixmap(FIX_WP_TEST, __pa(&swapper_pg_dir), PAGE_KERNEL_RO);
 	boot_cpu_data.wp_works_ok = do_test_wp_bit();
 	clear_fixmap(FIX_WP_TEST);
 
#4 lore raw

PATCH 3/11 x86, smap: Add CR4 bit for SMAP

In reply to H. Peter Anvin

From: "H. Peter Anvin" <[email protected]>

Add X86_CR4_SMAP to <asm/processor-flags.h>.

---
 arch/x86/include/asm/processor-flags.h |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
arch/x86/include/asm/processor-flags.h +1 -0
index aea1d1d..680cf09 100644
@@ -65,6 +65,7 @@
 #define X86_CR4_PCIDE	0x00020000 /* enable PCID support */
 #define X86_CR4_OSXSAVE 0x00040000 /* enable xsave and xrestore */
 #define X86_CR4_SMEP	0x00100000 /* enable SMEP support */
+#define X86_CR4_SMAP	0x00200000 /* enable SMAP support */
 
 /*
  * x86-64 Task Priority Register, CR8
Signature · 1 line
1.7.6.5
#5 lore raw

[tip:x86/smap] x86, smap: Add CR4 bit for SMAP

Commit-ID:  85fdf05cc395f23384cb0adb22765cbaa9653b54
Gitweb:     http://git.kernel.org/tip/85fdf05cc395f23384cb0adb22765cbaa9653b54
Author:     H. Peter Anvin <[email protected]>
AuthorDate: Fri, 21 Sep 2012 12:43:07 -0700
Committer:  H. Peter Anvin <[email protected]>
CommitDate: Fri, 21 Sep 2012 12:45:25 -0700

x86, smap: Add CR4 bit for SMAP

Add X86_CR4_SMAP to <asm/processor-flags.h>.

---
 arch/x86/include/asm/processor-flags.h |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
arch/x86/include/asm/processor-flags.h +1 -0
index aea1d1d..680cf09 100644
@@ -65,6 +65,7 @@
 #define X86_CR4_PCIDE	0x00020000 /* enable PCID support */
 #define X86_CR4_OSXSAVE 0x00040000 /* enable xsave and xrestore */
 #define X86_CR4_SMEP	0x00100000 /* enable SMEP support */
+#define X86_CR4_SMAP	0x00200000 /* enable SMAP support */
 
 /*
  * x86-64 Task Priority Register, CR8
#6 lore raw

PATCH 4/11 x86, alternative: Use .pushsection/.popsection

In reply to H. Peter Anvin

From: "H. Peter Anvin" <[email protected]>

.section/.previous doesn't nest. Use .pushsection/.popsection in <asm/alternative.h> so that they can be properly nested.

---
 arch/x86/include/asm/alternative-asm.h |    4 ++--
 arch/x86/include/asm/alternative.h     |   32 ++++++++++++++++----------------
 2 files changed, 18 insertions(+), 18 deletions(-)
arch/x86/include/asm/alternative-asm.h +2 -2
index 952bd01..018d29f 100644
@@ -5,10 +5,10 @@
 #ifdef CONFIG_SMP
 	.macro LOCK_PREFIX
 672:	lock
-	.section .smp_locks,"a"
+	.pushsection .smp_locks,"a"
 	.balign 4
 	.long 672b - .
-	.previous
+	.popsection
 	.endm
 #else
 	.macro LOCK_PREFIX
arch/x86/include/asm/alternative.h +16 -16
index 7078068..87bc00d 100644
@@ -29,10 +29,10 @@
 
 #ifdef CONFIG_SMP
 #define LOCK_PREFIX_HERE \
-		".section .smp_locks,\"a\"\n"	\
-		".balign 4\n"			\
-		".long 671f - .\n" /* offset */	\
-		".previous\n"			\
+		".pushsection .smp_locks,\"a\"\n"	\
+		".balign 4\n"				\
+		".long 671f - .\n" /* offset */		\
+		".popsection\n"				\
 		"671:"
 
 #define LOCK_PREFIX LOCK_PREFIX_HERE "\n\tlock; "
@@ -99,30 +99,30 @@ static inline int alternatives_text_reserved(void *start, void *end)
 /* alternative assembly primitive: */
 #define ALTERNATIVE(oldinstr, newinstr, feature)			\
 	OLDINSTR(oldinstr)						\
-	".section .altinstructions,\"a\"\n"				\
+	".pushsection .altinstructions,\"a\"\n"				\
 	ALTINSTR_ENTRY(feature, 1)					\
-	".previous\n"							\
-	".section .discard,\"aw\",@progbits\n"				\
+	".popsection\n"							\
+	".pushsection .discard,\"aw\",@progbits\n"			\
 	DISCARD_ENTRY(1)						\
-	".previous\n"							\
-	".section .altinstr_replacement, \"ax\"\n"			\
+	".popsection\n"							\
+	".pushsection .altinstr_replacement, \"ax\"\n"			\
 	ALTINSTR_REPLACEMENT(newinstr, feature, 1)			\
-	".previous"
+	".popsection"
 
 #define ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2)\
 	OLDINSTR(oldinstr)						\
-	".section .altinstructions,\"a\"\n"				\
+	".pushsection .altinstructions,\"a\"\n"				\
 	ALTINSTR_ENTRY(feature1, 1)					\
 	ALTINSTR_ENTRY(feature2, 2)					\
-	".previous\n"							\
-	".section .discard,\"aw\",@progbits\n"				\
+	".popsection\n"							\
+	".pushsection .discard,\"aw\",@progbits\n"			\
 	DISCARD_ENTRY(1)						\
 	DISCARD_ENTRY(2)						\
-	".previous\n"							\
-	".section .altinstr_replacement, \"ax\"\n"			\
+	".popsection\n"							\
+	".pushsection .altinstr_replacement, \"ax\"\n"			\
 	ALTINSTR_REPLACEMENT(newinstr1, feature1, 1)			\
 	ALTINSTR_REPLACEMENT(newinstr2, feature2, 2)			\
-	".previous"
+	".popsection"
 
 /*
  * This must be included *after* the definition of ALTERNATIVE due to
Signature · 1 line
1.7.6.5
#7 lore raw

[tip:x86/smap] x86, alternative: Use .pushsection/.popsection

Commit-ID:  9cebed423c84a56b871327dd77e555d1d2186a6b
Gitweb:     http://git.kernel.org/tip/9cebed423c84a56b871327dd77e555d1d2186a6b
Author:     H. Peter Anvin <[email protected]>
AuthorDate: Fri, 21 Sep 2012 12:43:08 -0700
Committer:  H. Peter Anvin <[email protected]>
CommitDate: Fri, 21 Sep 2012 12:45:25 -0700

x86, alternative: Use .pushsection/.popsection

.section/.previous doesn't nest. Use .pushsection/.popsection in <asm/alternative.h> so that they can be properly nested.

---
 arch/x86/include/asm/alternative-asm.h |    4 ++--
 arch/x86/include/asm/alternative.h     |   32 ++++++++++++++++----------------
 2 files changed, 18 insertions(+), 18 deletions(-)
arch/x86/include/asm/alternative-asm.h +2 -2
index 952bd01..018d29f 100644
@@ -5,10 +5,10 @@
 #ifdef CONFIG_SMP
 	.macro LOCK_PREFIX
 672:	lock
-	.section .smp_locks,"a"
+	.pushsection .smp_locks,"a"
 	.balign 4
 	.long 672b - .
-	.previous
+	.popsection
 	.endm
 #else
 	.macro LOCK_PREFIX
arch/x86/include/asm/alternative.h +16 -16
index 7078068..87bc00d 100644
@@ -29,10 +29,10 @@
 
 #ifdef CONFIG_SMP
 #define LOCK_PREFIX_HERE \
-		".section .smp_locks,\"a\"\n"	\
-		".balign 4\n"			\
-		".long 671f - .\n" /* offset */	\
-		".previous\n"			\
+		".pushsection .smp_locks,\"a\"\n"	\
+		".balign 4\n"				\
+		".long 671f - .\n" /* offset */		\
+		".popsection\n"				\
 		"671:"
 
 #define LOCK_PREFIX LOCK_PREFIX_HERE "\n\tlock; "
@@ -99,30 +99,30 @@ static inline int alternatives_text_reserved(void *start, void *end)
 /* alternative assembly primitive: */
 #define ALTERNATIVE(oldinstr, newinstr, feature)			\
 	OLDINSTR(oldinstr)						\
-	".section .altinstructions,\"a\"\n"				\
+	".pushsection .altinstructions,\"a\"\n"				\
 	ALTINSTR_ENTRY(feature, 1)					\
-	".previous\n"							\
-	".section .discard,\"aw\",@progbits\n"				\
+	".popsection\n"							\
+	".pushsection .discard,\"aw\",@progbits\n"			\
 	DISCARD_ENTRY(1)						\
-	".previous\n"							\
-	".section .altinstr_replacement, \"ax\"\n"			\
+	".popsection\n"							\
+	".pushsection .altinstr_replacement, \"ax\"\n"			\
 	ALTINSTR_REPLACEMENT(newinstr, feature, 1)			\
-	".previous"
+	".popsection"
 
 #define ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2)\
 	OLDINSTR(oldinstr)						\
-	".section .altinstructions,\"a\"\n"				\
+	".pushsection .altinstructions,\"a\"\n"				\
 	ALTINSTR_ENTRY(feature1, 1)					\
 	ALTINSTR_ENTRY(feature2, 2)					\
-	".previous\n"							\
-	".section .discard,\"aw\",@progbits\n"				\
+	".popsection\n"							\
+	".pushsection .discard,\"aw\",@progbits\n"			\
 	DISCARD_ENTRY(1)						\
 	DISCARD_ENTRY(2)						\
-	".previous\n"							\
-	".section .altinstr_replacement, \"ax\"\n"			\
+	".popsection\n"							\
+	".pushsection .altinstr_replacement, \"ax\"\n"			\
 	ALTINSTR_REPLACEMENT(newinstr1, feature1, 1)			\
 	ALTINSTR_REPLACEMENT(newinstr2, feature2, 2)			\
-	".previous"
+	".popsection"
 
 /*
  * This must be included *after* the definition of ALTERNATIVE due to
#8 lore raw

PATCH 5/11 x86, alternative: Add header guards to <asm/alternative-asm.h>

In reply to H. Peter Anvin

From: "H. Peter Anvin" <[email protected]>

Add header guards to protect <asm/alternative-asm.h> against multiple inclusion.

---
 arch/x86/include/asm/alternative-asm.h |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)
arch/x86/include/asm/alternative-asm.h +5 -0
index 018d29f..372231c 100644
@@ -1,3 +1,6 @@
+#ifndef _ASM_X86_ALTERNATIVE_ASM_H
+#define _ASM_X86_ALTERNATIVE_ASM_H
+
 #ifdef __ASSEMBLY__
 
 #include <asm/asm.h>
@@ -24,3 +27,5 @@
 .endm
 
 #endif  /*  __ASSEMBLY__  */
+
+#endif /* _ASM_X86_ALTERNATIVE_ASM_H */
Signature · 1 line
1.7.6.5
#9 lore raw

[tip:x86/smap] x86, alternative: Add header guards to <asm/ alternative-asm.h>

Commit-ID:  76f30759f690db21ca567a20665ed2679ad3235b
Gitweb:     http://git.kernel.org/tip/76f30759f690db21ca567a20665ed2679ad3235b
Author:     H. Peter Anvin <[email protected]>
AuthorDate: Fri, 21 Sep 2012 12:43:09 -0700
Committer:  H. Peter Anvin <[email protected]>
CommitDate: Fri, 21 Sep 2012 12:45:26 -0700

x86, alternative: Add header guards to <asm/alternative-asm.h>

Add header guards to protect <asm/alternative-asm.h> against multiple inclusion.

---
 arch/x86/include/asm/alternative-asm.h |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)
arch/x86/include/asm/alternative-asm.h +5 -0
index 018d29f..372231c 100644
@@ -1,3 +1,6 @@
+#ifndef _ASM_X86_ALTERNATIVE_ASM_H
+#define _ASM_X86_ALTERNATIVE_ASM_H
+
 #ifdef __ASSEMBLY__
 
 #include <asm/asm.h>
@@ -24,3 +27,5 @@
 .endm
 
 #endif  /*  __ASSEMBLY__  */
+
+#endif /* _ASM_X86_ALTERNATIVE_ASM_H */
#10 lore raw

PATCH 6/11 x86, smap: Add a header file with macros for STAC/CLAC

In reply to H. Peter Anvin

From: "H. Peter Anvin" <[email protected]>

The STAC/CLAC instructions are only available with SMAP, but on the other hand they aren't needed if SMAP is not available, or before we start to run userspace, so construct them as alternatives which start out as noops and are enabled by the alternatives mechanism.

---
 arch/x86/Kconfig            |   11 +++++
 arch/x86/include/asm/smap.h |   91 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 102 insertions(+), 0 deletions(-)
 create mode 100644 arch/x86/include/asm/smap.h
arch/x86/Kconfig +11 -0
index 8ec3a1a..5ce8694 100644
@@ -1487,6 +1487,17 @@ config ARCH_RANDOM
 	  If supported, this is a high bandwidth, cryptographically
 	  secure hardware random number generator.
 
+config X86_SMAP
+	def_bool y
+	prompt "Supervisor Mode Access Prevention" if EXPERT
+	---help---
+	  Supervisor Mode Access Prevention (SMAP) is a security
+	  feature in newer Intel processors.  There is a small
+	  performance cost if this enabled and turned on; there is
+	  also a small increase in the kernel size if this is enabled.
+
+	  If unsure, say Y.
+
 config EFI
 	bool "EFI runtime service support"
 	depends on ACPI
arch/x86/include/asm/smap.h new file +91 -0

91 lines not on this page · raw message

Signature · 1 line
1.7.6.5
#11 lore raw

[tip:x86/smap] x86, smap: Add a header file with macros for STAC/ CLAC

Commit-ID:  51ae4a2d775e1ee456282d7c60e49693d0a8555d
Gitweb:     http://git.kernel.org/tip/51ae4a2d775e1ee456282d7c60e49693d0a8555d
Author:     H. Peter Anvin <[email protected]>
AuthorDate: Fri, 21 Sep 2012 12:43:10 -0700
Committer:  H. Peter Anvin <[email protected]>
CommitDate: Fri, 21 Sep 2012 12:45:26 -0700

x86, smap: Add a header file with macros for STAC/CLAC

The STAC/CLAC instructions are only available with SMAP, but on the other hand they aren't needed if SMAP is not available, or before we start to run userspace, so construct them as alternatives which start out as noops and are enabled by the alternatives mechanism.

---
 arch/x86/Kconfig            |   11 +++++
 arch/x86/include/asm/smap.h |   91 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 102 insertions(+), 0 deletions(-)
arch/x86/Kconfig +11 -0
index 8ec3a1a..5ce8694 100644
@@ -1487,6 +1487,17 @@ config ARCH_RANDOM
 	  If supported, this is a high bandwidth, cryptographically
 	  secure hardware random number generator.
 
+config X86_SMAP
+	def_bool y
+	prompt "Supervisor Mode Access Prevention" if EXPERT
+	---help---
+	  Supervisor Mode Access Prevention (SMAP) is a security
+	  feature in newer Intel processors.  There is a small
+	  performance cost if this enabled and turned on; there is
+	  also a small increase in the kernel size if this is enabled.
+
+	  If unsure, say Y.
+
 config EFI
 	bool "EFI runtime service support"
 	depends on ACPI
arch/x86/include/asm/smap.h new file +91 -0

91 lines not on this page · raw message

#12 lore raw

PATCH 7/11 x86, uaccess: Merge prototypes for clear_user/__clear_user

In reply to H. Peter Anvin

From: "H. Peter Anvin" <[email protected]>

The prototypes for clear_user() and __clear_user() are identical in the 32- and 64-bit headers. No functionality change.

---
 arch/x86/include/asm/uaccess.h    |    3 +++
 arch/x86/include/asm/uaccess_32.h |    3 ---
 arch/x86/include/asm/uaccess_64.h |    3 ---
 3 files changed, 3 insertions(+), 6 deletions(-)
arch/x86/include/asm/uaccess.h +3 -0
index e1f3a17..2c7df3d 100644
@@ -569,6 +569,9 @@ strncpy_from_user(char *dst, const char __user *src, long count);
 extern __must_check long strlen_user(const char __user *str);
 extern __must_check long strnlen_user(const char __user *str, long n);
 
+unsigned long __must_check clear_user(void __user *mem, unsigned long len);
+unsigned long __must_check __clear_user(void __user *mem, unsigned long len);
+
 /*
  * movsl can be slow when source and dest are not both 8-byte aligned
  */
arch/x86/include/asm/uaccess_32.h +0 -3
index 576e39b..7f760a9 100644
@@ -213,7 +213,4 @@ static inline unsigned long __must_check copy_from_user(void *to,
 	return n;
 }
 
-unsigned long __must_check clear_user(void __user *mem, unsigned long len);
-unsigned long __must_check __clear_user(void __user *mem, unsigned long len);
-
 #endif /* _ASM_X86_UACCESS_32_H */
arch/x86/include/asm/uaccess_64.h +0 -3
index d8def8b..142810c 100644
@@ -217,9 +217,6 @@ int __copy_in_user(void __user *dst, const void __user *src, unsigned size)
 	}
 }
 
-__must_check unsigned long clear_user(void __user *mem, unsigned long len);
-__must_check unsigned long __clear_user(void __user *mem, unsigned long len);
-
 static __must_check __always_inline int
 __copy_from_user_inatomic(void *dst, const void __user *src, unsigned size)
 {
Signature · 1 line
1.7.6.5
#13 lore raw

[tip:x86/smap] x86, uaccess: Merge prototypes for clear_user/ __clear_user

Commit-ID:  a052858fabb376b695f2c125633daa6728e0f284
Gitweb:     http://git.kernel.org/tip/a052858fabb376b695f2c125633daa6728e0f284
Author:     H. Peter Anvin <[email protected]>
AuthorDate: Fri, 21 Sep 2012 12:43:11 -0700
Committer:  H. Peter Anvin <[email protected]>
CommitDate: Fri, 21 Sep 2012 12:45:26 -0700

x86, uaccess: Merge prototypes for clear_user/__clear_user

The prototypes for clear_user() and __clear_user() are identical in the 32- and 64-bit headers. No functionality change.

---
 arch/x86/include/asm/uaccess.h    |    3 +++
 arch/x86/include/asm/uaccess_32.h |    3 ---
 arch/x86/include/asm/uaccess_64.h |    3 ---
 3 files changed, 3 insertions(+), 6 deletions(-)
arch/x86/include/asm/uaccess.h +3 -0
index e1f3a17..2c7df3d 100644
@@ -569,6 +569,9 @@ strncpy_from_user(char *dst, const char __user *src, long count);
 extern __must_check long strlen_user(const char __user *str);
 extern __must_check long strnlen_user(const char __user *str, long n);
 
+unsigned long __must_check clear_user(void __user *mem, unsigned long len);
+unsigned long __must_check __clear_user(void __user *mem, unsigned long len);
+
 /*
  * movsl can be slow when source and dest are not both 8-byte aligned
  */
arch/x86/include/asm/uaccess_32.h +0 -3
index 576e39b..7f760a9 100644
@@ -213,7 +213,4 @@ static inline unsigned long __must_check copy_from_user(void *to,
 	return n;
 }
 
-unsigned long __must_check clear_user(void __user *mem, unsigned long len);
-unsigned long __must_check __clear_user(void __user *mem, unsigned long len);
-
 #endif /* _ASM_X86_UACCESS_32_H */
arch/x86/include/asm/uaccess_64.h +0 -3
index d8def8b..142810c 100644
@@ -217,9 +217,6 @@ int __copy_in_user(void __user *dst, const void __user *src, unsigned size)
 	}
 }
 
-__must_check unsigned long clear_user(void __user *mem, unsigned long len);
-__must_check unsigned long __clear_user(void __user *mem, unsigned long len);
-
 static __must_check __always_inline int
 __copy_from_user_inatomic(void *dst, const void __user *src, unsigned size)
 {
#14 lore raw

PATCH 8/11 x86, smap: Add STAC and CLAC instructions to control user space access

In reply to H. Peter Anvin

From: "H. Peter Anvin" <[email protected]>

When Supervisor Mode Access Prevention (SMAP) is enabled, access to userspace from the kernel is controlled by the AC flag. To make the performance of manipulating that flag acceptable, there are two new instructions, STAC and CLAC, to set and clear it.

This patch adds those instructions, via alternative(), when the SMAP feature is enabled. It also adds X86_EFLAGS_AC unconditionally to the SYSCALL entry mask; there is simply no reason to make that one conditional.

---
 arch/x86/ia32/ia32entry.S           |    6 ++++++
 arch/x86/include/asm/fpu-internal.h |   10 ++++++----
 arch/x86/include/asm/futex.h        |   19 +++++++++++++------
 arch/x86/include/asm/smap.h         |    4 ++--
 arch/x86/include/asm/uaccess.h      |   31 +++++++++++++++++++------------
 arch/x86/include/asm/xsave.h        |   10 ++++++----
 arch/x86/kernel/cpu/common.c        |    3 ++-
 arch/x86/kernel/entry_64.S          |   11 ++++++++++-
 arch/x86/lib/copy_user_64.S         |    7 +++++++
 arch/x86/lib/copy_user_nocache_64.S |    3 +++
 arch/x86/lib/getuser.S              |   10 ++++++++++
 arch/x86/lib/putuser.S              |    8 +++++++-
 arch/x86/lib/usercopy_32.c          |   13 ++++++++++++-
 arch/x86/lib/usercopy_64.c          |    3 +++
 14 files changed, 106 insertions(+), 32 deletions(-)
arch/x86/ia32/ia32entry.S +6 -0
index 20e5f7b..9c28950 100644
@@ -14,6 +14,7 @@
 #include <asm/segment.h>
 #include <asm/irqflags.h>
 #include <asm/asm.h>
+#include <asm/smap.h>
 #include <linux/linkage.h>
 #include <linux/err.h>
 
@@ -146,8 +147,10 @@ ENTRY(ia32_sysenter_target)
 	SAVE_ARGS 0,1,0
  	/* no need to do an access_ok check here because rbp has been
  	   32bit zero extended */ 
+	ASM_STAC
 1:	movl	(%rbp),%ebp
 	_ASM_EXTABLE(1b,ia32_badarg)
+	ASM_CLAC
 	orl     $TS_COMPAT,TI_status+THREAD_INFO(%rsp,RIP-ARGOFFSET)
 	testl   $_TIF_WORK_SYSCALL_ENTRY,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET)
 	CFI_REMEMBER_STATE
@@ -301,8 +304,10 @@ ENTRY(ia32_cstar_target)
 	/* no need to do an access_ok check here because r8 has been
 	   32bit zero extended */ 
 	/* hardware stack frame is complete now */	
+	ASM_STAC
 1:	movl	(%r8),%r9d
 	_ASM_EXTABLE(1b,ia32_badarg)
+	ASM_CLAC
 	orl     $TS_COMPAT,TI_status+THREAD_INFO(%rsp,RIP-ARGOFFSET)
 	testl   $_TIF_WORK_SYSCALL_ENTRY,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET)
 	CFI_REMEMBER_STATE
@@ -365,6 +370,7 @@ cstar_tracesys:
 END(ia32_cstar_target)
 				
 ia32_badarg:
+	ASM_CLAC
 	movq $-EFAULT,%rax
 	jmp ia32_sysret
 	CFI_ENDPROC
arch/x86/include/asm/fpu-internal.h +6 -4
index 75f4c6d..0fe1358 100644
@@ -126,8 +126,9 @@ static inline int fxsave_user(struct i387_fxsave_struct __user *fx)
 
 	/* See comment in fxsave() below. */
 #ifdef CONFIG_AS_FXSAVEQ
-	asm volatile("1:  fxsaveq %[fx]\n\t"
-		     "2:\n"
+	asm volatile(ASM_STAC "\n"
+		     "1:  fxsaveq %[fx]\n\t"
+		     "2: " ASM_CLAC "\n"
 		     ".section .fixup,\"ax\"\n"
 		     "3:  movl $-1,%[err]\n"
 		     "    jmp  2b\n"
@@ -136,8 +137,9 @@ static inline int fxsave_user(struct i387_fxsave_struct __user *fx)
 		     : [err] "=r" (err), [fx] "=m" (*fx)
 		     : "0" (0));
 #else
-	asm volatile("1:  rex64/fxsave (%[fx])\n\t"
-		     "2:\n"
+	asm volatile(ASM_STAC "\n"
+		     "1:  rex64/fxsave (%[fx])\n\t"
+		     "2: " ASM_CLAC "\n"
 		     ".section .fixup,\"ax\"\n"
 		     "3:  movl $-1,%[err]\n"
 		     "    jmp  2b\n"
arch/x86/include/asm/futex.h +13 -6
index 71ecbcb..f373046 100644
@@ -9,10 +9,13 @@
 #include <asm/asm.h>
 #include <asm/errno.h>
 #include <asm/processor.h>
+#include <asm/smap.h>
 
 #define __futex_atomic_op1(insn, ret, oldval, uaddr, oparg)	\
-	asm volatile("1:\t" insn "\n"				\
-		     "2:\t.section .fixup,\"ax\"\n"		\
+	asm volatile("\t" ASM_STAC "\n"				\
+		     "1:\t" insn "\n"				\
+		     "2:\t" ASM_CLAC "\n"			\
+		     "\t.section .fixup,\"ax\"\n"		\
 		     "3:\tmov\t%3, %1\n"			\
 		     "\tjmp\t2b\n"				\
 		     "\t.previous\n"				\
@@ -21,12 +24,14 @@
 		     : "i" (-EFAULT), "0" (oparg), "1" (0))
 
 #define __futex_atomic_op2(insn, ret, oldval, uaddr, oparg)	\
-	asm volatile("1:\tmovl	%2, %0\n"			\
+	asm volatile("\t" ASM_STAC "\n"				\
+		     "1:\tmovl	%2, %0\n"			\
 		     "\tmovl\t%0, %3\n"				\
 		     "\t" insn "\n"				\
 		     "2:\t" LOCK_PREFIX "cmpxchgl %3, %2\n"	\
 		     "\tjnz\t1b\n"				\
-		     "3:\t.section .fixup,\"ax\"\n"		\
+		     "3:\t" ASM_CLAC "\n"			\
+		     "\t.section .fixup,\"ax\"\n"		\
 		     "4:\tmov\t%5, %1\n"			\
 		     "\tjmp\t3b\n"				\
 		     "\t.previous\n"				\
@@ -122,8 +127,10 @@ static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
 	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
 		return -EFAULT;
 
-	asm volatile("1:\t" LOCK_PREFIX "cmpxchgl %4, %2\n"
-		     "2:\t.section .fixup, \"ax\"\n"
+	asm volatile("\t" ASM_STAC "\n"
+		     "1:\t" LOCK_PREFIX "cmpxchgl %4, %2\n"
+		     "2:\t" ASM_CLAC "\n"
+		     "\t.section .fixup, \"ax\"\n"
 		     "3:\tmov     %3, %0\n"
 		     "\tjmp     2b\n"
 		     "\t.previous\n"
arch/x86/include/asm/smap.h +2 -2
index 3989c24..8d3120f 100644
@@ -58,13 +58,13 @@
 
 #ifdef CONFIG_X86_SMAP
 
-static inline void clac(void)
+static __always_inline void clac(void)
 {
 	/* Note: a barrier is implicit in alternative() */
 	alternative(ASM_NOP3, __stringify(__ASM_CLAC), X86_FEATURE_SMAP);
 }
 
-static inline void stac(void)
+static __always_inline void stac(void)
 {
 	/* Note: a barrier is implicit in alternative() */
 	alternative(ASM_NOP3, __stringify(__ASM_STAC), X86_FEATURE_SMAP);
arch/x86/include/asm/uaccess.h +19 -12
index 2c7df3d..b92ece1 100644
@@ -9,6 +9,7 @@
 #include <linux/string.h>
 #include <asm/asm.h>
 #include <asm/page.h>
+#include <asm/smap.h>
 
 #define VERIFY_READ 0
 #define VERIFY_WRITE 1
@@ -192,9 +193,10 @@ extern int __get_user_bad(void);
 
 #ifdef CONFIG_X86_32
 #define __put_user_asm_u64(x, addr, err, errret)			\
-	asm volatile("1:	movl %%eax,0(%2)\n"			\
+	asm volatile(ASM_STAC "\n"					\
+		     "1:	movl %%eax,0(%2)\n"			\
 		     "2:	movl %%edx,4(%2)\n"			\
-		     "3:\n"						\
+		     "3: " ASM_CLAC "\n"				\
 		     ".section .fixup,\"ax\"\n"				\
 		     "4:	movl %3,%0\n"				\
 		     "	jmp 3b\n"					\
@@ -205,9 +207,10 @@ extern int __get_user_bad(void);
 		     : "A" (x), "r" (addr), "i" (errret), "0" (err))
 
 #define __put_user_asm_ex_u64(x, addr)					\
-	asm volatile("1:	movl %%eax,0(%1)\n"			\
+	asm volatile(ASM_STAC "\n"					\
+		     "1:	movl %%eax,0(%1)\n"			\
 		     "2:	movl %%edx,4(%1)\n"			\
-		     "3:\n"						\
+		     "3: " ASM_CLAC "\n"				\
 		     _ASM_EXTABLE_EX(1b, 2b)				\
 		     _ASM_EXTABLE_EX(2b, 3b)				\
 		     : : "A" (x), "r" (addr))
@@ -379,8 +382,9 @@ do {									\
 } while (0)
 
 #define __get_user_asm(x, addr, err, itype, rtype, ltype, errret)	\
-	asm volatile("1:	mov"itype" %2,%"rtype"1\n"		\
-		     "2:\n"						\
+	asm volatile(ASM_STAC "\n"					\
+		     "1:	mov"itype" %2,%"rtype"1\n"		\
+		     "2: " ASM_CLAC "\n"				\
 		     ".section .fixup,\"ax\"\n"				\
 		     "3:	mov %3,%0\n"				\
 		     "	xor"itype" %"rtype"1,%"rtype"1\n"		\
@@ -412,8 +416,9 @@ do {									\
 } while (0)
 
 #define __get_user_asm_ex(x, addr, itype, rtype, ltype)			\
-	asm volatile("1:	mov"itype" %1,%"rtype"0\n"		\
-		     "2:\n"						\
+	asm volatile(ASM_STAC "\n"					\
+		     "1:	mov"itype" %1,%"rtype"0\n"		\
+		     "2: " ASM_CLAC "\n"				\
 		     _ASM_EXTABLE_EX(1b, 2b)				\
 		     : ltype(x) : "m" (__m(addr)))
 
@@ -443,8 +448,9 @@ struct __large_struct { unsigned long buf[100]; };
  * aliasing issues.
  */
 #define __put_user_asm(x, addr, err, itype, rtype, ltype, errret)	\
-	asm volatile("1:	mov"itype" %"rtype"1,%2\n"		\
-		     "2:\n"						\
+	asm volatile(ASM_STAC "\n"					\
+		     "1:	mov"itype" %"rtype"1,%2\n"		\
+		     "2: " ASM_CLAC "\n"				\
 		     ".section .fixup,\"ax\"\n"				\
 		     "3:	mov %3,%0\n"				\
 		     "	jmp 2b\n"					\
@@ -454,8 +460,9 @@ struct __large_struct { unsigned long buf[100]; };
 		     : ltype(x), "m" (__m(addr)), "i" (errret), "0" (err))
 
 #define __put_user_asm_ex(x, addr, itype, rtype, ltype)			\
-	asm volatile("1:	mov"itype" %"rtype"0,%1\n"		\
-		     "2:\n"						\
+	asm volatile(ASM_STAC "\n"					\
+		     "1:	mov"itype" %"rtype"0,%1\n"		\
+		     "2: " ASM_CLAC "\n"				\
 		     _ASM_EXTABLE_EX(1b, 2b)				\
 		     : : ltype(x), "m" (__m(addr)))
 
arch/x86/include/asm/xsave.h +6 -4
index 8a1b6f9..2a923bd 100644
@@ -74,8 +74,9 @@ static inline int xsave_user(struct xsave_struct __user *buf)
 	if (unlikely(err))
 		return -EFAULT;
 
-	__asm__ __volatile__("1: .byte " REX_PREFIX "0x0f,0xae,0x27\n"
-			     "2:\n"
+	__asm__ __volatile__(ASM_STAC "\n"
+			     "1: .byte " REX_PREFIX "0x0f,0xae,0x27\n"
+			     "2: " ASM_CLAC "\n"
 			     ".section .fixup,\"ax\"\n"
 			     "3:  movl $-1,%[err]\n"
 			     "    jmp  2b\n"
@@ -97,8 +98,9 @@ static inline int xrestore_user(struct xsave_struct __user *buf, u64 mask)
 	u32 lmask = mask;
 	u32 hmask = mask >> 32;
 
-	__asm__ __volatile__("1: .byte " REX_PREFIX "0x0f,0xae,0x2f\n"
-			     "2:\n"
+	__asm__ __volatile__(ASM_STAC "\n"
+			     "1: .byte " REX_PREFIX "0x0f,0xae,0x2f\n"
+			     "2: " ASM_CLAC "\n"
 			     ".section .fixup,\"ax\"\n"
 			     "3:  movl $-1,%[err]\n"
 			     "    jmp  2b\n"
arch/x86/kernel/cpu/common.c +2 -1
index a5fbc3c..cd43e52 100644
@@ -1113,7 +1113,8 @@ void syscall_init(void)
 
 	/* Flags to clear on syscall */
 	wrmsrl(MSR_SYSCALL_MASK,
-	       X86_EFLAGS_TF|X86_EFLAGS_DF|X86_EFLAGS_IF|X86_EFLAGS_IOPL);
+	       X86_EFLAGS_TF|X86_EFLAGS_DF|X86_EFLAGS_IF|
+	       X86_EFLAGS_IOPL|X86_EFLAGS_AC);
 }
 
 unsigned long kernel_eflags;
arch/x86/kernel/entry_64.S +10 -1
index 69babd8..ce87e3d 100644
@@ -56,6 +56,7 @@
 #include <asm/ftrace.h>
 #include <asm/percpu.h>
 #include <asm/asm.h>
+#include <asm/smap.h>
 #include <linux/err.h>
 
 /* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this.  */
@@ -465,7 +466,8 @@ END(ret_from_fork)
  * System call entry. Up to 6 arguments in registers are supported.
  *
  * SYSCALL does not save anything on the stack and does not change the
- * stack pointer.
+ * stack pointer.  However, it does mask the flags register for us, so
+ * CLD and CLAC are not needed.
  */
 
 /*
@@ -884,6 +886,7 @@ END(interrupt)
 	 */
 	.p2align CONFIG_X86_L1_CACHE_SHIFT
 common_interrupt:
+	ASM_CLAC
 	XCPT_FRAME
 	addq $-0x80,(%rsp)		/* Adjust vector to [-256,-1] range */
 	interrupt do_IRQ
@@ -1023,6 +1026,7 @@ END(common_interrupt)
  */
 .macro apicinterrupt num sym do_sym
 ENTRY(\sym)
+	ASM_CLAC
 	INTR_FRAME
 	pushq_cfi $~(\num)
 .Lcommon_\sym:
@@ -1077,6 +1081,7 @@ apicinterrupt IRQ_WORK_VECTOR \
  */
 .macro zeroentry sym do_sym
 ENTRY(\sym)
+	ASM_CLAC
 	INTR_FRAME
 	PARAVIRT_ADJUST_EXCEPTION_FRAME
 	pushq_cfi $-1		/* ORIG_RAX: no syscall to restart */
@@ -1094,6 +1099,7 @@ END(\sym)
 
 .macro paranoidzeroentry sym do_sym
 ENTRY(\sym)
+	ASM_CLAC
 	INTR_FRAME
 	PARAVIRT_ADJUST_EXCEPTION_FRAME
 	pushq_cfi $-1		/* ORIG_RAX: no syscall to restart */
@@ -1112,6 +1118,7 @@ END(\sym)
 #define INIT_TSS_IST(x) PER_CPU_VAR(init_tss) + (TSS_ist + ((x) - 1) * 8)
 .macro paranoidzeroentry_ist sym do_sym ist
 ENTRY(\sym)
+	ASM_CLAC
 	INTR_FRAME
 	PARAVIRT_ADJUST_EXCEPTION_FRAME
 	pushq_cfi $-1		/* ORIG_RAX: no syscall to restart */
@@ -1131,6 +1138,7 @@ END(\sym)
 
 .macro errorentry sym do_sym
 ENTRY(\sym)
+	ASM_CLAC
 	XCPT_FRAME
 	PARAVIRT_ADJUST_EXCEPTION_FRAME
 	subq $ORIG_RAX-R15, %rsp
@@ -1149,6 +1157,7 @@ END(\sym)
 	/* error code is on the stack already */
 .macro paranoiderrorentry sym do_sym
 ENTRY(\sym)
+	ASM_CLAC
 	XCPT_FRAME
 	PARAVIRT_ADJUST_EXCEPTION_FRAME
 	subq $ORIG_RAX-R15, %rsp
arch/x86/lib/copy_user_64.S +7 -0
index 5b2995f..a30ca15 100644
@@ -17,6 +17,7 @@
 #include <asm/cpufeature.h>
 #include <asm/alternative-asm.h>
 #include <asm/asm.h>
+#include <asm/smap.h>
 
 /*
  * By placing feature2 after feature1 in altinstructions section, we logically
@@ -130,6 +131,7 @@ ENDPROC(bad_from_user)
  */
 ENTRY(copy_user_generic_unrolled)
 	CFI_STARTPROC
+	ASM_STAC
 	cmpl $8,%edx
 	jb 20f		/* less then 8 bytes, go to byte copy loop */
 	ALIGN_DESTINATION
@@ -177,6 +179,7 @@ ENTRY(copy_user_generic_unrolled)
 	decl %ecx
 	jnz 21b
 23:	xor %eax,%eax
+	ASM_CLAC
 	ret
 
 	.section .fixup,"ax"
@@ -232,6 +235,7 @@ ENDPROC(copy_user_generic_unrolled)
  */
 ENTRY(copy_user_generic_string)
 	CFI_STARTPROC
+	ASM_STAC
 	andl %edx,%edx
 	jz 4f
 	cmpl $8,%edx
@@ -246,6 +250,7 @@ ENTRY(copy_user_generic_string)
 3:	rep
 	movsb
 4:	xorl %eax,%eax
+	ASM_CLAC
 	ret
 
 	.section .fixup,"ax"
@@ -273,12 +278,14 @@ ENDPROC(copy_user_generic_string)
  */
 ENTRY(copy_user_enhanced_fast_string)
 	CFI_STARTPROC
+	ASM_STAC
 	andl %edx,%edx
 	jz 2f
 	movl %edx,%ecx
 1:	rep
 	movsb
 2:	xorl %eax,%eax
+	ASM_CLAC
 	ret
 
 	.section .fixup,"ax"
arch/x86/lib/copy_user_nocache_64.S +3 -0
index cacddc7..6a4f43c 100644
@@ -15,6 +15,7 @@
 #include <asm/asm-offsets.h>
 #include <asm/thread_info.h>
 #include <asm/asm.h>
+#include <asm/smap.h>
 
 	.macro ALIGN_DESTINATION
 #ifdef FIX_ALIGNMENT
@@ -48,6 +49,7 @@
  */
 ENTRY(__copy_user_nocache)
 	CFI_STARTPROC
+	ASM_STAC
 	cmpl $8,%edx
 	jb 20f		/* less then 8 bytes, go to byte copy loop */
 	ALIGN_DESTINATION
@@ -95,6 +97,7 @@ ENTRY(__copy_user_nocache)
 	decl %ecx
 	jnz 21b
 23:	xorl %eax,%eax
+	ASM_CLAC
 	sfence
 	ret
 
arch/x86/lib/getuser.S +10 -0
index b33b1fb..156b9c8 100644
@@ -33,6 +33,7 @@
 #include <asm/asm-offsets.h>
 #include <asm/thread_info.h>
 #include <asm/asm.h>
+#include <asm/smap.h>
 
 	.text
 ENTRY(__get_user_1)
@@ -40,8 +41,10 @@ ENTRY(__get_user_1)
 	GET_THREAD_INFO(%_ASM_DX)
 	cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
 	jae bad_get_user
+	ASM_STAC
 1:	movzb (%_ASM_AX),%edx
 	xor %eax,%eax
+	ASM_CLAC
 	ret
 	CFI_ENDPROC
 ENDPROC(__get_user_1)
@@ -53,8 +56,10 @@ ENTRY(__get_user_2)
 	GET_THREAD_INFO(%_ASM_DX)
 	cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
 	jae bad_get_user
+	ASM_STAC
 2:	movzwl -1(%_ASM_AX),%edx
 	xor %eax,%eax
+	ASM_CLAC
 	ret
 	CFI_ENDPROC
 ENDPROC(__get_user_2)
@@ -66,8 +71,10 @@ ENTRY(__get_user_4)
 	GET_THREAD_INFO(%_ASM_DX)
 	cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
 	jae bad_get_user
+	ASM_STAC
 3:	mov -3(%_ASM_AX),%edx
 	xor %eax,%eax
+	ASM_CLAC
 	ret
 	CFI_ENDPROC
 ENDPROC(__get_user_4)
@@ -80,8 +87,10 @@ ENTRY(__get_user_8)
 	GET_THREAD_INFO(%_ASM_DX)
 	cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
 	jae	bad_get_user
+	ASM_STAC
 4:	movq -7(%_ASM_AX),%_ASM_DX
 	xor %eax,%eax
+	ASM_CLAC
 	ret
 	CFI_ENDPROC
 ENDPROC(__get_user_8)
@@ -91,6 +100,7 @@ bad_get_user:
 	CFI_STARTPROC
 	xor %edx,%edx
 	mov $(-EFAULT),%_ASM_AX
+	ASM_CLAC
 	ret
 	CFI_ENDPROC
 END(bad_get_user)
arch/x86/lib/putuser.S +7 -1
index 7f951c8..fc6ba17 100644
@@ -15,6 +15,7 @@
 #include <asm/thread_info.h>
 #include <asm/errno.h>
 #include <asm/asm.h>
+#include <asm/smap.h>
 
 
 /*
@@ -31,7 +32,8 @@
 
 #define ENTER	CFI_STARTPROC ; \
 		GET_THREAD_INFO(%_ASM_BX)
-#define EXIT	ret ; \
+#define EXIT	ASM_CLAC ;	\
+		ret ;		\
 		CFI_ENDPROC
 
 .text
@@ -39,6 +41,7 @@ ENTRY(__put_user_1)
 	ENTER
 	cmp TI_addr_limit(%_ASM_BX),%_ASM_CX
 	jae bad_put_user
+	ASM_STAC
 1:	movb %al,(%_ASM_CX)
 	xor %eax,%eax
 	EXIT
@@ -50,6 +53,7 @@ ENTRY(__put_user_2)
 	sub $1,%_ASM_BX
 	cmp %_ASM_BX,%_ASM_CX
 	jae bad_put_user
+	ASM_STAC
 2:	movw %ax,(%_ASM_CX)
 	xor %eax,%eax
 	EXIT
@@ -61,6 +65,7 @@ ENTRY(__put_user_4)
 	sub $3,%_ASM_BX
 	cmp %_ASM_BX,%_ASM_CX
 	jae bad_put_user
+	ASM_STAC
 3:	movl %eax,(%_ASM_CX)
 	xor %eax,%eax
 	EXIT
@@ -72,6 +77,7 @@ ENTRY(__put_user_8)
 	sub $7,%_ASM_BX
 	cmp %_ASM_BX,%_ASM_CX
 	jae bad_put_user
+	ASM_STAC
 4:	mov %_ASM_AX,(%_ASM_CX)
 #ifdef CONFIG_X86_32
 5:	movl %edx,4(%_ASM_CX)
arch/x86/lib/usercopy_32.c +12 -1
index 1781b2f..98f6d6b6 100644
@@ -42,10 +42,11 @@ do {									\
 	int __d0;							\
 	might_fault();							\
 	__asm__ __volatile__(						\
+		ASM_STAC "\n"						\
 		"0:	rep; stosl\n"					\
 		"	movl %2,%0\n"					\
 		"1:	rep; stosb\n"					\
-		"2:\n"							\
+		"2: " ASM_CLAC "\n"					\
 		".section .fixup,\"ax\"\n"				\
 		"3:	lea 0(%2,%0,4),%0\n"				\
 		"	jmp 2b\n"					\
@@ -626,10 +627,12 @@ survive:
 		return n;
 	}
 #endif
+	stac();
 	if (movsl_is_ok(to, from, n))
 		__copy_user(to, from, n);
 	else
 		n = __copy_user_intel(to, from, n);
+	clac();
 	return n;
 }
 EXPORT_SYMBOL(__copy_to_user_ll);
@@ -637,10 +640,12 @@ EXPORT_SYMBOL(__copy_to_user_ll);
 unsigned long __copy_from_user_ll(void *to, const void __user *from,
 					unsigned long n)
 {
+	stac();
 	if (movsl_is_ok(to, from, n))
 		__copy_user_zeroing(to, from, n);
 	else
 		n = __copy_user_zeroing_intel(to, from, n);
+	clac();
 	return n;
 }
 EXPORT_SYMBOL(__copy_from_user_ll);
@@ -648,11 +653,13 @@ EXPORT_SYMBOL(__copy_from_user_ll);
 unsigned long __copy_from_user_ll_nozero(void *to, const void __user *from,
 					 unsigned long n)
 {
+	stac();
 	if (movsl_is_ok(to, from, n))
 		__copy_user(to, from, n);
 	else
 		n = __copy_user_intel((void __user *)to,
 				      (const void *)from, n);
+	clac();
 	return n;
 }
 EXPORT_SYMBOL(__copy_from_user_ll_nozero);
@@ -660,6 +667,7 @@ EXPORT_SYMBOL(__copy_from_user_ll_nozero);
 unsigned long __copy_from_user_ll_nocache(void *to, const void __user *from,
 					unsigned long n)
 {
+	stac();
 #ifdef CONFIG_X86_INTEL_USERCOPY
 	if (n > 64 && cpu_has_xmm2)
 		n = __copy_user_zeroing_intel_nocache(to, from, n);
@@ -668,6 +676,7 @@ unsigned long __copy_from_user_ll_nocache(void *to, const void __user *from,
 #else
 	__copy_user_zeroing(to, from, n);
 #endif
+	clac();
 	return n;
 }
 EXPORT_SYMBOL(__copy_from_user_ll_nocache);
@@ -675,6 +684,7 @@ EXPORT_SYMBOL(__copy_from_user_ll_nocache);
 unsigned long __copy_from_user_ll_nocache_nozero(void *to, const void __user *from,
 					unsigned long n)
 {
+	stac();
 #ifdef CONFIG_X86_INTEL_USERCOPY
 	if (n > 64 && cpu_has_xmm2)
 		n = __copy_user_intel_nocache(to, from, n);
@@ -683,6 +693,7 @@ unsigned long __copy_from_user_ll_nocache_nozero(void *to, const void __user *fr
 #else
 	__copy_user(to, from, n);
 #endif
+	clac();
 	return n;
 }
 EXPORT_SYMBOL(__copy_from_user_ll_nocache_nozero);
arch/x86/lib/usercopy_64.c +3 -0
index e5b130b..05928aa 100644
@@ -18,6 +18,7 @@ unsigned long __clear_user(void __user *addr, unsigned long size)
 	might_fault();
 	/* no memory constraint because it doesn't change any memory gcc knows
 	   about */
+	stac();
 	asm volatile(
 		"	testq  %[size8],%[size8]\n"
 		"	jz     4f\n"
@@ -40,6 +41,7 @@ unsigned long __clear_user(void __user *addr, unsigned long size)
 		: [size8] "=&c"(size), [dst] "=&D" (__d0)
 		: [size1] "r"(size & 7), "[size8]" (size / 8), "[dst]"(addr),
 		  [zero] "r" (0UL), [eight] "r" (8UL));
+	clac();
 	return size;
 }
 EXPORT_SYMBOL(__clear_user);
@@ -82,5 +84,6 @@ copy_user_handle_tail(char *to, char *from, unsigned len, unsigned zerorest)
 	for (c = 0, zero_len = len; zerorest && zero_len; --zero_len)
 		if (__put_user_nocheck(c, to++, sizeof(char)))
 			break;
+	clac();
 	return len;
 }
Signature · 1 line
1.7.6.5
#15 lore raw

[tip:x86/smap] x86, smap: Add STAC and CLAC instructions to control user space access

Commit-ID:  63bcff2a307b9bcc712a8251eb27df8b2e117967
Gitweb:     http://git.kernel.org/tip/63bcff2a307b9bcc712a8251eb27df8b2e117967
Author:     H. Peter Anvin <[email protected]>
AuthorDate: Fri, 21 Sep 2012 12:43:12 -0700
Committer:  H. Peter Anvin <[email protected]>
CommitDate: Fri, 21 Sep 2012 12:45:27 -0700

x86, smap: Add STAC and CLAC instructions to control user space access

When Supervisor Mode Access Prevention (SMAP) is enabled, access to userspace from the kernel is controlled by the AC flag. To make the performance of manipulating that flag acceptable, there are two new instructions, STAC and CLAC, to set and clear it.

This patch adds those instructions, via alternative(), when the SMAP feature is enabled. It also adds X86_EFLAGS_AC unconditionally to the SYSCALL entry mask; there is simply no reason to make that one conditional.

---
 arch/x86/ia32/ia32entry.S           |    6 ++++++
 arch/x86/include/asm/fpu-internal.h |   10 ++++++----
 arch/x86/include/asm/futex.h        |   19 +++++++++++++------
 arch/x86/include/asm/smap.h         |    4 ++--
 arch/x86/include/asm/uaccess.h      |   31 +++++++++++++++++++------------
 arch/x86/include/asm/xsave.h        |   10 ++++++----
 arch/x86/kernel/cpu/common.c        |    3 ++-
 arch/x86/kernel/entry_64.S          |   11 ++++++++++-
 arch/x86/lib/copy_user_64.S         |    7 +++++++
 arch/x86/lib/copy_user_nocache_64.S |    3 +++
 arch/x86/lib/getuser.S              |   10 ++++++++++
 arch/x86/lib/putuser.S              |    8 +++++++-
 arch/x86/lib/usercopy_32.c          |   13 ++++++++++++-
 arch/x86/lib/usercopy_64.c          |    3 +++
 14 files changed, 106 insertions(+), 32 deletions(-)
arch/x86/ia32/ia32entry.S +6 -0
index 20e5f7b..9c28950 100644
@@ -14,6 +14,7 @@
 #include <asm/segment.h>
 #include <asm/irqflags.h>
 #include <asm/asm.h>
+#include <asm/smap.h>
 #include <linux/linkage.h>
 #include <linux/err.h>
 
@@ -146,8 +147,10 @@ ENTRY(ia32_sysenter_target)
 	SAVE_ARGS 0,1,0
  	/* no need to do an access_ok check here because rbp has been
  	   32bit zero extended */ 
+	ASM_STAC
 1:	movl	(%rbp),%ebp
 	_ASM_EXTABLE(1b,ia32_badarg)
+	ASM_CLAC
 	orl     $TS_COMPAT,TI_status+THREAD_INFO(%rsp,RIP-ARGOFFSET)
 	testl   $_TIF_WORK_SYSCALL_ENTRY,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET)
 	CFI_REMEMBER_STATE
@@ -301,8 +304,10 @@ ENTRY(ia32_cstar_target)
 	/* no need to do an access_ok check here because r8 has been
 	   32bit zero extended */ 
 	/* hardware stack frame is complete now */	
+	ASM_STAC
 1:	movl	(%r8),%r9d
 	_ASM_EXTABLE(1b,ia32_badarg)
+	ASM_CLAC
 	orl     $TS_COMPAT,TI_status+THREAD_INFO(%rsp,RIP-ARGOFFSET)
 	testl   $_TIF_WORK_SYSCALL_ENTRY,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET)
 	CFI_REMEMBER_STATE
@@ -365,6 +370,7 @@ cstar_tracesys:
 END(ia32_cstar_target)
 				
 ia32_badarg:
+	ASM_CLAC
 	movq $-EFAULT,%rax
 	jmp ia32_sysret
 	CFI_ENDPROC
arch/x86/include/asm/fpu-internal.h +6 -4
index 75f4c6d..0fe1358 100644
@@ -126,8 +126,9 @@ static inline int fxsave_user(struct i387_fxsave_struct __user *fx)
 
 	/* See comment in fxsave() below. */
 #ifdef CONFIG_AS_FXSAVEQ
-	asm volatile("1:  fxsaveq %[fx]\n\t"
-		     "2:\n"
+	asm volatile(ASM_STAC "\n"
+		     "1:  fxsaveq %[fx]\n\t"
+		     "2: " ASM_CLAC "\n"
 		     ".section .fixup,\"ax\"\n"
 		     "3:  movl $-1,%[err]\n"
 		     "    jmp  2b\n"
@@ -136,8 +137,9 @@ static inline int fxsave_user(struct i387_fxsave_struct __user *fx)
 		     : [err] "=r" (err), [fx] "=m" (*fx)
 		     : "0" (0));
 #else
-	asm volatile("1:  rex64/fxsave (%[fx])\n\t"
-		     "2:\n"
+	asm volatile(ASM_STAC "\n"
+		     "1:  rex64/fxsave (%[fx])\n\t"
+		     "2: " ASM_CLAC "\n"
 		     ".section .fixup,\"ax\"\n"
 		     "3:  movl $-1,%[err]\n"
 		     "    jmp  2b\n"
arch/x86/include/asm/futex.h +13 -6
index 71ecbcb..f373046 100644
@@ -9,10 +9,13 @@
 #include <asm/asm.h>
 #include <asm/errno.h>
 #include <asm/processor.h>
+#include <asm/smap.h>
 
 #define __futex_atomic_op1(insn, ret, oldval, uaddr, oparg)	\
-	asm volatile("1:\t" insn "\n"				\
-		     "2:\t.section .fixup,\"ax\"\n"		\
+	asm volatile("\t" ASM_STAC "\n"				\
+		     "1:\t" insn "\n"				\
+		     "2:\t" ASM_CLAC "\n"			\
+		     "\t.section .fixup,\"ax\"\n"		\
 		     "3:\tmov\t%3, %1\n"			\
 		     "\tjmp\t2b\n"				\
 		     "\t.previous\n"				\
@@ -21,12 +24,14 @@
 		     : "i" (-EFAULT), "0" (oparg), "1" (0))
 
 #define __futex_atomic_op2(insn, ret, oldval, uaddr, oparg)	\
-	asm volatile("1:\tmovl	%2, %0\n"			\
+	asm volatile("\t" ASM_STAC "\n"				\
+		     "1:\tmovl	%2, %0\n"			\
 		     "\tmovl\t%0, %3\n"				\
 		     "\t" insn "\n"				\
 		     "2:\t" LOCK_PREFIX "cmpxchgl %3, %2\n"	\
 		     "\tjnz\t1b\n"				\
-		     "3:\t.section .fixup,\"ax\"\n"		\
+		     "3:\t" ASM_CLAC "\n"			\
+		     "\t.section .fixup,\"ax\"\n"		\
 		     "4:\tmov\t%5, %1\n"			\
 		     "\tjmp\t3b\n"				\
 		     "\t.previous\n"				\
@@ -122,8 +127,10 @@ static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
 	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
 		return -EFAULT;
 
-	asm volatile("1:\t" LOCK_PREFIX "cmpxchgl %4, %2\n"
-		     "2:\t.section .fixup, \"ax\"\n"
+	asm volatile("\t" ASM_STAC "\n"
+		     "1:\t" LOCK_PREFIX "cmpxchgl %4, %2\n"
+		     "2:\t" ASM_CLAC "\n"
+		     "\t.section .fixup, \"ax\"\n"
 		     "3:\tmov     %3, %0\n"
 		     "\tjmp     2b\n"
 		     "\t.previous\n"
arch/x86/include/asm/smap.h +2 -2
index 3989c24..8d3120f 100644
@@ -58,13 +58,13 @@
 
 #ifdef CONFIG_X86_SMAP
 
-static inline void clac(void)
+static __always_inline void clac(void)
 {
 	/* Note: a barrier is implicit in alternative() */
 	alternative(ASM_NOP3, __stringify(__ASM_CLAC), X86_FEATURE_SMAP);
 }
 
-static inline void stac(void)
+static __always_inline void stac(void)
 {
 	/* Note: a barrier is implicit in alternative() */
 	alternative(ASM_NOP3, __stringify(__ASM_STAC), X86_FEATURE_SMAP);
arch/x86/include/asm/uaccess.h +19 -12
index 2c7df3d..b92ece1 100644
@@ -9,6 +9,7 @@
 #include <linux/string.h>
 #include <asm/asm.h>
 #include <asm/page.h>
+#include <asm/smap.h>
 
 #define VERIFY_READ 0
 #define VERIFY_WRITE 1
@@ -192,9 +193,10 @@ extern int __get_user_bad(void);
 
 #ifdef CONFIG_X86_32
 #define __put_user_asm_u64(x, addr, err, errret)			\
-	asm volatile("1:	movl %%eax,0(%2)\n"			\
+	asm volatile(ASM_STAC "\n"					\
+		     "1:	movl %%eax,0(%2)\n"			\
 		     "2:	movl %%edx,4(%2)\n"			\
-		     "3:\n"						\
+		     "3: " ASM_CLAC "\n"				\
 		     ".section .fixup,\"ax\"\n"				\
 		     "4:	movl %3,%0\n"				\
 		     "	jmp 3b\n"					\
@@ -205,9 +207,10 @@ extern int __get_user_bad(void);
 		     : "A" (x), "r" (addr), "i" (errret), "0" (err))
 
 #define __put_user_asm_ex_u64(x, addr)					\
-	asm volatile("1:	movl %%eax,0(%1)\n"			\
+	asm volatile(ASM_STAC "\n"					\
+		     "1:	movl %%eax,0(%1)\n"			\
 		     "2:	movl %%edx,4(%1)\n"			\
-		     "3:\n"						\
+		     "3: " ASM_CLAC "\n"				\
 		     _ASM_EXTABLE_EX(1b, 2b)				\
 		     _ASM_EXTABLE_EX(2b, 3b)				\
 		     : : "A" (x), "r" (addr))
@@ -379,8 +382,9 @@ do {									\
 } while (0)
 
 #define __get_user_asm(x, addr, err, itype, rtype, ltype, errret)	\
-	asm volatile("1:	mov"itype" %2,%"rtype"1\n"		\
-		     "2:\n"						\
+	asm volatile(ASM_STAC "\n"					\
+		     "1:	mov"itype" %2,%"rtype"1\n"		\
+		     "2: " ASM_CLAC "\n"				\
 		     ".section .fixup,\"ax\"\n"				\
 		     "3:	mov %3,%0\n"				\
 		     "	xor"itype" %"rtype"1,%"rtype"1\n"		\
@@ -412,8 +416,9 @@ do {									\
 } while (0)
 
 #define __get_user_asm_ex(x, addr, itype, rtype, ltype)			\
-	asm volatile("1:	mov"itype" %1,%"rtype"0\n"		\
-		     "2:\n"						\
+	asm volatile(ASM_STAC "\n"					\
+		     "1:	mov"itype" %1,%"rtype"0\n"		\
+		     "2: " ASM_CLAC "\n"				\
 		     _ASM_EXTABLE_EX(1b, 2b)				\
 		     : ltype(x) : "m" (__m(addr)))
 
@@ -443,8 +448,9 @@ struct __large_struct { unsigned long buf[100]; };
  * aliasing issues.
  */
 #define __put_user_asm(x, addr, err, itype, rtype, ltype, errret)	\
-	asm volatile("1:	mov"itype" %"rtype"1,%2\n"		\
-		     "2:\n"						\
+	asm volatile(ASM_STAC "\n"					\
+		     "1:	mov"itype" %"rtype"1,%2\n"		\
+		     "2: " ASM_CLAC "\n"				\
 		     ".section .fixup,\"ax\"\n"				\
 		     "3:	mov %3,%0\n"				\
 		     "	jmp 2b\n"					\
@@ -454,8 +460,9 @@ struct __large_struct { unsigned long buf[100]; };
 		     : ltype(x), "m" (__m(addr)), "i" (errret), "0" (err))
 
 #define __put_user_asm_ex(x, addr, itype, rtype, ltype)			\
-	asm volatile("1:	mov"itype" %"rtype"0,%1\n"		\
-		     "2:\n"						\
+	asm volatile(ASM_STAC "\n"					\
+		     "1:	mov"itype" %"rtype"0,%1\n"		\
+		     "2: " ASM_CLAC "\n"				\
 		     _ASM_EXTABLE_EX(1b, 2b)				\
 		     : : ltype(x), "m" (__m(addr)))
 
arch/x86/include/asm/xsave.h +6 -4
index 8a1b6f9..2a923bd 100644
@@ -74,8 +74,9 @@ static inline int xsave_user(struct xsave_struct __user *buf)
 	if (unlikely(err))
 		return -EFAULT;
 
-	__asm__ __volatile__("1: .byte " REX_PREFIX "0x0f,0xae,0x27\n"
-			     "2:\n"
+	__asm__ __volatile__(ASM_STAC "\n"
+			     "1: .byte " REX_PREFIX "0x0f,0xae,0x27\n"
+			     "2: " ASM_CLAC "\n"
 			     ".section .fixup,\"ax\"\n"
 			     "3:  movl $-1,%[err]\n"
 			     "    jmp  2b\n"
@@ -97,8 +98,9 @@ static inline int xrestore_user(struct xsave_struct __user *buf, u64 mask)
 	u32 lmask = mask;
 	u32 hmask = mask >> 32;
 
-	__asm__ __volatile__("1: .byte " REX_PREFIX "0x0f,0xae,0x2f\n"
-			     "2:\n"
+	__asm__ __volatile__(ASM_STAC "\n"
+			     "1: .byte " REX_PREFIX "0x0f,0xae,0x2f\n"
+			     "2: " ASM_CLAC "\n"
 			     ".section .fixup,\"ax\"\n"
 			     "3:  movl $-1,%[err]\n"
 			     "    jmp  2b\n"
arch/x86/kernel/cpu/common.c +2 -1
index a5fbc3c..cd43e52 100644
@@ -1113,7 +1113,8 @@ void syscall_init(void)
 
 	/* Flags to clear on syscall */
 	wrmsrl(MSR_SYSCALL_MASK,
-	       X86_EFLAGS_TF|X86_EFLAGS_DF|X86_EFLAGS_IF|X86_EFLAGS_IOPL);
+	       X86_EFLAGS_TF|X86_EFLAGS_DF|X86_EFLAGS_IF|
+	       X86_EFLAGS_IOPL|X86_EFLAGS_AC);
 }
 
 unsigned long kernel_eflags;
arch/x86/kernel/entry_64.S +10 -1
index 69babd8..ce87e3d 100644
@@ -56,6 +56,7 @@
 #include <asm/ftrace.h>
 #include <asm/percpu.h>
 #include <asm/asm.h>
+#include <asm/smap.h>
 #include <linux/err.h>
 
 /* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this.  */
@@ -465,7 +466,8 @@ END(ret_from_fork)
  * System call entry. Up to 6 arguments in registers are supported.
  *
  * SYSCALL does not save anything on the stack and does not change the
- * stack pointer.
+ * stack pointer.  However, it does mask the flags register for us, so
+ * CLD and CLAC are not needed.
  */
 
 /*
@@ -884,6 +886,7 @@ END(interrupt)
 	 */
 	.p2align CONFIG_X86_L1_CACHE_SHIFT
 common_interrupt:
+	ASM_CLAC
 	XCPT_FRAME
 	addq $-0x80,(%rsp)		/* Adjust vector to [-256,-1] range */
 	interrupt do_IRQ
@@ -1023,6 +1026,7 @@ END(common_interrupt)
  */
 .macro apicinterrupt num sym do_sym
 ENTRY(\sym)
+	ASM_CLAC
 	INTR_FRAME
 	pushq_cfi $~(\num)
 .Lcommon_\sym:
@@ -1077,6 +1081,7 @@ apicinterrupt IRQ_WORK_VECTOR \
  */
 .macro zeroentry sym do_sym
 ENTRY(\sym)
+	ASM_CLAC
 	INTR_FRAME
 	PARAVIRT_ADJUST_EXCEPTION_FRAME
 	pushq_cfi $-1		/* ORIG_RAX: no syscall to restart */
@@ -1094,6 +1099,7 @@ END(\sym)
 
 .macro paranoidzeroentry sym do_sym
 ENTRY(\sym)
+	ASM_CLAC
 	INTR_FRAME
 	PARAVIRT_ADJUST_EXCEPTION_FRAME
 	pushq_cfi $-1		/* ORIG_RAX: no syscall to restart */
@@ -1112,6 +1118,7 @@ END(\sym)
 #define INIT_TSS_IST(x) PER_CPU_VAR(init_tss) + (TSS_ist + ((x) - 1) * 8)
 .macro paranoidzeroentry_ist sym do_sym ist
 ENTRY(\sym)
+	ASM_CLAC
 	INTR_FRAME
 	PARAVIRT_ADJUST_EXCEPTION_FRAME
 	pushq_cfi $-1		/* ORIG_RAX: no syscall to restart */
@@ -1131,6 +1138,7 @@ END(\sym)
 
 .macro errorentry sym do_sym
 ENTRY(\sym)
+	ASM_CLAC
 	XCPT_FRAME
 	PARAVIRT_ADJUST_EXCEPTION_FRAME
 	subq $ORIG_RAX-R15, %rsp
@@ -1149,6 +1157,7 @@ END(\sym)
 	/* error code is on the stack already */
 .macro paranoiderrorentry sym do_sym
 ENTRY(\sym)
+	ASM_CLAC
 	XCPT_FRAME
 	PARAVIRT_ADJUST_EXCEPTION_FRAME
 	subq $ORIG_RAX-R15, %rsp
arch/x86/lib/copy_user_64.S +7 -0
index 5b2995f..a30ca15 100644
@@ -17,6 +17,7 @@
 #include <asm/cpufeature.h>
 #include <asm/alternative-asm.h>
 #include <asm/asm.h>
+#include <asm/smap.h>
 
 /*
  * By placing feature2 after feature1 in altinstructions section, we logically
@@ -130,6 +131,7 @@ ENDPROC(bad_from_user)
  */
 ENTRY(copy_user_generic_unrolled)
 	CFI_STARTPROC
+	ASM_STAC
 	cmpl $8,%edx
 	jb 20f		/* less then 8 bytes, go to byte copy loop */
 	ALIGN_DESTINATION
@@ -177,6 +179,7 @@ ENTRY(copy_user_generic_unrolled)
 	decl %ecx
 	jnz 21b
 23:	xor %eax,%eax
+	ASM_CLAC
 	ret
 
 	.section .fixup,"ax"
@@ -232,6 +235,7 @@ ENDPROC(copy_user_generic_unrolled)
  */
 ENTRY(copy_user_generic_string)
 	CFI_STARTPROC
+	ASM_STAC
 	andl %edx,%edx
 	jz 4f
 	cmpl $8,%edx
@@ -246,6 +250,7 @@ ENTRY(copy_user_generic_string)
 3:	rep
 	movsb
 4:	xorl %eax,%eax
+	ASM_CLAC
 	ret
 
 	.section .fixup,"ax"
@@ -273,12 +278,14 @@ ENDPROC(copy_user_generic_string)
  */
 ENTRY(copy_user_enhanced_fast_string)
 	CFI_STARTPROC
+	ASM_STAC
 	andl %edx,%edx
 	jz 2f
 	movl %edx,%ecx
 1:	rep
 	movsb
 2:	xorl %eax,%eax
+	ASM_CLAC
 	ret
 
 	.section .fixup,"ax"
arch/x86/lib/copy_user_nocache_64.S +3 -0
index cacddc7..6a4f43c 100644
@@ -15,6 +15,7 @@
 #include <asm/asm-offsets.h>
 #include <asm/thread_info.h>
 #include <asm/asm.h>
+#include <asm/smap.h>
 
 	.macro ALIGN_DESTINATION
 #ifdef FIX_ALIGNMENT
@@ -48,6 +49,7 @@
  */
 ENTRY(__copy_user_nocache)
 	CFI_STARTPROC
+	ASM_STAC
 	cmpl $8,%edx
 	jb 20f		/* less then 8 bytes, go to byte copy loop */
 	ALIGN_DESTINATION
@@ -95,6 +97,7 @@ ENTRY(__copy_user_nocache)
 	decl %ecx
 	jnz 21b
 23:	xorl %eax,%eax
+	ASM_CLAC
 	sfence
 	ret
 
arch/x86/lib/getuser.S +10 -0
index b33b1fb..156b9c8 100644
@@ -33,6 +33,7 @@
 #include <asm/asm-offsets.h>
 #include <asm/thread_info.h>
 #include <asm/asm.h>
+#include <asm/smap.h>
 
 	.text
 ENTRY(__get_user_1)
@@ -40,8 +41,10 @@ ENTRY(__get_user_1)
 	GET_THREAD_INFO(%_ASM_DX)
 	cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
 	jae bad_get_user
+	ASM_STAC
 1:	movzb (%_ASM_AX),%edx
 	xor %eax,%eax
+	ASM_CLAC
 	ret
 	CFI_ENDPROC
 ENDPROC(__get_user_1)
@@ -53,8 +56,10 @@ ENTRY(__get_user_2)
 	GET_THREAD_INFO(%_ASM_DX)
 	cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
 	jae bad_get_user
+	ASM_STAC
 2:	movzwl -1(%_ASM_AX),%edx
 	xor %eax,%eax
+	ASM_CLAC
 	ret
 	CFI_ENDPROC
 ENDPROC(__get_user_2)
@@ -66,8 +71,10 @@ ENTRY(__get_user_4)
 	GET_THREAD_INFO(%_ASM_DX)
 	cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
 	jae bad_get_user
+	ASM_STAC
 3:	mov -3(%_ASM_AX),%edx
 	xor %eax,%eax
+	ASM_CLAC
 	ret
 	CFI_ENDPROC
 ENDPROC(__get_user_4)
@@ -80,8 +87,10 @@ ENTRY(__get_user_8)
 	GET_THREAD_INFO(%_ASM_DX)
 	cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
 	jae	bad_get_user
+	ASM_STAC
 4:	movq -7(%_ASM_AX),%_ASM_DX
 	xor %eax,%eax
+	ASM_CLAC
 	ret
 	CFI_ENDPROC
 ENDPROC(__get_user_8)
@@ -91,6 +100,7 @@ bad_get_user:
 	CFI_STARTPROC
 	xor %edx,%edx
 	mov $(-EFAULT),%_ASM_AX
+	ASM_CLAC
 	ret
 	CFI_ENDPROC
 END(bad_get_user)
arch/x86/lib/putuser.S +7 -1
index 7f951c8..fc6ba17 100644
@@ -15,6 +15,7 @@
 #include <asm/thread_info.h>
 #include <asm/errno.h>
 #include <asm/asm.h>
+#include <asm/smap.h>
 
 
 /*
@@ -31,7 +32,8 @@
 
 #define ENTER	CFI_STARTPROC ; \
 		GET_THREAD_INFO(%_ASM_BX)
-#define EXIT	ret ; \
+#define EXIT	ASM_CLAC ;	\
+		ret ;		\
 		CFI_ENDPROC
 
 .text
@@ -39,6 +41,7 @@ ENTRY(__put_user_1)
 	ENTER
 	cmp TI_addr_limit(%_ASM_BX),%_ASM_CX
 	jae bad_put_user
+	ASM_STAC
 1:	movb %al,(%_ASM_CX)
 	xor %eax,%eax
 	EXIT
@@ -50,6 +53,7 @@ ENTRY(__put_user_2)
 	sub $1,%_ASM_BX
 	cmp %_ASM_BX,%_ASM_CX
 	jae bad_put_user
+	ASM_STAC
 2:	movw %ax,(%_ASM_CX)
 	xor %eax,%eax
 	EXIT
@@ -61,6 +65,7 @@ ENTRY(__put_user_4)
 	sub $3,%_ASM_BX
 	cmp %_ASM_BX,%_ASM_CX
 	jae bad_put_user
+	ASM_STAC
 3:	movl %eax,(%_ASM_CX)
 	xor %eax,%eax
 	EXIT
@@ -72,6 +77,7 @@ ENTRY(__put_user_8)
 	sub $7,%_ASM_BX
 	cmp %_ASM_BX,%_ASM_CX
 	jae bad_put_user
+	ASM_STAC
 4:	mov %_ASM_AX,(%_ASM_CX)
 #ifdef CONFIG_X86_32
 5:	movl %edx,4(%_ASM_CX)
arch/x86/lib/usercopy_32.c +12 -1
index 1781b2f..98f6d6b6 100644
@@ -42,10 +42,11 @@ do {									\
 	int __d0;							\
 	might_fault();							\
 	__asm__ __volatile__(						\
+		ASM_STAC "\n"						\
 		"0:	rep; stosl\n"					\
 		"	movl %2,%0\n"					\
 		"1:	rep; stosb\n"					\
-		"2:\n"							\
+		"2: " ASM_CLAC "\n"					\
 		".section .fixup,\"ax\"\n"				\
 		"3:	lea 0(%2,%0,4),%0\n"				\
 		"	jmp 2b\n"					\
@@ -626,10 +627,12 @@ survive:
 		return n;
 	}
 #endif
+	stac();
 	if (movsl_is_ok(to, from, n))
 		__copy_user(to, from, n);
 	else
 		n = __copy_user_intel(to, from, n);
+	clac();
 	return n;
 }
 EXPORT_SYMBOL(__copy_to_user_ll);
@@ -637,10 +640,12 @@ EXPORT_SYMBOL(__copy_to_user_ll);
 unsigned long __copy_from_user_ll(void *to, const void __user *from,
 					unsigned long n)
 {
+	stac();
 	if (movsl_is_ok(to, from, n))
 		__copy_user_zeroing(to, from, n);
 	else
 		n = __copy_user_zeroing_intel(to, from, n);
+	clac();
 	return n;
 }
 EXPORT_SYMBOL(__copy_from_user_ll);
@@ -648,11 +653,13 @@ EXPORT_SYMBOL(__copy_from_user_ll);
 unsigned long __copy_from_user_ll_nozero(void *to, const void __user *from,
 					 unsigned long n)
 {
+	stac();
 	if (movsl_is_ok(to, from, n))
 		__copy_user(to, from, n);
 	else
 		n = __copy_user_intel((void __user *)to,
 				      (const void *)from, n);
+	clac();
 	return n;
 }
 EXPORT_SYMBOL(__copy_from_user_ll_nozero);
@@ -660,6 +667,7 @@ EXPORT_SYMBOL(__copy_from_user_ll_nozero);
 unsigned long __copy_from_user_ll_nocache(void *to, const void __user *from,
 					unsigned long n)
 {
+	stac();
 #ifdef CONFIG_X86_INTEL_USERCOPY
 	if (n > 64 && cpu_has_xmm2)
 		n = __copy_user_zeroing_intel_nocache(to, from, n);
@@ -668,6 +676,7 @@ unsigned long __copy_from_user_ll_nocache(void *to, const void __user *from,
 #else
 	__copy_user_zeroing(to, from, n);
 #endif
+	clac();
 	return n;
 }
 EXPORT_SYMBOL(__copy_from_user_ll_nocache);
@@ -675,6 +684,7 @@ EXPORT_SYMBOL(__copy_from_user_ll_nocache);
 unsigned long __copy_from_user_ll_nocache_nozero(void *to, const void __user *from,
 					unsigned long n)
 {
+	stac();
 #ifdef CONFIG_X86_INTEL_USERCOPY
 	if (n > 64 && cpu_has_xmm2)
 		n = __copy_user_intel_nocache(to, from, n);
@@ -683,6 +693,7 @@ unsigned long __copy_from_user_ll_nocache_nozero(void *to, const void __user *fr
 #else
 	__copy_user(to, from, n);
 #endif
+	clac();
 	return n;
 }
 EXPORT_SYMBOL(__copy_from_user_ll_nocache_nozero);
arch/x86/lib/usercopy_64.c +3 -0
index e5b130b..05928aa 100644
@@ -18,6 +18,7 @@ unsigned long __clear_user(void __user *addr, unsigned long size)
 	might_fault();
 	/* no memory constraint because it doesn't change any memory gcc knows
 	   about */
+	stac();
 	asm volatile(
 		"	testq  %[size8],%[size8]\n"
 		"	jz     4f\n"
@@ -40,6 +41,7 @@ unsigned long __clear_user(void __user *addr, unsigned long size)
 		: [size8] "=&c"(size), [dst] "=&D" (__d0)
 		: [size1] "r"(size & 7), "[size8]" (size / 8), "[dst]"(addr),
 		  [zero] "r" (0UL), [eight] "r" (8UL));
+	clac();
 	return size;
 }
 EXPORT_SYMBOL(__clear_user);
@@ -82,5 +84,6 @@ copy_user_handle_tail(char *to, char *from, unsigned len, unsigned zerorest)
 	for (c = 0, zero_len = len; zerorest && zero_len; --zero_len)
 		if (__put_user_nocheck(c, to++, sizeof(char)))
 			break;
+	clac();
 	return len;
 }
#16 lore raw

[tip:x86/smap] x86-32, smap: Add STAC/ CLAC instructions to 32-bit kernel entry

In reply to H. Peter Anvin
Commit-ID:  e59d1b0a24199db01978e6c1e89859eda93ce683
Gitweb:     http://git.kernel.org/tip/e59d1b0a24199db01978e6c1e89859eda93ce683
Author:     H. Peter Anvin <[email protected]>
AuthorDate: Fri, 21 Sep 2012 13:58:10 -0700
Committer:  H. Peter Anvin <[email protected]>
CommitDate: Fri, 21 Sep 2012 14:04:27 -0700

x86-32, smap: Add STAC/CLAC instructions to 32-bit kernel entry

The changes to entry_32.S got missed in checkin:

63bcff2a x86, smap: Add STAC and CLAC instructions to control user space access

The resulting kernel was largely functional but SMAP protection could have been bypassed.

---
 arch/x86/kernel/entry_32.S |   26 ++++++++++++++++++++++++++
 1 files changed, 26 insertions(+), 0 deletions(-)
arch/x86/kernel/entry_32.S +26 -0
index 623f288..9ebbeca 100644
@@ -57,6 +57,7 @@
 #include <asm/cpufeature.h>
 #include <asm/alternative-asm.h>
 #include <asm/asm.h>
+#include <asm/smap.h>
 
 /* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this.  */
 #include <linux/elf-em.h>
@@ -407,7 +408,9 @@ sysenter_past_esp:
  */
 	cmpl $__PAGE_OFFSET-3,%ebp
 	jae syscall_fault
+	ASM_STAC
 1:	movl (%ebp),%ebp
+	ASM_CLAC
 	movl %ebp,PT_EBP(%esp)
 	_ASM_EXTABLE(1b,syscall_fault)
 
@@ -488,6 +491,7 @@ ENDPROC(ia32_sysenter_target)
 	# system call handler stub
 ENTRY(system_call)
 	RING0_INT_FRAME			# can't unwind into user space anyway
+	ASM_CLAC
 	pushl_cfi %eax			# save orig_eax
 	SAVE_ALL
 	GET_THREAD_INFO(%ebp)
@@ -670,6 +674,7 @@ END(syscall_exit_work)
 
 	RING0_INT_FRAME			# can't unwind into user space anyway
 syscall_fault:
+	ASM_CLAC
 	GET_THREAD_INFO(%ebp)
 	movl $-EFAULT,PT_EAX(%esp)
 	jmp resume_userspace
@@ -825,6 +830,7 @@ END(interrupt)
  */
 	.p2align CONFIG_X86_L1_CACHE_SHIFT
 common_interrupt:
+	ASM_CLAC
 	addl $-0x80,(%esp)	/* Adjust vector into the [-256,-1] range */
 	SAVE_ALL
 	TRACE_IRQS_OFF
@@ -841,6 +847,7 @@ ENDPROC(common_interrupt)
 #define BUILD_INTERRUPT3(name, nr, fn)	\
 ENTRY(name)				\
 	RING0_INT_FRAME;		\
+	ASM_CLAC;			\
 	pushl_cfi $~(nr);		\
 	SAVE_ALL;			\
 	TRACE_IRQS_OFF			\
@@ -857,6 +864,7 @@ ENDPROC(name)
 
 ENTRY(coprocessor_error)
 	RING0_INT_FRAME
+	ASM_CLAC
 	pushl_cfi $0
 	pushl_cfi $do_coprocessor_error
 	jmp error_code
@@ -865,6 +873,7 @@ END(coprocessor_error)
 
 ENTRY(simd_coprocessor_error)
 	RING0_INT_FRAME
+	ASM_CLAC
 	pushl_cfi $0
 #ifdef CONFIG_X86_INVD_BUG
 	/* AMD 486 bug: invd from userspace calls exception 19 instead of #GP */
@@ -886,6 +895,7 @@ END(simd_coprocessor_error)
 
 ENTRY(device_not_available)
 	RING0_INT_FRAME
+	ASM_CLAC
 	pushl_cfi $-1			# mark this as an int
 	pushl_cfi $do_device_not_available
 	jmp error_code
@@ -906,6 +916,7 @@ END(native_irq_enable_sysexit)
 
 ENTRY(overflow)
 	RING0_INT_FRAME
+	ASM_CLAC
 	pushl_cfi $0
 	pushl_cfi $do_overflow
 	jmp error_code
@@ -914,6 +925,7 @@ END(overflow)
 
 ENTRY(bounds)
 	RING0_INT_FRAME
+	ASM_CLAC
 	pushl_cfi $0
 	pushl_cfi $do_bounds
 	jmp error_code
@@ -922,6 +934,7 @@ END(bounds)
 
 ENTRY(invalid_op)
 	RING0_INT_FRAME
+	ASM_CLAC
 	pushl_cfi $0
 	pushl_cfi $do_invalid_op
 	jmp error_code
@@ -930,6 +943,7 @@ END(invalid_op)
 
 ENTRY(coprocessor_segment_overrun)
 	RING0_INT_FRAME
+	ASM_CLAC
 	pushl_cfi $0
 	pushl_cfi $do_coprocessor_segment_overrun
 	jmp error_code
@@ -938,6 +952,7 @@ END(coprocessor_segment_overrun)
 
 ENTRY(invalid_TSS)
 	RING0_EC_FRAME
+	ASM_CLAC
 	pushl_cfi $do_invalid_TSS
 	jmp error_code
 	CFI_ENDPROC
@@ -945,6 +960,7 @@ END(invalid_TSS)
 
 ENTRY(segment_not_present)
 	RING0_EC_FRAME
+	ASM_CLAC
 	pushl_cfi $do_segment_not_present
 	jmp error_code
 	CFI_ENDPROC
@@ -952,6 +968,7 @@ END(segment_not_present)
 
 ENTRY(stack_segment)
 	RING0_EC_FRAME
+	ASM_CLAC
 	pushl_cfi $do_stack_segment
 	jmp error_code
 	CFI_ENDPROC
@@ -959,6 +976,7 @@ END(stack_segment)
 
 ENTRY(alignment_check)
 	RING0_EC_FRAME
+	ASM_CLAC
 	pushl_cfi $do_alignment_check
 	jmp error_code
 	CFI_ENDPROC
@@ -966,6 +984,7 @@ END(alignment_check)
 
 ENTRY(divide_error)
 	RING0_INT_FRAME
+	ASM_CLAC
 	pushl_cfi $0			# no error code
 	pushl_cfi $do_divide_error
 	jmp error_code
@@ -975,6 +994,7 @@ END(divide_error)
 #ifdef CONFIG_X86_MCE
 ENTRY(machine_check)
 	RING0_INT_FRAME
+	ASM_CLAC
 	pushl_cfi $0
 	pushl_cfi machine_check_vector
 	jmp error_code
@@ -984,6 +1004,7 @@ END(machine_check)
 
 ENTRY(spurious_interrupt_bug)
 	RING0_INT_FRAME
+	ASM_CLAC
 	pushl_cfi $0
 	pushl_cfi $do_spurious_interrupt_bug
 	jmp error_code
@@ -1207,6 +1228,7 @@ return_to_handler:
 
 ENTRY(page_fault)
 	RING0_EC_FRAME
+	ASM_CLAC
 	pushl_cfi $do_page_fault
 	ALIGN
 error_code:
@@ -1279,6 +1301,7 @@ END(page_fault)
 
 ENTRY(debug)
 	RING0_INT_FRAME
+	ASM_CLAC
 	cmpl $ia32_sysenter_target,(%esp)
 	jne debug_stack_correct
 	FIX_STACK 12, debug_stack_correct, debug_esp_fix_insn
@@ -1303,6 +1326,7 @@ END(debug)
  */
 ENTRY(nmi)
 	RING0_INT_FRAME
+	ASM_CLAC
 	pushl_cfi %eax
 	movl %ss, %eax
 	cmpw $__ESPFIX_SS, %ax
@@ -1373,6 +1397,7 @@ END(nmi)
 
 ENTRY(int3)
 	RING0_INT_FRAME
+	ASM_CLAC
 	pushl_cfi $-1			# mark this as an int
 	SAVE_ALL
 	TRACE_IRQS_OFF
@@ -1393,6 +1418,7 @@ END(general_protection)
 #ifdef CONFIG_KVM_GUEST
 ENTRY(async_page_fault)
 	RING0_EC_FRAME
+	ASM_CLAC
 	pushl_cfi $do_async_page_fault
 	jmp error_code
 	CFI_ENDPROC
#17 lore raw

PATCH 9/11 x86, smap: Turn on Supervisor Mode Access Prevention

In reply to H. Peter Anvin

From: "H. Peter Anvin" <[email protected]>

If Supervisor Mode Access Prevention is available and not disabled by the user, turn it on. Also fix the expansion of SMEP (Supervisor Mode Execution Prevention.)

---
 Documentation/kernel-parameters.txt |    6 +++++-
 arch/x86/kernel/cpu/common.c        |   26 ++++++++++++++++++++++++++
 2 files changed, 31 insertions(+), 1 deletions(-)
Documentation/kernel-parameters.txt +5 -1
index ad7e2e5..49c5c41 100644
@@ -1812,8 +1812,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 			noexec=on: enable non-executable mappings (default)
 			noexec=off: disable non-executable mappings
 
+	nosmap		[X86]
+			Disable SMAP (Supervisor Mode Access Prevention)
+			even if it is supported by processor.
+
 	nosmep		[X86]
-			Disable SMEP (Supervisor Mode Execution Protection)
+			Disable SMEP (Supervisor Mode Execution Prevention)
 			even if it is supported by processor.
 
 	noexec32	[X86-64]
arch/x86/kernel/cpu/common.c +26 -0
index cd43e52..7d35d65 100644
@@ -278,6 +278,31 @@ static __cpuinit void setup_smep(struct cpuinfo_x86 *c)
 	}
 }
 
+static int disable_smap __cpuinitdata;
+static __init int setup_disable_smap(char *arg)
+{
+	disable_smap = 1;
+	return 1;
+}
+__setup("nosmap", setup_disable_smap);
+
+static __cpuinit void setup_smap(struct cpuinfo_x86 *c)
+{
+	if (cpu_has(c, X86_FEATURE_SMAP)) {
+		if (unlikely(disable_smap)) {
+			setup_clear_cpu_cap(X86_FEATURE_SMAP);
+			clear_in_cr4(X86_CR4_SMAP);
+		} else {
+			set_in_cr4(X86_CR4_SMAP);
+			/*
+			 * Don't use clac() here since alternatives
+			 * haven't run yet...
+			 */
+			asm volatile(__stringify(__ASM_CLAC) ::: "memory");
+		}
+	}
+}
+
 /*
  * Some CPU features depend on higher CPUID levels, which may not always
  * be available due to CPUID level capping or broken virtualization
@@ -713,6 +738,7 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
 	filter_cpuid_features(c, false);
 
 	setup_smep(c);
+	setup_smap(c);
 
 	if (this_cpu->c_bsp_init)
 		this_cpu->c_bsp_init(c);
Signature · 1 line
1.7.6.5
#18 lore raw

[tip:x86/smap] x86, smap: Turn on Supervisor Mode Access Prevention

Commit-ID:  52b6179ac87d33c2eeaff5292786a10fe98cff64
Gitweb:     http://git.kernel.org/tip/52b6179ac87d33c2eeaff5292786a10fe98cff64
Author:     H. Peter Anvin <[email protected]>
AuthorDate: Fri, 21 Sep 2012 12:43:13 -0700
Committer:  H. Peter Anvin <[email protected]>
CommitDate: Fri, 21 Sep 2012 12:45:27 -0700

x86, smap: Turn on Supervisor Mode Access Prevention

If Supervisor Mode Access Prevention is available and not disabled by the user, turn it on. Also fix the expansion of SMEP (Supervisor Mode Execution Prevention.)

---
 Documentation/kernel-parameters.txt |    6 +++++-
 arch/x86/kernel/cpu/common.c        |   26 ++++++++++++++++++++++++++
 2 files changed, 31 insertions(+), 1 deletions(-)
Documentation/kernel-parameters.txt +5 -1
index ad7e2e5..49c5c41 100644
@@ -1812,8 +1812,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 			noexec=on: enable non-executable mappings (default)
 			noexec=off: disable non-executable mappings
 
+	nosmap		[X86]
+			Disable SMAP (Supervisor Mode Access Prevention)
+			even if it is supported by processor.
+
 	nosmep		[X86]
-			Disable SMEP (Supervisor Mode Execution Protection)
+			Disable SMEP (Supervisor Mode Execution Prevention)
 			even if it is supported by processor.
 
 	noexec32	[X86-64]
arch/x86/kernel/cpu/common.c +26 -0
index cd43e52..7d35d65 100644
@@ -278,6 +278,31 @@ static __cpuinit void setup_smep(struct cpuinfo_x86 *c)
 	}
 }
 
+static int disable_smap __cpuinitdata;
+static __init int setup_disable_smap(char *arg)
+{
+	disable_smap = 1;
+	return 1;
+}
+__setup("nosmap", setup_disable_smap);
+
+static __cpuinit void setup_smap(struct cpuinfo_x86 *c)
+{
+	if (cpu_has(c, X86_FEATURE_SMAP)) {
+		if (unlikely(disable_smap)) {
+			setup_clear_cpu_cap(X86_FEATURE_SMAP);
+			clear_in_cr4(X86_CR4_SMAP);
+		} else {
+			set_in_cr4(X86_CR4_SMAP);
+			/*
+			 * Don't use clac() here since alternatives
+			 * haven't run yet...
+			 */
+			asm volatile(__stringify(__ASM_CLAC) ::: "memory");
+		}
+	}
+}
+
 /*
  * Some CPU features depend on higher CPUID levels, which may not always
  * be available due to CPUID level capping or broken virtualization
@@ -713,6 +738,7 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
 	filter_cpuid_features(c, false);
 
 	setup_smep(c);
+	setup_smap(c);
 
 	if (this_cpu->c_bsp_init)
 		this_cpu->c_bsp_init(c);
#19 lore raw

PATCH 10/11 x86, smap: A page fault due to SMAP is an oops

In reply to H. Peter Anvin

From: "H. Peter Anvin" <[email protected]>

If we get a page fault due to SMAP, trigger an oops rather than spinning forever.

---
 arch/x86/mm/fault.c |   18 ++++++++++++++++++
 1 files changed, 18 insertions(+), 0 deletions(-)
arch/x86/mm/fault.c +18 -0
index 76dcd9d..f2fb75d 100644
@@ -995,6 +995,17 @@ static int fault_in_kernel_space(unsigned long address)
 	return address >= TASK_SIZE_MAX;
 }
 
+static inline bool smap_violation(int error_code, struct pt_regs *regs)
+{
+	if (error_code & PF_USER)
+		return false;
+
+	if (!user_mode_vm(regs) && (regs->flags & X86_EFLAGS_AC))
+		return false;
+
+	return true;
+}
+
 /*
  * This routine handles page faults.  It determines the address,
  * and the problem, and then passes it off to one of the appropriate
@@ -1088,6 +1099,13 @@ do_page_fault(struct pt_regs *regs, unsigned long error_code)
 	if (unlikely(error_code & PF_RSVD))
 		pgtable_bad(regs, error_code, address);
 
+	if (static_cpu_has(X86_FEATURE_SMAP)) {
+		if (unlikely(smap_violation(error_code, regs))) {
+			bad_area_nosemaphore(regs, error_code, address);
+			return;
+		}
+	}
+
 	perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
 
 	/*
Signature · 1 line
1.7.6.5
#20 lore raw

[tip:x86/smap] x86, smap: A page fault due to SMAP is an oops

Commit-ID:  40d3cd6695014bf3c44e2ca66b610b18acaf923d
Gitweb:     http://git.kernel.org/tip/40d3cd6695014bf3c44e2ca66b610b18acaf923d
Author:     H. Peter Anvin <[email protected]>
AuthorDate: Fri, 21 Sep 2012 12:43:14 -0700
Committer:  H. Peter Anvin <[email protected]>
CommitDate: Fri, 21 Sep 2012 12:45:27 -0700

x86, smap: A page fault due to SMAP is an oops

If we get a page fault due to SMAP, trigger an oops rather than spinning forever.

---
 arch/x86/mm/fault.c |   18 ++++++++++++++++++
 1 files changed, 18 insertions(+), 0 deletions(-)
arch/x86/mm/fault.c +18 -0
index 76dcd9d..f2fb75d 100644
@@ -995,6 +995,17 @@ static int fault_in_kernel_space(unsigned long address)
 	return address >= TASK_SIZE_MAX;
 }
 
+static inline bool smap_violation(int error_code, struct pt_regs *regs)
+{
+	if (error_code & PF_USER)
+		return false;
+
+	if (!user_mode_vm(regs) && (regs->flags & X86_EFLAGS_AC))
+		return false;
+
+	return true;
+}
+
 /*
  * This routine handles page faults.  It determines the address,
  * and the problem, and then passes it off to one of the appropriate
@@ -1088,6 +1099,13 @@ do_page_fault(struct pt_regs *regs, unsigned long error_code)
 	if (unlikely(error_code & PF_RSVD))
 		pgtable_bad(regs, error_code, address);
 
+	if (static_cpu_has(X86_FEATURE_SMAP)) {
+		if (unlikely(smap_violation(error_code, regs))) {
+			bad_area_nosemaphore(regs, error_code, address);
+			return;
+		}
+	}
+
 	perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
 
 	/*
#21 lore raw

PATCH 11/11 x86, smap: Reduce the SMAP overhead for signal handling

In reply to H. Peter Anvin

From: "H. Peter Anvin" <[email protected]>

Signal handling contains a bunch of accesses to individual user space items, which causes an excessive number of STAC and CLAC instructions. Instead, let get/put_user_try ... get/put_user_catch() contain the STAC and CLAC instructions.

This means that get/put_user_try no longer nests, and furthermore that it is no longer legal to use user space access functions other than __get/put_user_ex() inside those blocks. However, these macros are x86-specific anyway and are only used in the signal-handling paths; a simple reordering of moving the larger subroutine calls out of the try...catch blocks resolves that problem.

---
 arch/x86/ia32/ia32_signal.c    |   12 +++++++-----
 arch/x86/include/asm/uaccess.h |   14 ++++++--------
 arch/x86/kernel/signal.c       |   24 ++++++++++++++----------
 3 files changed, 27 insertions(+), 23 deletions(-)
arch/x86/ia32/ia32_signal.c +7 -5
index 673ac9b..05e62a3 100644
@@ -250,11 +250,12 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
 
 		get_user_ex(tmp, &sc->fpstate);
 		buf = compat_ptr(tmp);
-		err |= restore_i387_xstate_ia32(buf);
 
 		get_user_ex(*pax, &sc->ax);
 	} get_user_catch(err);
 
+	err |= restore_i387_xstate_ia32(buf);
+
 	return err;
 }
 
@@ -502,7 +503,6 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 		put_user_ex(sig, &frame->sig);
 		put_user_ex(ptr_to_compat(&frame->info), &frame->pinfo);
 		put_user_ex(ptr_to_compat(&frame->uc), &frame->puc);
-		err |= copy_siginfo_to_user32(&frame->info, info);
 
 		/* Create the ucontext.  */
 		if (cpu_has_xsave)
@@ -514,9 +514,6 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 		put_user_ex(sas_ss_flags(regs->sp),
 			    &frame->uc.uc_stack.ss_flags);
 		put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
-		err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
-					     regs, set->sig[0]);
-		err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 
 		if (ka->sa.sa_flags & SA_RESTORER)
 			restorer = ka->sa.sa_restorer;
@@ -532,6 +529,11 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 		put_user_ex(*((u64 *)&code), (u64 *)frame->retcode);
 	} put_user_catch(err);
 
+	err |= copy_siginfo_to_user32(&frame->info, info);
+	err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
+				     regs, set->sig[0]);
+	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
 	if (err)
 		return -EFAULT;
 
arch/x86/include/asm/uaccess.h +6 -8
index b92ece1..a91acfb 100644
@@ -416,9 +416,8 @@ do {									\
 } while (0)
 
 #define __get_user_asm_ex(x, addr, itype, rtype, ltype)			\
-	asm volatile(ASM_STAC "\n"					\
-		     "1:	mov"itype" %1,%"rtype"0\n"		\
-		     "2: " ASM_CLAC "\n"				\
+	asm volatile("1:	mov"itype" %1,%"rtype"0\n"		\
+		     "2:\n"						\
 		     _ASM_EXTABLE_EX(1b, 2b)				\
 		     : ltype(x) : "m" (__m(addr)))
 
@@ -460,9 +459,8 @@ struct __large_struct { unsigned long buf[100]; };
 		     : ltype(x), "m" (__m(addr)), "i" (errret), "0" (err))
 
 #define __put_user_asm_ex(x, addr, itype, rtype, ltype)			\
-	asm volatile(ASM_STAC "\n"					\
-		     "1:	mov"itype" %"rtype"0,%1\n"		\
-		     "2: " ASM_CLAC "\n"				\
+	asm volatile("1:	mov"itype" %"rtype"0,%1\n"		\
+		     "2:\n"						\
 		     _ASM_EXTABLE_EX(1b, 2b)				\
 		     : : ltype(x), "m" (__m(addr)))
 
@@ -470,13 +468,13 @@ struct __large_struct { unsigned long buf[100]; };
  * uaccess_try and catch
  */
 #define uaccess_try	do {						\
-	int prev_err = current_thread_info()->uaccess_err;		\
 	current_thread_info()->uaccess_err = 0;				\
+	stac();								\
 	barrier();
 
 #define uaccess_catch(err)						\
+	clac();								\
 	(err) |= (current_thread_info()->uaccess_err ? -EFAULT : 0);	\
-	current_thread_info()->uaccess_err = prev_err;			\
 } while (0)
 
 /**
arch/x86/kernel/signal.c +14 -10
index b280908..9326128 100644
@@ -114,11 +114,12 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
 		regs->orig_ax = -1;		/* disable syscall checks */
 
 		get_user_ex(buf, &sc->fpstate);
-		err |= restore_i387_xstate(buf);
 
 		get_user_ex(*pax, &sc->ax);
 	} get_user_catch(err);
 
+	err |= restore_i387_xstate(buf);
+
 	return err;
 }
 
@@ -357,7 +358,6 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 		put_user_ex(sig, &frame->sig);
 		put_user_ex(&frame->info, &frame->pinfo);
 		put_user_ex(&frame->uc, &frame->puc);
-		err |= copy_siginfo_to_user(&frame->info, info);
 
 		/* Create the ucontext.  */
 		if (cpu_has_xsave)
@@ -369,9 +369,6 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 		put_user_ex(sas_ss_flags(regs->sp),
 			    &frame->uc.uc_stack.ss_flags);
 		put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
-		err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
-					regs, set->sig[0]);
-		err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 
 		/* Set up to return from userspace.  */
 		restorer = VDSO32_SYMBOL(current->mm->context.vdso, rt_sigreturn);
@@ -389,6 +386,11 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 		put_user_ex(*((u64 *)&rt_retcode), (u64 *)frame->retcode);
 	} put_user_catch(err);
 
+	err |= copy_siginfo_to_user(&frame->info, info);
+	err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
+				regs, set->sig[0]);
+	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
 	if (err)
 		return -EFAULT;
 
@@ -436,8 +438,6 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 		put_user_ex(sas_ss_flags(regs->sp),
 			    &frame->uc.uc_stack.ss_flags);
 		put_user_ex(me->sas_ss_size, &frame->uc.uc_stack.ss_size);
-		err |= setup_sigcontext(&frame->uc.uc_mcontext, fp, regs, set->sig[0]);
-		err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 
 		/* Set up to return from userspace.  If provided, use a stub
 		   already in userspace.  */
@@ -450,6 +450,9 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 		}
 	} put_user_catch(err);
 
+	err |= setup_sigcontext(&frame->uc.uc_mcontext, fp, regs, set->sig[0]);
+	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
 	if (err)
 		return -EFAULT;
 
@@ -855,9 +858,6 @@ static int x32_setup_rt_frame(int sig, struct k_sigaction *ka,
 			    &frame->uc.uc_stack.ss_flags);
 		put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
 		put_user_ex(0, &frame->uc.uc__pad0);
-		err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
-					regs, set->sig[0]);
-		err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 
 		if (ka->sa.sa_flags & SA_RESTORER) {
 			restorer = ka->sa.sa_restorer;
@@ -869,6 +869,10 @@ static int x32_setup_rt_frame(int sig, struct k_sigaction *ka,
 		put_user_ex(restorer, &frame->pretcode);
 	} put_user_catch(err);
 
+	err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
+				regs, set->sig[0]);
+	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
 	if (err)
 		return -EFAULT;
 
Signature · 1 line
1.7.6.5
#22 lore raw

[tip:x86/smap] x86, smap: Reduce the SMAP overhead for signal handling

Commit-ID:  5e88353d8b5f483bc1c873ad24ac2b59a6b66c73
Gitweb:     http://git.kernel.org/tip/5e88353d8b5f483bc1c873ad24ac2b59a6b66c73
Author:     H. Peter Anvin <[email protected]>
AuthorDate: Fri, 21 Sep 2012 12:43:15 -0700
Committer:  H. Peter Anvin <[email protected]>
CommitDate: Fri, 21 Sep 2012 12:45:27 -0700

x86, smap: Reduce the SMAP overhead for signal handling

Signal handling contains a bunch of accesses to individual user space items, which causes an excessive number of STAC and CLAC instructions. Instead, let get/put_user_try ... get/put_user_catch() contain the STAC and CLAC instructions.

This means that get/put_user_try no longer nests, and furthermore that it is no longer legal to use user space access functions other than __get/put_user_ex() inside those blocks. However, these macros are x86-specific anyway and are only used in the signal-handling paths; a simple reordering of moving the larger subroutine calls out of the try...catch blocks resolves that problem.

---
 arch/x86/ia32/ia32_signal.c    |   12 +++++++-----
 arch/x86/include/asm/uaccess.h |   14 ++++++--------
 arch/x86/kernel/signal.c       |   24 ++++++++++++++----------
 3 files changed, 27 insertions(+), 23 deletions(-)
arch/x86/ia32/ia32_signal.c +7 -5
index 673ac9b..05e62a3 100644
@@ -250,11 +250,12 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
 
 		get_user_ex(tmp, &sc->fpstate);
 		buf = compat_ptr(tmp);
-		err |= restore_i387_xstate_ia32(buf);
 
 		get_user_ex(*pax, &sc->ax);
 	} get_user_catch(err);
 
+	err |= restore_i387_xstate_ia32(buf);
+
 	return err;
 }
 
@@ -502,7 +503,6 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 		put_user_ex(sig, &frame->sig);
 		put_user_ex(ptr_to_compat(&frame->info), &frame->pinfo);
 		put_user_ex(ptr_to_compat(&frame->uc), &frame->puc);
-		err |= copy_siginfo_to_user32(&frame->info, info);
 
 		/* Create the ucontext.  */
 		if (cpu_has_xsave)
@@ -514,9 +514,6 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 		put_user_ex(sas_ss_flags(regs->sp),
 			    &frame->uc.uc_stack.ss_flags);
 		put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
-		err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
-					     regs, set->sig[0]);
-		err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 
 		if (ka->sa.sa_flags & SA_RESTORER)
 			restorer = ka->sa.sa_restorer;
@@ -532,6 +529,11 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 		put_user_ex(*((u64 *)&code), (u64 *)frame->retcode);
 	} put_user_catch(err);
 
+	err |= copy_siginfo_to_user32(&frame->info, info);
+	err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
+				     regs, set->sig[0]);
+	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
 	if (err)
 		return -EFAULT;
 
arch/x86/include/asm/uaccess.h +6 -8
index b92ece1..a91acfb 100644
@@ -416,9 +416,8 @@ do {									\
 } while (0)
 
 #define __get_user_asm_ex(x, addr, itype, rtype, ltype)			\
-	asm volatile(ASM_STAC "\n"					\
-		     "1:	mov"itype" %1,%"rtype"0\n"		\
-		     "2: " ASM_CLAC "\n"				\
+	asm volatile("1:	mov"itype" %1,%"rtype"0\n"		\
+		     "2:\n"						\
 		     _ASM_EXTABLE_EX(1b, 2b)				\
 		     : ltype(x) : "m" (__m(addr)))
 
@@ -460,9 +459,8 @@ struct __large_struct { unsigned long buf[100]; };
 		     : ltype(x), "m" (__m(addr)), "i" (errret), "0" (err))
 
 #define __put_user_asm_ex(x, addr, itype, rtype, ltype)			\
-	asm volatile(ASM_STAC "\n"					\
-		     "1:	mov"itype" %"rtype"0,%1\n"		\
-		     "2: " ASM_CLAC "\n"				\
+	asm volatile("1:	mov"itype" %"rtype"0,%1\n"		\
+		     "2:\n"						\
 		     _ASM_EXTABLE_EX(1b, 2b)				\
 		     : : ltype(x), "m" (__m(addr)))
 
@@ -470,13 +468,13 @@ struct __large_struct { unsigned long buf[100]; };
  * uaccess_try and catch
  */
 #define uaccess_try	do {						\
-	int prev_err = current_thread_info()->uaccess_err;		\
 	current_thread_info()->uaccess_err = 0;				\
+	stac();								\
 	barrier();
 
 #define uaccess_catch(err)						\
+	clac();								\
 	(err) |= (current_thread_info()->uaccess_err ? -EFAULT : 0);	\
-	current_thread_info()->uaccess_err = prev_err;			\
 } while (0)
 
 /**
arch/x86/kernel/signal.c +14 -10
index b280908..9326128 100644
@@ -114,11 +114,12 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
 		regs->orig_ax = -1;		/* disable syscall checks */
 
 		get_user_ex(buf, &sc->fpstate);
-		err |= restore_i387_xstate(buf);
 
 		get_user_ex(*pax, &sc->ax);
 	} get_user_catch(err);
 
+	err |= restore_i387_xstate(buf);
+
 	return err;
 }
 
@@ -357,7 +358,6 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 		put_user_ex(sig, &frame->sig);
 		put_user_ex(&frame->info, &frame->pinfo);
 		put_user_ex(&frame->uc, &frame->puc);
-		err |= copy_siginfo_to_user(&frame->info, info);
 
 		/* Create the ucontext.  */
 		if (cpu_has_xsave)
@@ -369,9 +369,6 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 		put_user_ex(sas_ss_flags(regs->sp),
 			    &frame->uc.uc_stack.ss_flags);
 		put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
-		err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
-					regs, set->sig[0]);
-		err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 
 		/* Set up to return from userspace.  */
 		restorer = VDSO32_SYMBOL(current->mm->context.vdso, rt_sigreturn);
@@ -389,6 +386,11 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 		put_user_ex(*((u64 *)&rt_retcode), (u64 *)frame->retcode);
 	} put_user_catch(err);
 
+	err |= copy_siginfo_to_user(&frame->info, info);
+	err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
+				regs, set->sig[0]);
+	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
 	if (err)
 		return -EFAULT;
 
@@ -436,8 +438,6 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 		put_user_ex(sas_ss_flags(regs->sp),
 			    &frame->uc.uc_stack.ss_flags);
 		put_user_ex(me->sas_ss_size, &frame->uc.uc_stack.ss_size);
-		err |= setup_sigcontext(&frame->uc.uc_mcontext, fp, regs, set->sig[0]);
-		err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 
 		/* Set up to return from userspace.  If provided, use a stub
 		   already in userspace.  */
@@ -450,6 +450,9 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 		}
 	} put_user_catch(err);
 
+	err |= setup_sigcontext(&frame->uc.uc_mcontext, fp, regs, set->sig[0]);
+	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
 	if (err)
 		return -EFAULT;
 
@@ -855,9 +858,6 @@ static int x32_setup_rt_frame(int sig, struct k_sigaction *ka,
 			    &frame->uc.uc_stack.ss_flags);
 		put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
 		put_user_ex(0, &frame->uc.uc__pad0);
-		err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
-					regs, set->sig[0]);
-		err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 
 		if (ka->sa.sa_flags & SA_RESTORER) {
 			restorer = ka->sa.sa_restorer;
@@ -869,6 +869,10 @@ static int x32_setup_rt_frame(int sig, struct k_sigaction *ka,
 		put_user_ex(restorer, &frame->pretcode);
 	} put_user_catch(err);
 
+	err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
+				regs, set->sig[0]);
+	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
 	if (err)
 		return -EFAULT;
 
#23 lore raw
In reply to H. Peter Anvin
Quoted 3 lines · H. Peter Anvin

Supervisor Mode Access Prevention (SMAP) is a new security feature disclosed by Intel in revision 014 of the Intel® Architecture Instruction Set Extensions Programming Reference:

Looks good.

Did this find any bugs, btw? We've had a few cases where we forgot to use the proper user access function, and code just happened to work because it all boils down to the same thing and never got any page faults in practice anyway..

I'd obviously hope that we have caught all of them, but.. IOW, has SMAP actually triggered for anybody in testing inside Intel?

Linus

#24 lore raw
Quoted 7 lines · Linus Torvalds
Quoted 3 lines · H. Peter Anvin

Supervisor Mode Access Prevention (SMAP) is a new security feature disclosed by Intel in revision 014 of the Intel® Architecture Instruction Set Extensions Programming Reference:

Looks good.

Quoted 8 lines

Did this find any bugs, btw? We've had a few cases where we forgot to use the proper user access function, and code just happened to work because it all boils down to the same thing and never got any page faults in practice anyway..

I'd obviously hope that we have caught all of them, but.. IOW, has SMAP actually triggered for anybody in testing inside Intel?

So far, it caught the use of PAGE_READONLY instead of PAGE_KERNEL_RO for the WP test on 32 bits (patch 02/11).

It has not had very high testing bandwidth yet, and especially the exposure of driver code has been very limited, so I would not be at all surprised if more crop up.

-hpa

#25 lore raw
In reply to Linus Torvalds
Quoted 7 lines · Linus Torvalds
Quoted 4 lines · H. Peter Anvin

Supervisor Mode Access Prevention (SMAP) is a new security feature disclosed by Intel in revision 014 of the Intel® Architecture Instruction Set Extensions Programming Reference:

Quoted 6 lines

Looks good.

Did this find any bugs, btw? We've had a few cases where we forgot to use the proper user access function, and code just happened to work because it all boils down to the same thing and never got any page faults in practice anyway..

The 4g:4g patch sweeped out most of the historic ones - so what we have are perhaps newer bugs (but those should be pretty rare, most new features are cross-arch).

Thanks,

Ingo

#26 lore raw
Quoted 12 lines · Ingo Molnar
Quoted 9 lines · Linus Torvalds
Quoted 4 lines · H. Peter Anvin

Supervisor Mode Access Prevention (SMAP) is a new security feature disclosed by Intel in revision 014 of the Intel® Architecture Instruction Set Extensions Programming Reference:

Looks good.

Quoted 9 lines
Quoted 4 lines

Did this find any bugs, btw? We've had a few cases where we forgot to use the proper user access function, and code just happened to work because it all boils down to the same thing and never got any page faults in practice anyway..

The 4g:4g patch sweeped out most of the historic ones - so what we have are perhaps newer bugs (but those should be pretty rare, most new features are cross-arch).

A while ago I also did a mockup patch which switched %cr3 to swapper_pg_dir while entering the kernel (basically where the CLAC instructions go, plus the SYSCALL path; a restore was obviously needed, too.) The performance was atrocious, but I didn't remember running into any problems.

-hpa

#27 lore raw
Quoted 6 lines · H. Peter Anvin

A while ago I also did a mockup patch which switched %cr3 to swapper_pg_dir while entering the kernel (basically where the CLAC instructions go, plus the SYSCALL path; a restore was obviously needed, too.) The performance was atrocious, but I didn't remember running into any problems.

Well, they are bound to be corner-cases and unusual. I was thinking of problems like the one recently fixed in commit ed6fe9d614fc ("Fix order of arguments to compat_put_time[spec|val]"), which really requires compat handling of fairly unusual cases.

That's the kind of situation where I'd expect bugs might still lurk. And it would only get triggered by some rather unusual setups.

Linus

#28 lore raw
Quoted 8 lines · Linus Torvalds
Quoted 6 lines · H. Peter Anvin

A while ago I also did a mockup patch which switched %cr3 to swapper_pg_dir while entering the kernel (basically where the CLAC instructions go, plus the SYSCALL path; a restore was obviously needed, too.) The performance was atrocious, but I didn't remember running into any problems.

Quoted 8 lines

Well, they are bound to be corner-cases and unusual. I was thinking of problems like the one recently fixed in commit ed6fe9d614fc ("Fix order of arguments to compat_put_time[spec|val]"), which really requires compat handling of fairly unusual cases.

That's the kind of situation where I'd expect bugs might still lurk. And it would only get triggered by some rather unusual setups.

Yes; in *most* cases these are exploitable security bugs on non-SMAP hardware (which is obviously the whole point!), but there are a few conditions where there may be issues that aren't exploitable problems.

-hpa

#29 lore raw
In reply to H. Peter Anvin
Quoted 13 lines · H. Peter Anvin

Supervisor Mode Access Prevention (SMAP) is a new security feature disclosed by Intel in revision 014 of the Intel® Architecture Instruction Set Extensions Programming Reference:

http://software.intel.com/sites/default/files/319433-014.pdf

When SMAP is active, the kernel cannot normally access pages that are user space (U=1). Since the kernel does have the need to access user space pages under specific circumstances, an override is provided: the kernel can access user space pages if EFLAGS.AC=1. For system data structures, e.g. descriptor tables, that are accessed by the processor directly, SMAP is active even in CPL 3 regardless of EFLAGS.AC.

Quoted 2 lines

SMAP also includes two new instructions, STAC and CLAC, to flip the AC flag more quickly.

Have you tested kexec in this environment?

This is the kind of cpu feature that when we enable it, frequently we have to do something on the kexec path.

At a quick skim it looks like the kexec path is using kernel page table entries and clearing all bits from cr4 except X86_CR4_PAE so I don't actually expect this change will require anything on the kexec path.

Eric

#30 lore raw
Quoted 10 lines · Eric W. Biederman

Have you tested kexec in this environment?

This is the kind of cpu feature that when we enable it, frequently we have to do something on the kexec path.

At a quick skim it looks like the kexec path is using kernel page table entries and clearing all bits from cr4 except X86_CR4_PAE so I don't actually expect this change will require anything on the kexec path.

I have not, no, but as you quite correctly point out that shouldn't affect things.

We should also change the kernel to start clean with CR4 -- the purpose of CR4 is to indicate which CPU features the OS is opting into.

I think we do on x86-64 but not on x86-32 at the moment.

This is an unrelated problem, though, and can be addressed later.

-hpa

#31 lore raw
Quoted 15 lines · H. Peter Anvin
Quoted 10 lines · Eric W. Biederman

Have you tested kexec in this environment?

This is the kind of cpu feature that when we enable it, frequently we have to do something on the kexec path.

At a quick skim it looks like the kexec path is using kernel page table entries and clearing all bits from cr4 except X86_CR4_PAE so I don't actually expect this change will require anything on the kexec path.

I have not, no, but as you quite correctly point out that shouldn't affect things.

Quoted 6 lines

We should also change the kernel to start clean with CR4 -- the purpose of CR4 is to indicate which CPU features the OS is opting into.

I think we do on x86-64 but not on x86-32 at the moment.

This is an unrelated problem, though, and can be addressed later.

Agreed. I just was just curious where things stood.

Eric

#32 lore raw

RFC PATCH 1/1 x86-32: Start out eflags and cr4 clean

From: "H. Peter Anvin" <[email protected]>

%cr4 is supposed to reflect a set of features into which the operating system is opting in. If the BIOS or bootloader leaks bits here, this is not desirable. Consider a bootloader passing in %cr4.pae set to a legacy paging kernel, for example -- it will not have any immediate effect, but the kernel would crash when turning paging on.

A similar argument applies to %eflags, and since we have to look for %eflags.id being settable we can use a sequence which clears %eflags as a side effect.

Note that we already do this for x86-64.

I would like opinions on this especially from the PV crowd and nonstandard platforms (e.g. OLPC) to make sure we don't screw them up.

---
 arch/x86/kernel/head_32.S |   31 ++++++++++++++++---------------
 1 files changed, 16 insertions(+), 15 deletions(-)
arch/x86/kernel/head_32.S +16 -15
index d42ab17..957a47a 100644
@@ -287,27 +287,28 @@ ENTRY(startup_32_smp)
 	leal -__PAGE_OFFSET(%ecx),%esp
 
 default_entry:
-
 /*
  *	New page tables may be in 4Mbyte page mode and may
  *	be using the global pages. 
  *
  *	NOTE! If we are on a 486 we may have no cr4 at all!
- *	So we do not try to touch it unless we really have
- *	some bits in it to set.  This won't work if the BSP
- *	implements cr4 but this AP does not -- very unlikely
- *	but be warned!  The same applies to the pse feature
- *	if not equally supported. --macro
- *
- *	NOTE! We have to correct for the fact that we're
- *	not yet offset PAGE_OFFSET..
+ *	Specifically, cr4 exists if and only if CPUID exists,
+ *	which in turn exists if and only if EFLAGS.ID exists.
  */
-#define cr4_bits pa(mmu_cr4_features)
-	movl cr4_bits,%edx
-	andl %edx,%edx
-	jz 6f
-	movl %cr4,%eax		# Turn on paging options (PSE,PAE,..)
-	orl %edx,%eax
+	movl $X86_EFLAGS_ID,%ecx
+	pushl %ecx
+	popfl
+	pushfl
+	popl %eax
+	pushl $0
+	popfl
+	pushfl
+	popl %edx
+	xorl %edx,%eax
+	testl %ecx,%eax
+	jz 6f			# No ID flag = no CPUID = no CR4
+
+	movl pa(mmu_cr4_features),%eax
 	movl %eax,%cr4
 
 	testb $X86_CR4_PAE, %al		# check if PAE is enabled
Signature · 1 line
1.7.6.5
#33 lore raw

Re: [RFC PATCH] x86-32: Start out eflags and cr4 clean

Quoted 12 lines · H. Peter Anvin

From: "H. Peter Anvin" <[email protected]>

%cr4 is supposed to reflect a set of features into which the operating system is opting in. If the BIOS or bootloader leaks bits here, this is not desirable. Consider a bootloader passing in %cr4.pae set to a legacy paging kernel, for example -- it will not have any immediate effect, but the kernel would crash when turning paging on.

A similar argument applies to %eflags, and since we have to look for %eflags.id being settable we can use a sequence which clears %eflags as a side effect.

Quoted 7 lines

Note that we already do this for x86-64.

I would like opinions on this especially from the PV crowd and nonstandard platforms (e.g. OLPC) to make sure we don't screw them up.

From a glance at this it looks ok - as we do not ever end up in this

function at all. Our entry point in the kernel is from startup_xen.

But just to make sure that nothing is amiss let me take this patch on a spin.

And thank you for CC-ing me.

Quoted 62 lines
---
 arch/x86/kernel/head_32.S |   31 ++++++++++++++++---------------
 1 files changed, 16 insertions(+), 15 deletions(-)
arch/x86/kernel/head_32.S +16 -15
index d42ab17..957a47a 100644
@@ -287,27 +287,28 @@ ENTRY(startup_32_smp)
 	leal -__PAGE_OFFSET(%ecx),%esp
 
 default_entry:
-
 /*
  *	New page tables may be in 4Mbyte page mode and may
  *	be using the global pages. 
  *
  *	NOTE! If we are on a 486 we may have no cr4 at all!
- *	So we do not try to touch it unless we really have
- *	some bits in it to set.  This won't work if the BSP
- *	implements cr4 but this AP does not -- very unlikely
- *	but be warned!  The same applies to the pse feature
- *	if not equally supported. --macro
- *
- *	NOTE! We have to correct for the fact that we're
- *	not yet offset PAGE_OFFSET..
+ *	Specifically, cr4 exists if and only if CPUID exists,
+ *	which in turn exists if and only if EFLAGS.ID exists.
  */
-#define cr4_bits pa(mmu_cr4_features)
-	movl cr4_bits,%edx
-	andl %edx,%edx
-	jz 6f
-	movl %cr4,%eax		# Turn on paging options (PSE,PAE,..)
-	orl %edx,%eax
+	movl $X86_EFLAGS_ID,%ecx
+	pushl %ecx
+	popfl
+	pushfl
+	popl %eax
+	pushl $0
+	popfl
+	pushfl
+	popl %edx
+	xorl %edx,%eax
+	testl %ecx,%eax
+	jz 6f			# No ID flag = no CPUID = no CR4
+
+	movl pa(mmu_cr4_features),%eax
 	movl %eax,%cr4
 
 	testb $X86_CR4_PAE, %al		# check if PAE is enabled
Signature · 7 lines
1.7.6.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/
Acked-by on v1 1/1
#34 lore raw

Re: [RFC PATCH] x86-32: Start out eflags and cr4 clean

In reply to H. Peter Anvin
Quoted 8 lines · H. Peter Anvin

From: "H. Peter Anvin" <[email protected]>

%cr4 is supposed to reflect a set of features into which the operating system is opting in. If the BIOS or bootloader leaks bits here, this is not desirable. Consider a bootloader passing in %cr4.pae set to a legacy paging kernel, for example -- it will not have any immediate effect, but the kernel would crash when turning paging on.

Quoted 7 lines

A similar argument applies to %eflags, and since we have to look for %eflags.id being settable we can use a sequence which clears %eflags as a side effect.

Note that we already do this for x86-64.

I would like opinions on this especially from the PV crowd

Xen PV guests don't pass through this code path so there is no danger there AFAICT, so from that PoV:

FWIW it looks correct to me from the native PoV too, but you probably already knew that ;-)

Ian.

Acked-by Tested-by
#35 lore raw

Re: [RFC PATCH] x86-32: Start out eflags and cr4 clean

Quoted 17 lines · Ian Campbell
Quoted 8 lines · H. Peter Anvin

From: "H. Peter Anvin" <[email protected]>

%cr4 is supposed to reflect a set of features into which the operating system is opting in. If the BIOS or bootloader leaks bits here, this is not desirable. Consider a bootloader passing in %cr4.pae set to a legacy paging kernel, for example -- it will not have any immediate effect, but the kernel would crash when turning paging on.

Quoted 7 lines

A similar argument applies to %eflags, and since we have to look for %eflags.id being settable we can use a sequence which clears %eflags as a side effect.

Note that we already do this for x86-64.

I would like opinions on this especially from the PV crowd

Quoted 7 lines

Xen PV guests don't pass through this code path so there is no danger there AFAICT, so from that PoV:

FWIW it looks correct to me from the native PoV too, but you probably already knew that ;-)

And sanity testing confirmed it.

Quoted 10 lines

Ian.

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

#36 lore raw

[tip:x86/smap] x86-32: Start out eflags and cr4 clean

In reply to H. Peter Anvin
Commit-ID:  5a5a51db78ef24aa61a4cb2ae36f07f6fa37356d
Gitweb:     http://git.kernel.org/tip/5a5a51db78ef24aa61a4cb2ae36f07f6fa37356d
Author:     H. Peter Anvin <[email protected]>
AuthorDate: Mon, 24 Sep 2012 16:05:48 -0700
Committer:  H. Peter Anvin <[email protected]>
CommitDate: Wed, 26 Sep 2012 15:06:22 -0700

x86-32: Start out eflags and cr4 clean

%cr4 is supposed to reflect a set of features into which the operating system is opting in. If the BIOS or bootloader leaks bits here, this is not desirable. Consider a bootloader passing in %cr4.pae set to a legacy paging kernel, for example -- it will not have any immediate effect, but the kernel would crash when turning paging on.

A similar argument applies to %eflags, and since we have to look for %eflags.id being settable we can use a sequence which clears %eflags as a side effect.

Note that we already do this for x86-64.

---
 arch/x86/kernel/head_32.S |   31 ++++++++++++++++---------------
 1 files changed, 16 insertions(+), 15 deletions(-)
arch/x86/kernel/head_32.S +16 -15
index d42ab17..957a47a 100644
@@ -287,27 +287,28 @@ ENTRY(startup_32_smp)
 	leal -__PAGE_OFFSET(%ecx),%esp
 
 default_entry:
-
 /*
  *	New page tables may be in 4Mbyte page mode and may
  *	be using the global pages. 
  *
  *	NOTE! If we are on a 486 we may have no cr4 at all!
- *	So we do not try to touch it unless we really have
- *	some bits in it to set.  This won't work if the BSP
- *	implements cr4 but this AP does not -- very unlikely
- *	but be warned!  The same applies to the pse feature
- *	if not equally supported. --macro
- *
- *	NOTE! We have to correct for the fact that we're
- *	not yet offset PAGE_OFFSET..
+ *	Specifically, cr4 exists if and only if CPUID exists,
+ *	which in turn exists if and only if EFLAGS.ID exists.
  */
-#define cr4_bits pa(mmu_cr4_features)
-	movl cr4_bits,%edx
-	andl %edx,%edx
-	jz 6f
-	movl %cr4,%eax		# Turn on paging options (PSE,PAE,..)
-	orl %edx,%eax
+	movl $X86_EFLAGS_ID,%ecx
+	pushl %ecx
+	popfl
+	pushfl
+	popl %eax
+	pushl $0
+	popfl
+	pushfl
+	popl %edx
+	xorl %edx,%eax
+	testl %ecx,%eax
+	jz 6f			# No ID flag = no CPUID = no CR4
+
+	movl pa(mmu_cr4_features),%eax
 	movl %eax,%cr4
 
 	testb $X86_CR4_PAE, %al		# check if PAE is enabled
#37 lore raw

RE: [tip:x86/smap] x86-32: Start out eflags and cr4 clean

Quoted 2 lines

+ * Specifically, cr4 exists if and only if CPUID exists,
+ * which in turn exists if and only if EFLAGS.ID exists.

This may be true for *Intel* 486 CPUs as VME was implemented at the same time as CPUID, but I am not sure that it is true for AMD 486 CPUs.

Yuhong Bao

#38 lore raw

Re: [tip:x86/smap] x86-32: Start out eflags and cr4 clean

Quoted 5 lines · Yuhong Bao
Quoted 2 lines

+ * Specifically, cr4 exists if and only if CPUID exists,
+ * which in turn exists if and only if EFLAGS.ID exists.

This may be true for *Intel* 486 CPUs as VME was implemented at the same time as CPUID, but I am not sure that it is true for AMD 486 CPUs.

Yuhong Bao

That is the architecture; if you know of a counterexample speak up. "I am not sure" doesn't count.

-hpa

Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.
#39 lore raw

[tip:x86/smap] x86, suspend: On wakeup always initialize cr4 and EFER

In reply to H. Peter Anvin
Commit-ID:  73201dbec64aebf6b0dca855b523f437972dc7bb
Gitweb:     http://git.kernel.org/tip/73201dbec64aebf6b0dca855b523f437972dc7bb
Author:     H. Peter Anvin <[email protected]>
AuthorDate: Wed, 26 Sep 2012 15:02:34 -0700
Committer:  H. Peter Anvin <[email protected]>
CommitDate: Wed, 26 Sep 2012 15:06:22 -0700

x86, suspend: On wakeup always initialize cr4 and EFER

We already have a flag word to indicate the existence of MISC_ENABLES, so use the same flag word to indicate existence of cr4 and EFER, and always restore them if they exist. That way if something passes a nonzero value when the value *should* be zero, we will still initialize it.

---
 arch/x86/kernel/acpi/sleep.c      |   15 ++++++++++-----
 arch/x86/realmode/rm/wakeup.h     |    2 ++
 arch/x86/realmode/rm/wakeup_asm.S |   29 +++++++++++++++++++----------
 3 files changed, 31 insertions(+), 15 deletions(-)
arch/x86/kernel/acpi/sleep.c +10 -5
index 1b8e5a0..11676cf 100644
@@ -43,17 +43,22 @@ int acpi_suspend_lowlevel(void)
 
 	header->video_mode = saved_video_mode;
 
+	header->pmode_behavior = 0;
+
 #ifndef CONFIG_64BIT
 	store_gdt((struct desc_ptr *)&header->pmode_gdt);
 
-	if (rdmsr_safe(MSR_EFER, &header->pmode_efer_low,
-		       &header->pmode_efer_high))
-		header->pmode_efer_low = header->pmode_efer_high = 0;
+	if (!rdmsr_safe(MSR_EFER,
+			&header->pmode_efer_low,
+			&header->pmode_efer_high))
+		header->pmode_behavior |= (1 << WAKEUP_BEHAVIOR_RESTORE_EFER);
 #endif /* !CONFIG_64BIT */
 
 	header->pmode_cr0 = read_cr0();
-	header->pmode_cr4 = read_cr4_safe();
-	header->pmode_behavior = 0;
+	if (__this_cpu_read(cpu_info.cpuid_level) >= 0) {
+		header->pmode_cr4 = read_cr4();
+		header->pmode_behavior |= (1 << WAKEUP_BEHAVIOR_RESTORE_CR4);
+	}
 	if (!rdmsr_safe(MSR_IA32_MISC_ENABLE,
 			&header->pmode_misc_en_low,
 			&header->pmode_misc_en_high))
arch/x86/realmode/rm/wakeup.h +2 -0
index 9317e00..7dd86a4 100644
@@ -36,5 +36,7 @@ extern struct wakeup_header wakeup_header;
 
 /* Wakeup behavior bits */
 #define WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE     0
+#define WAKEUP_BEHAVIOR_RESTORE_CR4		1
+#define WAKEUP_BEHAVIOR_RESTORE_EFER		2
 
 #endif /* ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H */
arch/x86/realmode/rm/wakeup_asm.S +19 -10
index 8905166..e56479e 100644
@@ -74,9 +74,18 @@ ENTRY(wakeup_start)
 
 	lidtl	wakeup_idt
 
-	/* Clear the EFLAGS */
-	pushl	$0
+	/* Clear the EFLAGS but remember if we have EFLAGS.ID */
+	movl $X86_EFLAGS_ID, %ecx
+	pushl %ecx
 	popfl
+	pushfl
+	popl %edi
+	pushl $0
+	popfl
+	pushfl
+	popl %edx
+	xorl %edx, %edi
+	andl %ecx, %edi		/* %edi is zero iff CPUID & %cr4 are missing */
 
 	/* Check header signature... */
 	movl	signature, %eax
@@ -93,8 +102,8 @@ ENTRY(wakeup_start)
 
 	/* Restore MISC_ENABLE before entering protected mode, in case
 	   BIOS decided to clear XD_DISABLE during S3. */
-	movl	pmode_behavior, %eax
-	btl	$WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE, %eax
+	movl	pmode_behavior, %edi
+	btl	$WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE, %edi
 	jnc	1f
 
 	movl	pmode_misc_en, %eax
@@ -110,15 +119,15 @@ ENTRY(wakeup_start)
 	movl	pmode_cr3, %eax
 	movl	%eax, %cr3
 
-	movl	pmode_cr4, %ecx
-	jecxz	1f
-	movl	%ecx, %cr4
+	btl	$WAKEUP_BEHAVIOR_RESTORE_CR4, %edi
+	jz	1f
+	movl	pmode_cr4, %eax
+	movl	%eax, %cr4
 1:
+	btl	$WAKEUP_BEHAVIOR_RESTORE_EFER, %edi
+	jz	1f
 	movl	pmode_efer, %eax
 	movl	pmode_efer + 4, %edx
-	movl	%eax, %ecx
-	orl	%edx, %ecx
-	jz	1f
 	movl	$MSR_EFER, %ecx
 	wrmsr
 1:
#40 lore raw

[tip:x86/urgent] x86, suspend: Correct the restore of CR4, EFER; skip computing EFLAGS.ID

In reply to H. Peter Anvin
Commit-ID:  f1d01b229294734e52630c6ad6366aa29a257475
Gitweb:     http://git.kernel.org/tip/f1d01b229294734e52630c6ad6366aa29a257475
Author:     H. Peter Anvin <[email protected]>
AuthorDate: Mon, 1 Oct 2012 14:34:42 -0700
Committer:  H. Peter Anvin <[email protected]>
CommitDate: Mon, 1 Oct 2012 14:45:18 -0700

x86, suspend: Correct the restore of CR4, EFER; skip computing EFLAGS.ID

The patch:

73201dbe x86, suspend: On wakeup always initialize cr4 and EFER

... was incorrectly committed in an intermediate (unfinished) form.

- We need to test CF, not ZF, for a bit test with btl.
- We don't actually need to compute the existence of EFLAGS.ID, since we set a flag at suspend time if CR4 should be restored.

---
 arch/x86/realmode/rm/wakeup_asm.S |   15 +++------------
 1 files changed, 3 insertions(+), 12 deletions(-)
arch/x86/realmode/rm/wakeup_asm.S +3 -12
index e56479e..9e7e147 100644
@@ -74,18 +74,9 @@ ENTRY(wakeup_start)
 
 	lidtl	wakeup_idt
 
-	/* Clear the EFLAGS but remember if we have EFLAGS.ID */
-	movl $X86_EFLAGS_ID, %ecx
-	pushl %ecx
-	popfl
-	pushfl
-	popl %edi
+	/* Clear the EFLAGS */
 	pushl $0
 	popfl
-	pushfl
-	popl %edx
-	xorl %edx, %edi
-	andl %ecx, %edi		/* %edi is zero iff CPUID & %cr4 are missing */
 
 	/* Check header signature... */
 	movl	signature, %eax
@@ -120,12 +111,12 @@ ENTRY(wakeup_start)
 	movl	%eax, %cr3
 
 	btl	$WAKEUP_BEHAVIOR_RESTORE_CR4, %edi
-	jz	1f
+	jnc	1f
 	movl	pmode_cr4, %eax
 	movl	%eax, %cr4
 1:
 	btl	$WAKEUP_BEHAVIOR_RESTORE_EFER, %edi
-	jz	1f
+	jnc	1f
 	movl	pmode_efer, %eax
 	movl	pmode_efer + 4, %edx
 	movl	$MSR_EFER, %ecx
#41 lore raw

[tip:x86/urgent] x86, suspend: Correct the restore of CR4, EFER; skip computing EFLAGS.ID

In reply to H. Peter Anvin
Commit-ID:  1396adc3c2bdc556d4cdd1cf107aa0b6d59fbb1e
Gitweb:     http://git.kernel.org/tip/1396adc3c2bdc556d4cdd1cf107aa0b6d59fbb1e
Author:     H. Peter Anvin <[email protected]>
AuthorDate: Mon, 1 Oct 2012 14:34:42 -0700
Committer:  Ingo Molnar <[email protected]>
CommitDate: Tue, 2 Oct 2012 08:42:31 +0200

x86, suspend: Correct the restore of CR4, EFER; skip computing EFLAGS.ID

The patch:

73201dbe x86, suspend: On wakeup always initialize cr4 and EFER

... was incorrectly committed in an intermediate (unfinished) form.

- We need to test CF, not ZF, for a bit test with btl.
- We don't actually need to compute the existence of EFLAGS.ID, since we set a flag at suspend time if CR4 should be restored.

---
 arch/x86/realmode/rm/wakeup_asm.S |   15 +++------------
 1 files changed, 3 insertions(+), 12 deletions(-)
arch/x86/realmode/rm/wakeup_asm.S +3 -12
index e56479e..9e7e147 100644
@@ -74,18 +74,9 @@ ENTRY(wakeup_start)
 
 	lidtl	wakeup_idt
 
-	/* Clear the EFLAGS but remember if we have EFLAGS.ID */
-	movl $X86_EFLAGS_ID, %ecx
-	pushl %ecx
-	popfl
-	pushfl
-	popl %edi
+	/* Clear the EFLAGS */
 	pushl $0
 	popfl
-	pushfl
-	popl %edx
-	xorl %edx, %edi
-	andl %ecx, %edi		/* %edi is zero iff CPUID & %cr4 are missing */
 
 	/* Check header signature... */
 	movl	signature, %eax
@@ -120,12 +111,12 @@ ENTRY(wakeup_start)
 	movl	%eax, %cr3
 
 	btl	$WAKEUP_BEHAVIOR_RESTORE_CR4, %edi
-	jz	1f
+	jnc	1f
 	movl	pmode_cr4, %eax
 	movl	%eax, %cr4
 1:
 	btl	$WAKEUP_BEHAVIOR_RESTORE_EFER, %edi
-	jz	1f
+	jnc	1f
 	movl	pmode_efer, %eax
 	movl	pmode_efer + 4, %edx
 	movl	$MSR_EFER, %ecx
Acked-by on v1 1/1
#42 lore raw

Re: [RFC PATCH] x86-32: Start out eflags and cr4 clean

In reply to H. Peter Anvin

Thanks for Cc'ing me. I just tested this on an XO-1, and it doesn't appear to break anything. So, looks fine to me.

Quoted 72 lines · On Mon, 24 Sep 2012 16:27:19 -0700 "H. Peter Anvin" <[email protected]> wrote:

From: "H. Peter Anvin" <[email protected]>

%cr4 is supposed to reflect a set of features into which the operating system is opting in. If the BIOS or bootloader leaks bits here, this is not desirable. Consider a bootloader passing in %cr4.pae set to a legacy paging kernel, for example -- it will not have any immediate effect, but the kernel would crash when turning paging on.

A similar argument applies to %eflags, and since we have to look for %eflags.id being settable we can use a sequence which clears %eflags as a side effect.

Note that we already do this for x86-64.

I would like opinions on this especially from the PV crowd and nonstandard platforms (e.g. OLPC) to make sure we don't screw them up.

---
 arch/x86/kernel/head_32.S |   31 ++++++++++++++++---------------
 1 files changed, 16 insertions(+), 15 deletions(-)
arch/x86/kernel/head_32.S +16 -15
index d42ab17..957a47a 100644
@@ -287,27 +287,28 @@ ENTRY(startup_32_smp)
 	leal -__PAGE_OFFSET(%ecx),%esp
 
 default_entry:
-
 /*
  *	New page tables may be in 4Mbyte page mode and may
  *	be using the global pages. 
  *
  *	NOTE! If we are on a 486 we may have no cr4 at all!
- *	So we do not try to touch it unless we really have
- *	some bits in it to set.  This won't work if the BSP
- *	implements cr4 but this AP does not -- very unlikely
- *	but be warned!  The same applies to the pse feature
- *	if not equally supported. --macro
- *
- *	NOTE! We have to correct for the fact that we're
- *	not yet offset PAGE_OFFSET..
+ *	Specifically, cr4 exists if and only if CPUID exists,
+ *	which in turn exists if and only if EFLAGS.ID exists.
  */
-#define cr4_bits pa(mmu_cr4_features)
-	movl cr4_bits,%edx
-	andl %edx,%edx
-	jz 6f
-	movl %cr4,%eax		# Turn on paging options
 (PSE,PAE,..)
-	orl %edx,%eax
+	movl $X86_EFLAGS_ID,%ecx
+	pushl %ecx
+	popfl
+	pushfl
+	popl %eax
+	pushl $0
+	popfl
+	pushfl
+	popl %edx
+	xorl %edx,%eax
+	testl %ecx,%eax
+	jz 6f			# No ID flag = no CPUID = no CR4
+
+	movl pa(mmu_cr4_features),%eax
 	movl %eax,%cr4
 

testb $X86_CR4_PAE, %al # check if PAE is
enabled

#43 lore raw

Re: [RFC PATCH] x86-32: Start out eflags and cr4 clean

Bad news on this patch; I've been told that it breaks booting on an XO-1.5. Does anyone from OLPC know why yet?

Quoted 83 lines · On Wed, 10 Oct 2012 12:59:27 -0700 Andres Salomon <[email protected]> wrote:

Thanks for Cc'ing me. I just tested this on an XO-1, and it doesn't appear to break anything. So, looks fine to me.

Quoted 74 lines · On Mon, 24 Sep 2012 16:27:19 -0700 "H. Peter Anvin" <[email protected]> wrote:

From: "H. Peter Anvin" <[email protected]>

%cr4 is supposed to reflect a set of features into which the operating system is opting in. If the BIOS or bootloader leaks bits here, this is not desirable. Consider a bootloader passing in %cr4.pae set to a legacy paging kernel, for example -- it will not have any immediate effect, but the kernel would crash when turning paging on.

A similar argument applies to %eflags, and since we have to look for %eflags.id being settable we can use a sequence which clears %eflags as a side effect.

Note that we already do this for x86-64.

I would like opinions on this especially from the PV crowd and nonstandard platforms (e.g. OLPC) to make sure we don't screw them up.

---
 arch/x86/kernel/head_32.S |   31 ++++++++++++++++---------------
 1 files changed, 16 insertions(+), 15 deletions(-)
arch/x86/kernel/head_32.S +14 -15
index d42ab17..957a47a 100644
@@ -287,27 +287,28 @@ ENTRY(startup_32_smp)
 	leal -__PAGE_OFFSET(%ecx),%esp
 
 default_entry:
-
 /*
  *	New page tables may be in 4Mbyte page mode and may
  *	be using the global pages. 
  *
  *	NOTE! If we are on a 486 we may have no cr4 at all!
- *	So we do not try to touch it unless we really have
- *	some bits in it to set.  This won't work if the BSP
- *	implements cr4 but this AP does not -- very unlikely
- *	but be warned!  The same applies to the pse feature
- *	if not equally supported. --macro
- *
- *	NOTE! We have to correct for the fact that we're
- *	not yet offset PAGE_OFFSET..
+ *	Specifically, cr4 exists if and only if CPUID exists,
+ *	which in turn exists if and only if EFLAGS.ID exists.
  */
-#define cr4_bits pa(mmu_cr4_features)
-	movl cr4_bits,%edx
-	andl %edx,%edx
-	jz 6f
-	movl %cr4,%eax		# Turn on paging options
 (PSE,PAE,..)
-	orl %edx,%eax
+	movl $X86_EFLAGS_ID,%ecx
+	pushl %ecx
+	popfl
+	pushfl
+	popl %eax
+	pushl $0
+	popfl
+	pushfl
+	popl %edx
+	xorl %edx,%eax
+	testl %ecx,%eax
+	jz 6f			# No ID flag = no CPUID = no

CR4 +

arch/x86/kernel/head_32.S +1 -0
+	movl pa(mmu_cr4_features),%eax
 	movl %eax,%cr4
 
 	testb $X86_CR4_PAE, %al		# check if PAE is

enabled

#44 lore raw

Re: [RFC PATCH] x86-32: Start out eflags and cr4 clean

Quoted 2 lines · Andres Salomon

Bad news on this patch; I've been told that it breaks booting on an XO-1.5. Does anyone from OLPC know why yet?

What are the settings of CR0 and CR4 on kernel entry on XO-1.5?

-hpa

#45 lore raw

Re: [Techteam] [RFC PATCH] x86-32: Start out eflags and cr4 clean

Quoted 5 lines · H. Peter Anvin
Quoted 2 lines · Andres Salomon

Bad news on this patch; I've been told that it breaks booting on an XO-1.5. Does anyone from OLPC know why yet?

What are the settings of CR0 and CR4 on kernel entry on XO-1.5?

CR0 is 0x80000011
CR4 is 0x10

Quoted 9 lines

-hpa

_______________________________________________
Techteam mailing list
[email protected]
http://lists.laptop.org/listinfo/techteam

#46 lore raw

Re: [Techteam] [RFC PATCH] x86-32: Start out eflags and cr4 clean

Quoted 4 lines · Mitch Bradley
Quoted 1 line · H. Peter Anvin

On 01/18/2013 04:40 PM, Andres Salomon wrote:

Quoted 9 lines
Quoted 4 lines
Quoted 2 lines

Bad news on this patch; I've been told that it breaks booting on an XO-1.5. Does anyone from OLPC know why yet?

What are the settings of CR0 and CR4 on kernel entry on XO-1.5?

CR0 is 0x80000011
CR4 is 0x10

OK, that makes sense... the kernel doesn't enable the PSE bit yet and I bet that's what you're using for the non-stolen page tables.

Can we simply disable paging before mucking with CR4? The other option that I can see is to always enable PSE and PGE, since they are simply features opt-ins that don't do any harm if unused. At the same time, though, entering the kernel through the default_entry path with paging enabled is definitely not anything the kernel expects.

Does this patch work for you? Since we have ditched 386 support, we can mimic x86-64 (yay, one more difference gone!) and just use a predefined value for %cr0 (the FPU flags need to change if we are on an FPU-less chip, but that happens during FPU probing.)

Does this patch work for you?

-hpa

arch/x86/kernel/head_32.S +6 -2
index 8e7f655..2713ea1 100644
@@ -300,6 +300,11 @@ ENTRY(startup_32_smp)
 	leal -__PAGE_OFFSET(%ecx),%esp
 
 default_entry:
+#define CR0_STATE	(X86_CR0_PE | X86_CR0_MP | X86_CR0_ET | \
+			 X86_CR0_NE | X86_CR0_WP | X86_CR0_AM | \
+			 X86_CR0_PG)
+	movl $(CR0_STATE & ~X86_CR0_PG),%eax
+	movl %eax,%cr0
 /*
  *	New page tables may be in 4Mbyte page mode and may
  *	be using the global pages. 
@@ -364,8 +369,7 @@ default_entry:
  */
 	movl $pa(initial_page_table), %eax
 	movl %eax,%cr3		/* set the page table pointer.. */
-	movl %cr0,%eax
-	orl  $X86_CR0_PG,%eax
+	movl $CR0_STATE,%eax
 	movl %eax,%cr0		/* ..and set paging (PG) bit */
 	ljmp $__BOOT_CS,$1f	/* Clear prefetch and normalize %eip */
 1:
#47 lore raw

Re: [Techteam] [RFC PATCH] x86-32: Start out eflags and cr4 clean

Quoted 11 lines · H. Peter Anvin
Quoted 10 lines · Mitch Bradley
Quoted 5 lines · H. Peter Anvin
Quoted 2 lines · Andres Salomon

Bad news on this patch; I've been told that it breaks booting on an XO-1.5. Does anyone from OLPC know why yet?

What are the settings of CR0 and CR4 on kernel entry on XO-1.5?

Quoted 6 lines
Quoted 3 lines

CR0 is 0x80000011
CR4 is 0x10

OK, that makes sense... the kernel doesn't enable the PSE bit yet and I bet that's what you're using for the non-stolen page tables.

Indeed, we are using 4M pages to map the firmware into high virtual addresses.

Quoted 7 lines

Can we simply disable paging before mucking with CR4? The other option that I can see is to always enable PSE and PGE, since they are simply features opt-ins that don't do any harm if unused. At the same time, though, entering the kernel through the default_entry path with paging enabled is definitely not anything the kernel expects.

Quoted 6 lines

Does this patch work for you? Since we have ditched 386 support, we can mimic x86-64 (yay, one more difference gone!) and just use a predefined value for %cr0 (the FPU flags need to change if we are on an FPU-less chip, but that happens during FPU probing.)

Does this patch work for you?

We will test it and get back to you.

Quoted 5 lines

-hpa

#48 lore raw

Re: [Techteam] [RFC PATCH] x86-32: Start out eflags and cr4 clean

In reply to H. Peter Anvin
Quoted 10 lines · H. Peter Anvin

Can we simply disable paging before mucking with CR4? The other option that I can see is to always enable PSE and PGE, since they are simply features opt-ins that don't do any harm if unused. At the same time, though, entering the kernel through the default_entry path with paging enabled is definitely not anything the kernel expects.

Does this patch work for you? Since we have ditched 386 support, we can mimic x86-64 (yay, one more difference gone!) and just use a predefined value for %cr0 (the FPU flags need to change if we are on an FPU-less chip, but that happens during FPU probing.)

The patch fixes boot on XO-1.5. Thanks for the quick response!

Daniel

#49 lore raw

[tip:x86/urgent] x86-32: Start out cr0 clean, disable paging before modifying cr3/4

In reply to H. Peter Anvin
Commit-ID:  021ef050fc092d5638e69868d126c18006ea7296
Gitweb:     http://git.kernel.org/tip/021ef050fc092d5638e69868d126c18006ea7296
Author:     H. Peter Anvin <[email protected]>
AuthorDate: Sat, 19 Jan 2013 10:29:37 -0800
Committer:  H. Peter Anvin <[email protected]>
CommitDate: Sat, 19 Jan 2013 11:01:22 -0800

x86-32: Start out cr0 clean, disable paging before modifying cr3/4

Patch

5a5a51db78e x86-32: Start out eflags and cr4 clean

... made x86-32 match x86-64 in that we initialize %eflags and %cr4 from scratch. This broke OLPC XO-1.5, because the XO enters the kernel with paging enabled, which the kernel doesn't expect.

Since we no longer support 386 (the source of most of the variability in %cr0 configuration), we can simply match further x86-64 and initialize %cr0 to a fixed value -- the one variable part remaining in %cr0 is for FPU control, but all that is handled later on in initialization; in particular, configuring %cr0 as if the FPU is present until proven otherwise is correct and necessary for the probe to work.

To deal with the XO case sanely, explicitly disable paging in %cr0 before we muck with %cr3, %cr4 or EFER -- those operations are inherently unsafe with paging enabled.

NOTE: There is still a lot of 386-related junk in head_32.S which we can and should get rid of, however, this is intended as a minimal fix whereas the cleanup can be deferred to the next merge window.

---
 arch/x86/kernel/head_32.S | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)
arch/x86/kernel/head_32.S +7 -2
index 8e7f655..c8932c7 100644
@@ -300,6 +300,12 @@ ENTRY(startup_32_smp)
 	leal -__PAGE_OFFSET(%ecx),%esp
 
 default_entry:
+#define CR0_STATE	(X86_CR0_PE | X86_CR0_MP | X86_CR0_ET | \
+			 X86_CR0_NE | X86_CR0_WP | X86_CR0_AM | \
+			 X86_CR0_PG)
+	movl $(CR0_STATE & ~X86_CR0_PG),%eax
+	movl %eax,%cr0
+
 /*
  *	New page tables may be in 4Mbyte page mode and may
  *	be using the global pages. 
@@ -364,8 +370,7 @@ default_entry:
  */
 	movl $pa(initial_page_table), %eax
 	movl %eax,%cr3		/* set the page table pointer.. */
-	movl %cr0,%eax
-	orl  $X86_CR0_PG,%eax
+	movl $CR0_STATE,%eax
 	movl %eax,%cr0		/* ..and set paging (PG) bit */
 	ljmp $__BOOT_CS,$1f	/* Clear prefetch and normalize %eip */
 1:
#50 lore raw
In reply to H. Peter Anvin
Quoted 13 lines · H. Peter Anvin

Supervisor Mode Access Prevention (SMAP) is a new security feature disclosed by Intel in revision 014 of the Intel® Architecture Instruction Set Extensions Programming Reference:

http://software.intel.com/sites/default/files/319433-014.pdf

When SMAP is active, the kernel cannot normally access pages that are user space (U=1). Since the kernel does have the need to access user space pages under specific circumstances, an override is provided: the kernel can access user space pages if EFLAGS.AC=1. For system data structures, e.g. descriptor tables, that are accessed by the processor directly, SMAP is active even in CPL 3 regardless of EFLAGS.AC.

Quoted 2 lines

SMAP also includes two new instructions, STAC and CLAC, to flip the AC flag more quickly.

Perhaps add a printk somewhere to show that it's actually been enabled maybe ?

Also, would it be feasible to add something like we have for test_nx ? If this feature regresses in some way in the future, I suspect we'd like to know about it sooner rather than later.

Dave

#51 lore raw
Quoted 7 lines · Dave Jones

Perhaps add a printk somewhere to show that it's actually been enabled maybe ?

Also, would it be feasible to add something like we have for test_nx ? If this feature regresses in some way in the future, I suspect we'd like to know about it sooner rather than later.

Good idea... should add this both for SMEP and SMAP.

-hpa

#52 lore raw
Quoted 10 lines · H. Peter Anvin
Quoted 7 lines · Dave Jones

Perhaps add a printk somewhere to show that it's actually been enabled maybe ?

Also, would it be feasible to add something like we have for test_nx ? If this feature regresses in some way in the future, I suspect we'd like to know about it sooner rather than later.

Good idea... should add this both for SMEP and SMAP.

Very much agreed - these exploit preventation hardware features are really useful, and it's good to inform the user that they are active.

Thanks,

Ingo

#53 lore raw
Quoted 11 lines · Ingo Molnar
Quoted 8 lines · H. Peter Anvin
Quoted 6 lines · Dave Jones

Perhaps add a printk somewhere to show that it's actually been enabled maybe ?

Also, would it be feasible to add something like we have for test_nx ? If this feature regresses in some way in the future, I suspect we'd like to know about it sooner rather than later.

Quoted 6 lines
Quoted 1 line

Good idea... should add this both for SMEP and SMAP.

Very much agreed - these exploit preventation hardware features are really useful, and it's good to inform the user that they are active.

I was thinking about this, do you think a printk would be better, or a new field in /proc/cpuinfo?

-hpa

#54 lore raw
Quoted 14 lines · H. Peter Anvin
Quoted 13 lines · Ingo Molnar
Quoted 9 lines · H. Peter Anvin
Quoted 6 lines · Dave Jones

Perhaps add a printk somewhere to show that it's actually been enabled maybe ?

Also, would it be feasible to add something like we have for test_nx ? If this feature regresses in some way in the future, I suspect we'd like to know about it sooner rather than later.

Good idea... should add this both for SMEP and SMAP.

Quoted 7 lines
Quoted 4 lines

Very much agreed - these exploit preventation hardware features are really useful, and it's good to inform the user that they are active.

I was thinking about this, do you think a printk would be better, or a new field in /proc/cpuinfo?

We use printk for displaying the possible states of NX, however, this is rather ephemeral and scrolls away, making its harder for an admin to find later. It might make sense for a new field in cpuinfo for all three, however, unlike NX, the status of SMEP/SMAP isn't (normally) discoverable from userspace. That said, their CPU feature flags are already right there, and the cases where it would be disabled are very small.

How about this...

mem protection : nx smap smep

Maybe the "why" of a cpu feature being missing from the "mem protection" line can stay in printk?

-Kees

Signature · 2 lines
Kees Cook
Chrome OS Security
#55 lore raw
Quoted 8 lines · Kees Cook

How about this...

mem protection : nx smap smep

Maybe the "why" of a cpu feature being missing from the "mem protection" line can stay in printk?

Come to think about it, since we use setup_set/clear_cpu_cap we aready don't list the feature in /proc/cpuinfo already if it isn't enabled.

I would therefore suggest that we simply printk a message if the feature is disabled.

-hpa