[ 10/25] x86, espfix: Make it possible to disable 16-bit support

From: Willy Tarreau
Date: Sat Dec 06 2014 - 13:00:47 EST


2.6.32-longterm review patch. If anyone has any objections, please let me know.

------------------

From: "H. Peter Anvin" <hpa@xxxxxxxxx>

commit 34273f41d57ee8d854dcd2a1d754cbb546cb548f upstream.

Embedded systems, which may be very memory-size-sensitive, are
extremely unlikely to ever encounter any 16-bit software, so make it
a CONFIG_EXPERT option to turn off support for any 16-bit software
whatsoever.

Signed-off-by: H. Peter Anvin <hpa@xxxxxxxxx>
Link: http://lkml.kernel.org/r/1398816946-3351-1-git-send-email-hpa@xxxxxxxxxxxxxxx
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
Signed-off-by: Ben Hutchings <ben@xxxxxxxxxxxxxxx>
(cherry picked from 3.2 commit 70d87cbbd92a3611655b39003176ee1033796bf7)
[wt: backport notes for 2.6.32 :
- Fixed arch/x86/kernel/ldt.c (no IS_ENABLED on 2.6.32).
- No CONFIG_EXPERT condition in 2.6.32.
/wt]
Signed-off-by: Willy Tarreau <w@xxxxxx>
---
arch/x86/Kconfig | 23 ++++++++++++++++++-----
arch/x86/kernel/entry_32.S | 12 ++++++++++++
arch/x86/kernel/entry_64.S | 8 ++++++++
arch/x86/kernel/ldt.c | 6 ++++++
4 files changed, 44 insertions(+), 5 deletions(-)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 026fe60..67c3187 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -882,14 +882,27 @@ config VM86
default y
depends on X86_32
---help---
- This option is required by programs like DOSEMU to run 16-bit legacy
- code on X86 processors. It also may be needed by software like
- XFree86 to initialize some video cards via BIOS. Disabling this
- option saves about 6k.
+ This option is required by programs like DOSEMU to run
+ 16-bit real mode legacy code on x86 processors. It also may
+ be needed by software like XFree86 to initialize some video
+ cards via BIOS. Disabling this option saves about 6K.
+
+config X86_16BIT
+ bool "Enable support for 16-bit segments"
+ default y
+ ---help---
+ This option is required by programs like Wine to run 16-bit
+ protected mode legacy code on x86 processors. Disabling
+ this option saves about 300 bytes on i386, or around 6K text
+ plus 16K runtime memory on x86-64,
+
+config X86_ESPFIX32
+ def_bool y
+ depends on X86_16BIT && X86_32

config X86_ESPFIX64
def_bool y
- depends on X86_64
+ depends on X86_16BIT && X86_64

config TOSHIBA
tristate "Toshiba Laptop support"
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index db7dbe7..c1207f7 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -543,6 +543,7 @@ syscall_exit:
restore_all:
TRACE_IRQS_IRET
restore_all_notrace:
+#ifdef CONFIG_X86_ESPFIX32
movl PT_EFLAGS(%esp), %eax # mix EFLAGS, SS and CS
# Warning: PT_OLDSS(%esp) contains the wrong/random values if we
# are returning to the kernel.
@@ -553,6 +554,7 @@ restore_all_notrace:
cmpl $((SEGMENT_LDT << 8) | USER_RPL), %eax
CFI_REMEMBER_STATE
je ldt_ss # returning to user-space with LDT SS
+#endif
restore_nocheck:
RESTORE_REGS 4 # skip orig_eax/error_code
CFI_ADJUST_CFA_OFFSET -4
@@ -569,6 +571,7 @@ ENTRY(iret_exc)
.long irq_return,iret_exc
.previous

+#ifdef CONFIG_X86_ESPFIX32
CFI_RESTORE_STATE
ldt_ss:
#ifdef CONFIG_PARAVIRT
@@ -614,6 +617,7 @@ ldt_ss:
lss (%esp), %esp /* switch to espfix segment */
CFI_ADJUST_CFA_OFFSET -8
jmp restore_nocheck
+#endif
CFI_ENDPROC
ENDPROC(system_call)

@@ -736,6 +740,7 @@ PTREGSCALL(vm86old)
* the high word of the segment base from the GDT and swiches to the
* normal stack and adjusts ESP with the matching offset.
*/
+#ifdef CONFIG_X86_ESPFIX32
/* fixup the stack */
PER_CPU(gdt_page, %ebx)
mov GDT_ENTRY_ESPFIX_SS * 8 + 4(%ebx), %al /* bits 16..23 */
@@ -748,8 +753,10 @@ PTREGSCALL(vm86old)
CFI_ADJUST_CFA_OFFSET 4
lss (%esp), %esp /* switch to the normal stack segment */
CFI_ADJUST_CFA_OFFSET -8
+#endif
.endm
.macro UNWIND_ESPFIX_STACK
+#ifdef CONFIG_X86_ESPFIX32
movl %ss, %eax
/* see if on espfix stack */
cmpw $__ESPFIX_SS, %ax
@@ -760,6 +767,7 @@ PTREGSCALL(vm86old)
/* switch to normal stack */
FIXUP_ESPFIX_STACK
27:
+#endif
.endm

/*
@@ -1323,6 +1331,7 @@ END(debug)
*/
ENTRY(nmi)
RING0_INT_FRAME
+#ifdef CONFIG_X86_ESPFIX32
pushl %eax
CFI_ADJUST_CFA_OFFSET 4
movl %ss, %eax
@@ -1330,6 +1339,7 @@ ENTRY(nmi)
popl %eax
CFI_ADJUST_CFA_OFFSET -4
je nmi_espfix_stack
+#endif
cmpl $ia32_sysenter_target,(%esp)
je nmi_stack_fixup
pushl %eax
@@ -1372,6 +1382,7 @@ nmi_debug_stack_check:
FIX_STACK 24, nmi_stack_correct, 1
jmp nmi_stack_correct

+#ifdef CONFIG_X86_ESPFIX32
nmi_espfix_stack:
/* We have a RING0_INT_FRAME here.
*
@@ -1397,6 +1408,7 @@ nmi_espfix_stack:
lss 12+4(%esp), %esp # back to espfix stack
CFI_ADJUST_CFA_OFFSET -24
jmp irq_return
+#endif
CFI_ENDPROC
END(nmi)

diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index a69901e..cf9e7d2 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -863,8 +863,10 @@ irq_return:
* Are we returning to a stack segment from the LDT? Note: in
* 64-bit mode SS:RSP on the exception stack is always valid.
*/
+#ifdef CONFIG_X86_ESPFIX64
testb $4,(SS-RIP)(%rsp)
jnz irq_return_ldt
+#endif

irq_return_iret:
INTERRUPT_RETURN
@@ -882,6 +884,7 @@ ENTRY(native_iret)
.previous
#endif

+#ifdef CONFIG_X86_ESPFIX64
irq_return_ldt:
pushq_cfi %rax
pushq_cfi %rdi
@@ -905,6 +908,7 @@ irq_return_ldt:
movq %rax,%rsp
popq_cfi %rax
jmp irq_return_iret
+#endif

.section .fixup,"ax"
bad_iret:
@@ -980,6 +984,7 @@ END(common_interrupt)
* modify the stack to make it look like we just entered
* the #GP handler from user space, similar to bad_iret.
*/
+#ifdef CONFIG_X86_ESPFIX64
ALIGN
__do_double_fault:
XCPT_FRAME 1 RDI+8
@@ -1005,6 +1010,9 @@ __do_double_fault:
retq
CFI_ENDPROC
END(__do_double_fault)
+#else
+# define __do_double_fault do_double_fault
+#endif

/*
* APIC interrupts.
diff --git a/arch/x86/kernel/ldt.c b/arch/x86/kernel/ldt.c
index ec6ef60..4e668bb 100644
--- a/arch/x86/kernel/ldt.c
+++ b/arch/x86/kernel/ldt.c
@@ -229,6 +229,12 @@ static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode)
}
}

+#ifndef CONFIG_X86_16BIT
+ if (!ldt_info.seg_32bit) {
+ error = -EINVAL;
+ goto out_unlock;
+ }
+#endif
fill_ldt(&ldt, &ldt_info);
if (oldmode)
ldt.avl = 0;
--
1.7.12.2.21.g234cd45.dirty



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