Merge branch 'x86-pti-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 PTI and Spectre related fixes and updates from Ingo Molnar:
 "Here's the latest set of Spectre and PTI related fixes and updates:

  Spectre:
   - Add entry code register clearing to reduce the Spectre attack
     surface
   - Update the Spectre microcode blacklist
   - Inline the KVM Spectre helpers to get close to v4.14 performance
     again.
   - Fix indirect_branch_prediction_barrier()
   - Fix/improve Spectre related kernel messages
   - Fix array_index_nospec_mask() asm constraint
   - KVM: fix two MSR handling bugs

  PTI:
   - Fix a paranoid entry PTI CR3 handling bug
   - Fix comments

  objtool:
   - Fix paranoid_entry() frame pointer warning
   - Annotate WARN()-related UD2 as reachable
   - Various fixes
   - Add Add Peter Zijlstra as objtool co-maintainer

  Misc:
   - Various x86 entry code self-test fixes
   - Improve/simplify entry code stack frame generation and handling
     after recent heavy-handed PTI and Spectre changes. (There's two
     more WIP improvements expected here.)
   - Type fix for cache entries

  There's also some low risk non-fix changes I've included in this
  branch to reduce backporting conflicts:

   - rename a confusing x86_cpu field name
   - de-obfuscate the naming of single-TLB flushing primitives"

* 'x86-pti-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (41 commits)
  x86/entry/64: Fix CR3 restore in paranoid_exit()
  x86/cpu: Change type of x86_cache_size variable to unsigned int
  x86/spectre: Fix an error message
  x86/cpu: Rename cpu_data.x86_mask to cpu_data.x86_stepping
  selftests/x86/mpx: Fix incorrect bounds with old _sigfault
  x86/mm: Rename flush_tlb_single() and flush_tlb_one() to __flush_tlb_one_[user|kernel]()
  x86/speculation: Add <asm/msr-index.h> dependency
  nospec: Move array_index_nospec() parameter checking into separate macro
  x86/speculation: Fix up array_index_nospec_mask() asm constraint
  x86/debug: Use UD2 for WARN()
  x86/debug, objtool: Annotate WARN()-related UD2 as reachable
  objtool: Fix segfault in ignore_unreachable_insn()
  selftests/x86: Disable tests requiring 32-bit support on pure 64-bit systems
  selftests/x86: Do not rely on "int $0x80" in single_step_syscall.c
  selftests/x86: Do not rely on "int $0x80" in test_mremap_vdso.c
  selftests/x86: Fix build bug caused by the 5lvl test which has been moved to the VM directory
  selftests/x86/pkeys: Remove unused functions
  selftests/x86: Clean up and document sscanf() usage
  selftests/x86: Fix vDSO selftest segfault for vsyscall=none
  x86/entry/64: Remove the unused 'icebp' macro
  ...
This commit is contained in:
Linus Torvalds 2018-02-14 17:02:15 -08:00
commit d4667ca142
69 changed files with 444 additions and 362 deletions

View file

@ -5,16 +5,26 @@ include ../lib.mk
.PHONY: all all_32 all_64 warn_32bit_failure clean
TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_syscall test_mremap_vdso \
check_initial_reg_state sigreturn ldt_gdt iopl mpx-mini-test ioperm \
UNAME_M := $(shell uname -m)
CAN_BUILD_I386 := $(shell ./check_cc.sh $(CC) trivial_32bit_program.c -m32)
CAN_BUILD_X86_64 := $(shell ./check_cc.sh $(CC) trivial_64bit_program.c)
TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt test_mremap_vdso \
check_initial_reg_state sigreturn iopl mpx-mini-test ioperm \
protection_keys test_vdso test_vsyscall
TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso unwind_vdso \
test_FCMOV test_FCOMI test_FISTTP \
vdso_restorer
TARGETS_C_64BIT_ONLY := fsgsbase sysret_rip 5lvl
TARGETS_C_64BIT_ONLY := fsgsbase sysret_rip
# Some selftests require 32bit support enabled also on 64bit systems
TARGETS_C_32BIT_NEEDED := ldt_gdt ptrace_syscall
TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY)
TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY) $(TARGETS_C_32BIT_NEEDED)
TARGETS_C_64BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_64BIT_ONLY)
ifeq ($(CAN_BUILD_I386)$(CAN_BUILD_X86_64),11)
TARGETS_C_64BIT_ALL += $(TARGETS_C_32BIT_NEEDED)
endif
BINARIES_32 := $(TARGETS_C_32BIT_ALL:%=%_32)
BINARIES_64 := $(TARGETS_C_64BIT_ALL:%=%_64)
@ -23,10 +33,6 @@ BINARIES_64 := $(patsubst %,$(OUTPUT)/%,$(BINARIES_64))
CFLAGS := -O2 -g -std=gnu99 -pthread -Wall -no-pie
UNAME_M := $(shell uname -m)
CAN_BUILD_I386 := $(shell ./check_cc.sh $(CC) trivial_32bit_program.c -m32)
CAN_BUILD_X86_64 := $(shell ./check_cc.sh $(CC) trivial_64bit_program.c)
define gen-target-rule-32
$(1) $(1)_32: $(OUTPUT)/$(1)_32
.PHONY: $(1) $(1)_32
@ -40,12 +46,14 @@ endef
ifeq ($(CAN_BUILD_I386),1)
all: all_32
TEST_PROGS += $(BINARIES_32)
EXTRA_CFLAGS += -DCAN_BUILD_32
$(foreach t,$(TARGETS_C_32BIT_ALL),$(eval $(call gen-target-rule-32,$(t))))
endif
ifeq ($(CAN_BUILD_X86_64),1)
all: all_64
TEST_PROGS += $(BINARIES_64)
EXTRA_CFLAGS += -DCAN_BUILD_64
$(foreach t,$(TARGETS_C_64BIT_ALL),$(eval $(call gen-target-rule-64,$(t))))
endif

View file

@ -315,11 +315,39 @@ static inline void *__si_bounds_upper(siginfo_t *si)
return si->si_upper;
}
#else
/*
* This deals with old version of _sigfault in some distros:
*
old _sigfault:
struct {
void *si_addr;
} _sigfault;
new _sigfault:
struct {
void __user *_addr;
int _trapno;
short _addr_lsb;
union {
struct {
void __user *_lower;
void __user *_upper;
} _addr_bnd;
__u32 _pkey;
};
} _sigfault;
*
*/
static inline void **__si_bounds_hack(siginfo_t *si)
{
void *sigfault = &si->_sifields._sigfault;
void *end_sigfault = sigfault + sizeof(si->_sifields._sigfault);
void **__si_lower = end_sigfault;
int *trapno = (int*)end_sigfault;
/* skip _trapno and _addr_lsb */
void **__si_lower = (void**)(trapno + 2);
return __si_lower;
}
@ -331,7 +359,7 @@ static inline void *__si_bounds_lower(siginfo_t *si)
static inline void *__si_bounds_upper(siginfo_t *si)
{
return (*__si_bounds_hack(si)) + sizeof(void *);
return *(__si_bounds_hack(si) + 1);
}
#endif

View file

@ -393,34 +393,6 @@ pid_t fork_lazy_child(void)
return forkret;
}
void davecmp(void *_a, void *_b, int len)
{
int i;
unsigned long *a = _a;
unsigned long *b = _b;
for (i = 0; i < len / sizeof(*a); i++) {
if (a[i] == b[i])
continue;
dprintf3("[%3d]: a: %016lx b: %016lx\n", i, a[i], b[i]);
}
}
void dumpit(char *f)
{
int fd = open(f, O_RDONLY);
char buf[100];
int nr_read;
dprintf2("maps fd: %d\n", fd);
do {
nr_read = read(fd, &buf[0], sizeof(buf));
write(1, buf, nr_read);
} while (nr_read > 0);
close(fd);
}
#define PKEY_DISABLE_ACCESS 0x1
#define PKEY_DISABLE_WRITE 0x2

View file

@ -119,7 +119,9 @@ static void check_result(void)
int main()
{
#ifdef CAN_BUILD_32
int tmp;
#endif
sethandler(SIGTRAP, sigtrap, 0);
@ -139,12 +141,13 @@ int main()
: : "c" (post_nop) : "r11");
check_result();
#endif
#ifdef CAN_BUILD_32
printf("[RUN]\tSet TF and check int80\n");
set_eflags(get_eflags() | X86_EFLAGS_TF);
asm volatile ("int $0x80" : "=a" (tmp) : "a" (SYS_getpid)
: INT80_CLOBBERS);
check_result();
#endif
/*
* This test is particularly interesting if fast syscalls use

View file

@ -90,8 +90,12 @@ int main(int argc, char **argv, char **envp)
vdso_size += PAGE_SIZE;
}
#ifdef __i386__
/* Glibc is likely to explode now - exit with raw syscall */
asm volatile ("int $0x80" : : "a" (__NR_exit), "b" (!!ret));
#else /* __x86_64__ */
syscall(SYS_exit, ret);
#endif
} else {
int status;

View file

@ -26,20 +26,59 @@
# endif
#endif
int nerrs = 0;
/* max length of lines in /proc/self/maps - anything longer is skipped here */
#define MAPS_LINE_LEN 128
#ifdef __x86_64__
# define VSYS(x) (x)
#else
# define VSYS(x) 0
#endif
int nerrs = 0;
typedef long (*getcpu_t)(unsigned *, unsigned *, void *);
const getcpu_t vgetcpu = (getcpu_t)VSYS(0xffffffffff600800);
getcpu_t vgetcpu;
getcpu_t vdso_getcpu;
void fill_function_pointers()
static void *vsyscall_getcpu(void)
{
#ifdef __x86_64__
FILE *maps;
char line[MAPS_LINE_LEN];
bool found = false;
maps = fopen("/proc/self/maps", "r");
if (!maps) /* might still be present, but ignore it here, as we test vDSO not vsyscall */
return NULL;
while (fgets(line, MAPS_LINE_LEN, maps)) {
char r, x;
void *start, *end;
char name[MAPS_LINE_LEN];
/* sscanf() is safe here as strlen(name) >= strlen(line) */
if (sscanf(line, "%p-%p %c-%cp %*x %*x:%*x %*u %s",
&start, &end, &r, &x, name) != 5)
continue;
if (strcmp(name, "[vsyscall]"))
continue;
/* assume entries are OK, as we test vDSO here not vsyscall */
found = true;
break;
}
fclose(maps);
if (!found) {
printf("Warning: failed to find vsyscall getcpu\n");
return NULL;
}
return (void *) (0xffffffffff600800);
#else
return NULL;
#endif
}
static void fill_function_pointers()
{
void *vdso = dlopen("linux-vdso.so.1",
RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
@ -54,6 +93,8 @@ void fill_function_pointers()
vdso_getcpu = (getcpu_t)dlsym(vdso, "__vdso_getcpu");
if (!vdso_getcpu)
printf("Warning: failed to find getcpu in vDSO\n");
vgetcpu = (getcpu_t) vsyscall_getcpu();
}
static long sys_getcpu(unsigned * cpu, unsigned * node,

View file

@ -33,6 +33,9 @@
# endif
#endif
/* max length of lines in /proc/self/maps - anything longer is skipped here */
#define MAPS_LINE_LEN 128
static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
int flags)
{
@ -98,7 +101,7 @@ static int init_vsys(void)
#ifdef __x86_64__
int nerrs = 0;
FILE *maps;
char line[128];
char line[MAPS_LINE_LEN];
bool found = false;
maps = fopen("/proc/self/maps", "r");
@ -108,10 +111,12 @@ static int init_vsys(void)
return 0;
}
while (fgets(line, sizeof(line), maps)) {
while (fgets(line, MAPS_LINE_LEN, maps)) {
char r, x;
void *start, *end;
char name[128];
char name[MAPS_LINE_LEN];
/* sscanf() is safe here as strlen(name) >= strlen(line) */
if (sscanf(line, "%p-%p %c-%cp %*x %*x:%*x %*u %s",
&start, &end, &r, &x, name) != 5)
continue;