Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a5b9e5a2 authored by Andy Lutomirski's avatar Andy Lutomirski Committed by Ingo Molnar
Browse files

x86/ldt: Make modify_ldt() optional



The modify_ldt syscall exposes a large attack surface and is
unnecessary for modern userspace.  Make it optional.

Signed-off-by: default avatarAndy Lutomirski <luto@kernel.org>
Reviewed-by: default avatarKees Cook <keescook@chromium.org>
Cc: Andrew Cooper <andrew.cooper3@citrix.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Jan Beulich <jbeulich@suse.com>
Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Sasha Levin <sasha.levin@oracle.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: security@kernel.org <security@kernel.org>
Cc: xen-devel <xen-devel@lists.xen.org>
Link: http://lkml.kernel.org/r/a605166a771c343fd64802dece77a903507333bd.1438291540.git.luto@kernel.org


[ Made MATH_EMULATION dependent on MODIFY_LDT_SYSCALL. ]
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent 014dc90b
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -1036,6 +1036,7 @@ config VM86
config X86_16BIT
	bool "Enable support for 16-bit segments" if EXPERT
	default y
	depends on MODIFY_LDT_SYSCALL
	---help---
	  This option is required by programs like Wine to run 16-bit
	  protected mode legacy code on x86 processors.  Disabling
@@ -1530,6 +1531,7 @@ config X86_RESERVE_LOW

config MATH_EMULATION
	bool
	depends on MODIFY_LDT_SYSCALL
	prompt "Math emulation" if X86_32
	---help---
	  Linux can emulate a math coprocessor (used for floating point
@@ -2074,6 +2076,22 @@ config CMDLINE_OVERRIDE
	  This is used to work around broken boot loaders.  This should
	  be set to 'N' under normal conditions.

config MODIFY_LDT_SYSCALL
	bool "Enable the LDT (local descriptor table)" if EXPERT
	default y
	---help---
	  Linux can allow user programs to install a per-process x86
	  Local Descriptor Table (LDT) using the modify_ldt(2) system
	  call.  This is required to run 16-bit or segmented code such as
	  DOSEMU or some Wine programs.  It is also used by some very old
	  threading libraries.

	  Enabling this feature adds a small amount of overhead to
	  context switches and increases the low-level kernel attack
	  surface.  Disabling it removes the modify_ldt(2) system call.

	  Saying 'N' here may make sense for embedded or server kernels.

source "kernel/livepatch/Kconfig"

endmenu
+2 −0
Original line number Diff line number Diff line
@@ -9,7 +9,9 @@
 * we put the segment information here.
 */
typedef struct {
#ifdef CONFIG_MODIFY_LDT_SYSCALL
	struct ldt_struct *ldt;
#endif

#ifdef CONFIG_X86_64
	/* True if mm supports a task running in 32 bit compatibility mode. */
+21 −7
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ static inline void load_mm_cr4(struct mm_struct *mm)
static inline void load_mm_cr4(struct mm_struct *mm) {}
#endif

#ifdef CONFIG_MODIFY_LDT_SYSCALL
/*
 * ldt_structs can be allocated, used, and freed, but they are never
 * modified while live.
@@ -48,8 +49,23 @@ struct ldt_struct {
	int size;
};

/*
 * Used for LDT copy/destruction.
 */
int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
void destroy_context(struct mm_struct *mm);
#else	/* CONFIG_MODIFY_LDT_SYSCALL */
static inline int init_new_context(struct task_struct *tsk,
				   struct mm_struct *mm)
{
	return 0;
}
static inline void destroy_context(struct mm_struct *mm) {}
#endif

static inline void load_mm_ldt(struct mm_struct *mm)
{
#ifdef CONFIG_MODIFY_LDT_SYSCALL
	struct ldt_struct *ldt;

	/* lockless_dereference synchronizes with smp_store_release */
@@ -73,17 +89,13 @@ static inline void load_mm_ldt(struct mm_struct *mm)
		set_ldt(ldt->entries, ldt->size);
	else
		clear_LDT();
#else
	clear_LDT();
#endif

	DEBUG_LOCKS_WARN_ON(preemptible());
}

/*
 * Used for LDT copy/destruction.
 */
int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
void destroy_context(struct mm_struct *mm);


static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
{
#ifdef CONFIG_SMP
@@ -114,6 +126,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
		/* Load per-mm CR4 state */
		load_mm_cr4(next);

#ifdef CONFIG_MODIFY_LDT_SYSCALL
		/*
		 * Load the LDT, if the LDT is different.
		 *
@@ -128,6 +141,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
		 */
		if (unlikely(prev->context.ldt != next->context.ldt))
			load_mm_ldt(next);
#endif
	}
#ifdef CONFIG_SMP
	  else {
+2 −1
Original line number Diff line number Diff line
@@ -25,7 +25,8 @@ CFLAGS_irq.o := -I$(src)/../include/asm/trace
obj-y			:= process_$(BITS).o signal.o
obj-$(CONFIG_COMPAT)	+= signal_compat.o
obj-y			+= traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o
obj-y			+= time.o ioport.o ldt.o dumpstack.o nmi.o
obj-y			+= time.o ioport.o dumpstack.o nmi.o
obj-$(CONFIG_MODIFY_LDT_SYSCALL)	+= ldt.o
obj-y			+= setup.o x86_init.o i8259.o irqinit.o jump_label.o
obj-$(CONFIG_IRQ_WORK)  += irq_work.o
obj-y			+= probe_roms.o
+4 −0
Original line number Diff line number Diff line
@@ -2179,6 +2179,7 @@ static unsigned long get_segment_base(unsigned int segment)
	int idx = segment >> 3;

	if ((segment & SEGMENT_TI_MASK) == SEGMENT_LDT) {
#ifdef CONFIG_MODIFY_LDT_SYSCALL
		struct ldt_struct *ldt;

		if (idx > LDT_ENTRIES)
@@ -2190,6 +2191,9 @@ static unsigned long get_segment_base(unsigned int segment)
			return 0;

		desc = &ldt->entries[idx];
#else
		return 0;
#endif
	} else {
		if (idx > GDT_ENTRIES)
			return 0;
Loading