diff options
Diffstat (limited to 'tools/testing/selftests/x86')
| -rw-r--r-- | tools/testing/selftests/x86/Makefile | 24 | ||||
| -rw-r--r-- | tools/testing/selftests/x86/entry_from_vm86.c | 32 | ||||
| -rw-r--r-- | tools/testing/selftests/x86/mpx-mini-test.c | 32 | ||||
| -rw-r--r-- | tools/testing/selftests/x86/protection_keys.c | 28 | ||||
| -rw-r--r-- | tools/testing/selftests/x86/ptrace_syscall.c | 8 | ||||
| -rw-r--r-- | tools/testing/selftests/x86/single_step_syscall.c | 5 | ||||
| -rw-r--r-- | tools/testing/selftests/x86/test_mremap_vdso.c | 4 | ||||
| -rw-r--r-- | tools/testing/selftests/x86/test_vdso.c | 55 | ||||
| -rw-r--r-- | tools/testing/selftests/x86/test_vsyscall.c | 22 | 
9 files changed, 150 insertions, 60 deletions
diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile index 10ca46df1449..d744991c0f4f 100644 --- a/tools/testing/selftests/x86/Makefile +++ b/tools/testing/selftests/x86/Makefile @@ -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 diff --git a/tools/testing/selftests/x86/entry_from_vm86.c b/tools/testing/selftests/x86/entry_from_vm86.c index 361466a2eaef..ade443a88421 100644 --- a/tools/testing/selftests/x86/entry_from_vm86.c +++ b/tools/testing/selftests/x86/entry_from_vm86.c @@ -95,6 +95,10 @@ asm (  	"int3\n\t"  	"vmcode_int80:\n\t"  	"int $0x80\n\t" +	"vmcode_popf_hlt:\n\t" +	"push %ax\n\t" +	"popf\n\t" +	"hlt\n\t"  	"vmcode_umip:\n\t"  	/* addressing via displacements */  	"smsw (2052)\n\t" @@ -124,8 +128,8 @@ asm (  extern unsigned char vmcode[], end_vmcode[];  extern unsigned char vmcode_bound[], vmcode_sysenter[], vmcode_syscall[], -	vmcode_sti[], vmcode_int3[], vmcode_int80[], vmcode_umip[], -	vmcode_umip_str[], vmcode_umip_sldt[]; +	vmcode_sti[], vmcode_int3[], vmcode_int80[], vmcode_popf_hlt[], +	vmcode_umip[], vmcode_umip_str[], vmcode_umip_sldt[];  /* Returns false if the test was skipped. */  static bool do_test(struct vm86plus_struct *v86, unsigned long eip, @@ -175,7 +179,7 @@ static bool do_test(struct vm86plus_struct *v86, unsigned long eip,  	    (VM86_TYPE(ret) == rettype && VM86_ARG(ret) == retarg)) {  		printf("[OK]\tReturned correctly\n");  	} else { -		printf("[FAIL]\tIncorrect return reason\n"); +		printf("[FAIL]\tIncorrect return reason (started at eip = 0x%lx, ended at eip = 0x%lx)\n", eip, v86->regs.eip);  		nerrs++;  	} @@ -264,6 +268,9 @@ int main(void)  	v86.regs.ds = load_addr / 16;  	v86.regs.es = load_addr / 16; +	/* Use the end of the page as our stack. */ +	v86.regs.esp = 4096; +  	assert((v86.regs.cs & 3) == 0);	/* Looks like RPL = 0 */  	/* #BR -- should deliver SIG??? */ @@ -295,6 +302,23 @@ int main(void)  	v86.regs.eflags &= ~X86_EFLAGS_IF;  	do_test(&v86, vmcode_sti - vmcode, VM86_STI, 0, "STI with VIP set"); +	/* POPF with VIP set but IF clear: should not trap */ +	v86.regs.eflags = X86_EFLAGS_VIP; +	v86.regs.eax = 0; +	do_test(&v86, vmcode_popf_hlt - vmcode, VM86_UNKNOWN, 0, "POPF with VIP set and IF clear"); + +	/* POPF with VIP set and IF set: should trap */ +	v86.regs.eflags = X86_EFLAGS_VIP; +	v86.regs.eax = X86_EFLAGS_IF; +	do_test(&v86, vmcode_popf_hlt - vmcode, VM86_STI, 0, "POPF with VIP and IF set"); + +	/* POPF with VIP clear and IF set: should not trap */ +	v86.regs.eflags = 0; +	v86.regs.eax = X86_EFLAGS_IF; +	do_test(&v86, vmcode_popf_hlt - vmcode, VM86_UNKNOWN, 0, "POPF with VIP clear and IF set"); + +	v86.regs.eflags = 0; +  	/* INT3 -- should cause #BP */  	do_test(&v86, vmcode_int3 - vmcode, VM86_TRAP, 3, "INT3"); @@ -318,7 +342,7 @@ int main(void)  	clearhandler(SIGSEGV);  	/* Make sure nothing explodes if we fork. */ -	if (fork() > 0) +	if (fork() == 0)  		return 0;  	return (nerrs == 0 ? 0 : 1); diff --git a/tools/testing/selftests/x86/mpx-mini-test.c b/tools/testing/selftests/x86/mpx-mini-test.c index ec0f6b45ce8b..9c0325e1ea68 100644 --- a/tools/testing/selftests/x86/mpx-mini-test.c +++ b/tools/testing/selftests/x86/mpx-mini-test.c @@ -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 diff --git a/tools/testing/selftests/x86/protection_keys.c b/tools/testing/selftests/x86/protection_keys.c index bc1b0735bb50..f15aa5a76fe3 100644 --- a/tools/testing/selftests/x86/protection_keys.c +++ b/tools/testing/selftests/x86/protection_keys.c @@ -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 diff --git a/tools/testing/selftests/x86/ptrace_syscall.c b/tools/testing/selftests/x86/ptrace_syscall.c index 1ae1c5a7392e..6f22238f3217 100644 --- a/tools/testing/selftests/x86/ptrace_syscall.c +++ b/tools/testing/selftests/x86/ptrace_syscall.c @@ -183,8 +183,10 @@ static void test_ptrace_syscall_restart(void)  		if (ptrace(PTRACE_TRACEME, 0, 0, 0) != 0)  			err(1, "PTRACE_TRACEME"); +		pid_t pid = getpid(), tid = syscall(SYS_gettid); +  		printf("\tChild will make one syscall\n"); -		raise(SIGSTOP); +		syscall(SYS_tgkill, pid, tid, SIGSTOP);  		syscall(SYS_gettid, 10, 11, 12, 13, 14, 15);  		_exit(0); @@ -301,9 +303,11 @@ static void test_restart_under_ptrace(void)  		if (ptrace(PTRACE_TRACEME, 0, 0, 0) != 0)  			err(1, "PTRACE_TRACEME"); +		pid_t pid = getpid(), tid = syscall(SYS_gettid); +  		printf("\tChild will take a nap until signaled\n");  		setsigign(SIGUSR1, SA_RESTART); -		raise(SIGSTOP); +		syscall(SYS_tgkill, pid, tid, SIGSTOP);  		syscall(SYS_pause, 0, 0, 0, 0, 0, 0);  		_exit(0); diff --git a/tools/testing/selftests/x86/single_step_syscall.c b/tools/testing/selftests/x86/single_step_syscall.c index a48da95c18fd..ddfdd635de16 100644 --- a/tools/testing/selftests/x86/single_step_syscall.c +++ b/tools/testing/selftests/x86/single_step_syscall.c @@ -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 diff --git a/tools/testing/selftests/x86/test_mremap_vdso.c b/tools/testing/selftests/x86/test_mremap_vdso.c index bf0d687c7db7..64f11c8d9b76 100644 --- a/tools/testing/selftests/x86/test_mremap_vdso.c +++ b/tools/testing/selftests/x86/test_mremap_vdso.c @@ -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; diff --git a/tools/testing/selftests/x86/test_vdso.c b/tools/testing/selftests/x86/test_vdso.c index 29973cde06d3..235259011704 100644 --- a/tools/testing/selftests/x86/test_vdso.c +++ b/tools/testing/selftests/x86/test_vdso.c @@ -26,20 +26,59 @@  # endif  #endif +/* max length of lines in /proc/self/maps - anything longer is skipped here */ +#define MAPS_LINE_LEN 128 +  int nerrs = 0; +typedef long (*getcpu_t)(unsigned *, unsigned *, void *); + +getcpu_t vgetcpu; +getcpu_t vdso_getcpu; + +static void *vsyscall_getcpu(void) +{  #ifdef __x86_64__ -# define VSYS(x) (x) +	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 -# define VSYS(x) 0 +	return NULL;  #endif +} -typedef long (*getcpu_t)(unsigned *, unsigned *, void *); - -const getcpu_t vgetcpu = (getcpu_t)VSYS(0xffffffffff600800); -getcpu_t vdso_getcpu; -void fill_function_pointers() +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, diff --git a/tools/testing/selftests/x86/test_vsyscall.c b/tools/testing/selftests/x86/test_vsyscall.c index 7a744fa7b786..0b4f1cc2291c 100644 --- a/tools/testing/selftests/x86/test_vsyscall.c +++ b/tools/testing/selftests/x86/test_vsyscall.c @@ -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; @@ -445,7 +450,7 @@ static void sigtrap(int sig, siginfo_t *info, void *ctx_void)  		num_vsyscall_traps++;  } -static int test_native_vsyscall(void) +static int test_emulation(void)  {  	time_t tmp;  	bool is_native; @@ -453,7 +458,7 @@ static int test_native_vsyscall(void)  	if (!vtime)  		return 0; -	printf("[RUN]\tchecking for native vsyscall\n"); +	printf("[RUN]\tchecking that vsyscalls are emulated\n");  	sethandler(SIGTRAP, sigtrap, 0);  	set_eflags(get_eflags() | X86_EFLAGS_TF);  	vtime(&tmp); @@ -469,11 +474,12 @@ static int test_native_vsyscall(void)  	 */  	is_native = (num_vsyscall_traps > 1); -	printf("\tvsyscalls are %s (%d instructions in vsyscall page)\n", +	printf("[%s]\tvsyscalls are %s (%d instructions in vsyscall page)\n", +	       (is_native ? "FAIL" : "OK"),  	       (is_native ? "native" : "emulated"),  	       (int)num_vsyscall_traps); -	return 0; +	return is_native;  }  #endif @@ -493,7 +499,7 @@ int main(int argc, char **argv)  	nerrs += test_vsys_r();  #ifdef __x86_64__ -	nerrs += test_native_vsyscall(); +	nerrs += test_emulation();  #endif  	return nerrs ? 1 : 0;  | 

