lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <54FDC9C6.3090102@osg.samsung.com>
Date:	Mon, 09 Mar 2015 10:26:46 -0600
From:	Shuah Khan <shuahkh@....samsung.com>
To:	Andy Lutomirski <luto@...capital.net>, x86@...nel.org,
	linux-kernel@...r.kernel.org
CC:	Steven Rostedt <rostedt@...dmis.org>,
	Denys Vlasenko <vda.linux@...glemail.com>,
	Shuah Khan <shuah.kh@...sung.com>,
	Borislav Petkov <bp@...en8.de>
Subject: Re: [PATCH] x86, selftests: Add sigreturn_32 selftest

On 03/09/2015 10:08 AM, Andy Lutomirski wrote:
> This is my sigreturn test, added mostly unchanged from its old home.
> 
> The integration with the selftest build process seems okay if not
> particularly elegant.
> 
> I'm not using the ksft_ helpers at all yet.  I can do that later.

Andy,

Could you please write a brief description of what the test does
for a commit log. What you have for a commit log isn't very useful
and serves as notes for reviewers.

-- Shuah
> 
> Signed-off-by: Andy Lutomirski <luto@...capital.net>
> ---
>  tools/testing/selftests/Makefile         |   1 +
>  tools/testing/selftests/x86/.gitignore   |   2 +
>  tools/testing/selftests/x86/Makefile     |  18 ++
>  tools/testing/selftests/x86/run_tests.sh |   6 +
>  tools/testing/selftests/x86/sigreturn.c  | 531 +++++++++++++++++++++++++++++++
>  5 files changed, 558 insertions(+)
>  create mode 100644 tools/testing/selftests/x86/.gitignore
>  create mode 100644 tools/testing/selftests/x86/Makefile
>  create mode 100755 tools/testing/selftests/x86/run_tests.sh
>  create mode 100644 tools/testing/selftests/x86/sigreturn.c
> 
> diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
> index 4e511221a0c1..2ad56d451469 100644
> --- a/tools/testing/selftests/Makefile
> +++ b/tools/testing/selftests/Makefile
> @@ -17,6 +17,7 @@ TARGETS += sysctl
>  TARGETS += timers
>  TARGETS += user
>  TARGETS += vm
> +TARGETS += x86
>  #Please keep the TARGETS list alphabetically sorted
>  
>  TARGETS_HOTPLUG = cpu-hotplug
> diff --git a/tools/testing/selftests/x86/.gitignore b/tools/testing/selftests/x86/.gitignore
> new file mode 100644
> index 000000000000..15034fef9698
> --- /dev/null
> +++ b/tools/testing/selftests/x86/.gitignore
> @@ -0,0 +1,2 @@
> +*_32
> +*_64
> diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile
> new file mode 100644
> index 000000000000..3c4fc3158ddc
> --- /dev/null
> +++ b/tools/testing/selftests/x86/Makefile
> @@ -0,0 +1,18 @@
> +.PHONY: all clean run_tests
> +
> +TARGETS_C_32ONLY := sigreturn
> +
> +BINARIES := $(TARGETS_C_32ONLY:%=%_32)
> +
> +CFLAGS := -O2 -g -std=gnu99 -pthread -Wall
> +
> +all: $(BINARIES)
> +
> +clean:
> +	$(RM) $(BINARIES)
> +
> +run_tests:
> +	./run_tests.sh
> +
> +$(TARGETS_C_32ONLY:%=%_32): %_32: %.c
> +	gcc -m32 -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl
> diff --git a/tools/testing/selftests/x86/run_tests.sh b/tools/testing/selftests/x86/run_tests.sh
> new file mode 100755
> index 000000000000..2dd495300363
> --- /dev/null
> +++ b/tools/testing/selftests/x86/run_tests.sh
> @@ -0,0 +1,6 @@
> +#!/bin/bash
> +
> +# This is deliberately minimal.  IMO kselftests should provide a standard
> +# script here.
> +./sigreturn_32
> +exit $?
> diff --git a/tools/testing/selftests/x86/sigreturn.c b/tools/testing/selftests/x86/sigreturn.c
> new file mode 100644
> index 000000000000..655cc35847f5
> --- /dev/null
> +++ b/tools/testing/selftests/x86/sigreturn.c
> @@ -0,0 +1,531 @@
> +/*
> + * Sigreturn test.
> + * Copyright (c) 2014-2015 Andrew Lutomirski.
> + *
> + * This abuses sigreturn to test interesting cases when returning to
> + * user space.  It exercises espfix and various iret exceptions.
> + *
> + * GPL v2.
> + */
> +
> +#define _GNU_SOURCE
> +
> +#include <sys/time.h>
> +#include <time.h>
> +#include <stdlib.h>
> +#include <sys/syscall.h>
> +#include <unistd.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <inttypes.h>
> +#include <sys/mman.h>
> +#include <sys/signal.h>
> +#include <sys/ucontext.h>
> +#include <asm/ldt.h>
> +#include <err.h>
> +#include <setjmp.h>
> +#include <stddef.h>
> +#include <stdbool.h>
> +#include <sys/ptrace.h>
> +#include <sys/user.h>
> +
> +struct selectors {
> +	unsigned short cs, gs, fs, ss;
> +};
> +
> +static bool has_code16, has_data16, has_npcode32, has_npdata32;
> +
> +static int gdt_data16_idx, gdt_npdata32_idx;
> +
> +static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
> +		       int flags)
> +{
> +	struct sigaction sa;
> +
> +	memset(&sa, 0, sizeof(sa));
> +	sa.sa_sigaction = handler;
> +	sa.sa_flags = SA_SIGINFO | flags;
> +	sigemptyset(&sa.sa_mask);
> +	if (sigaction(sig, &sa, 0))
> +		err(1, "sigaction");
> +}
> +
> +static void clearhandler(int sig)
> +{
> +	struct sigaction sa;
> +
> +	memset(&sa, 0, sizeof(sa));
> +	sa.sa_handler = SIG_DFL;
> +	sigemptyset(&sa.sa_mask);
> +	if (sigaction(sig, &sa, 0))
> +		err(1, "sigaction");
> +}
> +
> +static unsigned char stack16[65536] __attribute__((aligned(4096)));
> +
> +asm (".pushsection .text\n\t"
> +     ".type int3, @function\n\t"
> +     ".align 4096\n\t"
> +     "int3:\n\t"
> +     "mov %ss,%eax\n\t"
> +     "int3\n\t"
> +     ".size int3, . - int3\n\t"
> +     ".align 4096, 0xcc\n\t"
> +     ".popsection");
> +extern char int3[4096];
> +
> +static void add_ldt(const struct user_desc *desc, bool *var, const char *name)
> +{
> +	if (syscall(SYS_modify_ldt, 1, desc, sizeof(*desc)) == 0) {
> +		*var = true;
> +	} else {
> +		printf("[NOTE]\tFailed to create %s segment\n", name);
> +		*var = false;
> +	}
> +}
> +
> +static void setup_ldt(void)
> +{
> +	if ((unsigned long)stack16 > (1ULL << 32) - sizeof(stack16))
> +		errx(1, "stack16 is too high\n");
> +	if ((unsigned long)int3 > (1ULL << 32) - sizeof(int3))
> +		errx(1, "int3 is too high\n");
> +
> +	/* Borrowed from a test case by hpa */
> +	const struct user_desc code16_desc = {
> +		.entry_number    = 0,
> +		.base_addr       = (unsigned long)int3,
> +		.limit           = 4095,
> +		.seg_32bit       = 0,
> +		.contents        = 2, /* Code, not conforming */
> +		.read_exec_only  = 0,
> +		.limit_in_pages  = 0,
> +		.seg_not_present = 0,
> +		.useable         = 0
> +	};
> +	add_ldt(&code16_desc, &has_code16, "code16");
> +
> +	const struct user_desc data16_desc = {
> +		.entry_number    = 1,
> +		.base_addr       = (unsigned long)stack16,
> +		.limit           = 0xffff,
> +		.seg_32bit       = 0,
> +		.contents        = 0, /* Data, grow-up */
> +		.read_exec_only  = 0,
> +		.limit_in_pages  = 0,
> +		.seg_not_present = 0,
> +		.useable         = 0
> +	};
> +	add_ldt(&data16_desc, &has_data16, "data16");
> +
> +	const struct user_desc npcode32_desc = {
> +		.entry_number    = 3,
> +		.base_addr       = (unsigned long)int3,
> +		.limit           = 4095,
> +		.seg_32bit       = 1,
> +		.contents        = 2, /* Code, not conforming */
> +		.read_exec_only  = 0,
> +		.limit_in_pages  = 0,
> +		.seg_not_present = 1,
> +		.useable         = 0
> +	};
> +	add_ldt(&npcode32_desc, &has_npcode32, "npcode32");
> +
> +	const struct user_desc npdata32_desc = {
> +		.entry_number    = 4,
> +		.base_addr       = (unsigned long)stack16,
> +		.limit           = 0xffff,
> +		.seg_32bit       = 1,
> +		.contents        = 0, /* Data, grow-up */
> +		.read_exec_only  = 0,
> +		.limit_in_pages  = 0,
> +		.seg_not_present = 1,
> +		.useable         = 0
> +	};
> +	add_ldt(&npdata32_desc, &has_npdata32, "npdata32");
> +
> +	struct user_desc gdt_data16_desc = {
> +		.entry_number    = -1,
> +		.base_addr       = (unsigned long)stack16,
> +		.limit           = 0xffff,
> +		.seg_32bit       = 0,
> +		.contents        = 0, /* Data, grow-up */
> +		.read_exec_only  = 0,
> +		.limit_in_pages  = 0,
> +		.seg_not_present = 0,
> +		.useable         = 0
> +	};
> +
> +	if (syscall(SYS_set_thread_area, &gdt_data16_desc) == 0) {
> +		printf("[WARN]\tset_thread_area allocated data16 at index %d\n",
> +		       gdt_data16_desc.entry_number);
> +		gdt_data16_idx = gdt_data16_desc.entry_number;
> +	} else {
> +		printf("[OK]\tset_thread_area refused 16-bit data\n");
> +	}
> +
> +	struct user_desc gdt_npdata32_desc = {
> +		.entry_number    = -1,
> +		.base_addr       = (unsigned long)stack16,
> +		.limit           = 0xffff,
> +		.seg_32bit       = 1,
> +		.contents        = 0, /* Data, grow-up */
> +		.read_exec_only  = 0,
> +		.limit_in_pages  = 0,
> +		.seg_not_present = 1,
> +		.useable         = 0
> +	};
> +
> +	if (syscall(SYS_set_thread_area, &gdt_npdata32_desc) == 0) {
> +		printf("[WARN]\tset_thread_area allocated npdata32 at index %d\n",
> +		       gdt_npdata32_desc.entry_number);
> +		gdt_npdata32_idx = gdt_npdata32_desc.entry_number;
> +	} else {
> +		printf("[OK]\tset_thread_area refused 16-bit data\n");
> +	}
> +}
> +
> +static gregset_t initial_regs, requested_regs, resulting_regs;
> +
> +/* Per POSIX, these should be volatile sigatomic_t.  Go away, pedants. */
> +static volatile unsigned short sig_cs, sig_ss;
> +static volatile sig_atomic_t sig_trapped, sig_err, sig_trapno;
> +
> +#ifdef __x86_64__
> +# define REG_IP REG_RIP
> +# define REG_SP REG_RSP
> +# define REG_AX REG_RAX
> +
> +static unsigned short *ssptr(ucontext_t *ctx)
> +{
> +	struct selectors *sels = (void *)&ctx->uc_mcontext.gregs[REG_CSGSFS];
> +	return &sels->ss;
> +}
> +
> +static unsigned short *csptr(ucontext_t *ctx)
> +{
> +	struct selectors *sels = (void *)&ctx->uc_mcontext.gregs[REG_CSGSFS];
> +	return &sels->cs;
> +}
> +#else
> +# define REG_IP REG_EIP
> +# define REG_SP REG_ESP
> +# define REG_AX REG_EAX
> +
> +static greg_t *ssptr(ucontext_t *ctx)
> +{
> +	return &ctx->uc_mcontext.gregs[REG_SS];
> +}
> +
> +static greg_t *csptr(ucontext_t *ctx)
> +{
> +	return &ctx->uc_mcontext.gregs[REG_CS];
> +}
> +#endif
> +
> +static int nerrs;
> +
> +static void sigusr1(int sig, siginfo_t *info, void *ctx_void)
> +{
> +	ucontext_t *ctx = (ucontext_t *)ctx_void;
> +
> +	memcpy(&initial_regs, &ctx->uc_mcontext.gregs, sizeof(gregset_t));
> +
> +	*csptr(ctx) = sig_cs;
> +	*ssptr(ctx) = sig_ss;
> +
> +	ctx->uc_mcontext.gregs[REG_IP] =
> +		(sig_cs == 0x7 || sig_cs == 0x1f) ? 0 : (unsigned long)&int3;
> +	ctx->uc_mcontext.gregs[REG_SP] = (unsigned long)0x8badf00d5aadc0deULL;
> +	ctx->uc_mcontext.gregs[REG_AX] = 0;
> +
> +	memcpy(&requested_regs, &ctx->uc_mcontext.gregs, sizeof(gregset_t));
> +	requested_regs[REG_AX] = *ssptr(ctx);	/* The asm code does this. */
> +
> +	return;
> +}
> +
> +static void sigtrap(int sig, siginfo_t *info, void *ctx_void)
> +{
> +	ucontext_t *ctx = (ucontext_t*)ctx_void;
> +
> +	sig_err = ctx->uc_mcontext.gregs[REG_ERR];
> +	sig_trapno = ctx->uc_mcontext.gregs[REG_TRAPNO];
> +
> +	unsigned short ss;
> +	asm ("mov %%ss,%0" : "=r" (ss));
> +
> +	greg_t asm_ss = ctx->uc_mcontext.gregs[REG_AX];
> +	if (asm_ss != sig_ss && sig == SIGTRAP) {
> +		printf("[FAIL]\tSIGTRAP: ss = %hx, frame ss = %hx, ax = %llx\n",
> +		       ss, *ssptr(ctx), (unsigned long long)asm_ss);
> +		nerrs++;
> +	}
> +
> +	memcpy(&resulting_regs, &ctx->uc_mcontext.gregs, sizeof(gregset_t));
> +	memcpy(&ctx->uc_mcontext.gregs, &initial_regs, sizeof(gregset_t));
> +
> +	sig_trapped = sig;
> +}
> +
> +static char altstack_data[SIGSTKSZ];
> +
> +int cs_bitness(unsigned short cs)
> +{
> +	uint32_t valid = 0, ar;
> +	asm ("lar %[cs], %[ar]\n\t"
> +	     "jnz 1f\n\t"
> +	     "mov $1, %[valid]\n\t"
> +	     "1:"
> +	     : [ar] "=r" (ar), [valid] "+rm" (valid)
> +	     : [cs] "r" (cs));
> +
> +	if (!valid)
> +		return -1;
> +
> +	bool db = (ar & (1 << 22));
> +	bool l = (ar & (1 << 21));
> +
> +	if (!(ar & (1<<11)))
> +		return -1;	/* Not code. */
> +
> +	if (l && !db)
> +		return 64;
> +	else if (!l && db)
> +		return 32;
> +	else if (!l && !db)
> +		return 16;
> +	else
> +		return -1;	/* Unknown bitness. */
> +}
> +
> +int find_cs(int bitness)
> +{
> +	unsigned short my_cs;
> +
> +	asm ("mov %%cs,%0" :  "=r" (my_cs));
> +
> +	if (cs_bitness(my_cs) == bitness)
> +		return my_cs;
> +	if (cs_bitness(my_cs + (2 << 3)) == bitness)
> +		return my_cs + (2 << 3);
> +	if (my_cs > (2<<3) && cs_bitness(my_cs - (2 << 3)) == bitness)
> +		return my_cs - (2 << 3);
> +	if (cs_bitness(0x7) == bitness)
> +		return 0x7;
> +
> +	printf("[WARN]\tCould not find %d-bit CS\n", bitness);
> +	return -1;
> +}
> +
> +static int do_test(int cs_bits, bool use_16bit_ss, int force_ss)
> +{
> +	int cs = find_cs(cs_bits);
> +	if (cs == -1) {
> +		printf("[SKIP]\tCode segment unavailable for %d-bit CS, %d-bit SS\n",
> +		       cs_bits, use_16bit_ss ? 16 : 32);
> +		return 0;
> +	}
> +
> +	if (force_ss != -1) {
> +		sig_ss = force_ss;
> +	} else {
> +		if (use_16bit_ss) {
> +			if (!has_data16) {
> +				printf("[SKIP]\tData segment unavailable for %d-bit CS, 16-bit SS\n",
> +				       cs_bits);
> +				return 0;
> +			}
> +			sig_ss = (1 << 3) | 7;	/* LDT selector 1, RPL = 3 */
> +		} else {
> +			asm volatile ("mov %%ss,%0" : "=r" (sig_ss));
> +		}
> +	}
> +
> +	sig_cs = cs;
> +
> +	printf("[RUN]\t%d-bit CS (%hx), %d-bit SS (%hx%s)\n",
> +	       cs_bits, sig_cs, use_16bit_ss ? 16 : 32, sig_ss,
> +	       (sig_ss & 4) ? "" : ", GDT");
> +
> +	raise(SIGUSR1);
> +
> +	nerrs = 0;
> +
> +	for (int i = 0; i < NGREG; i++) {
> +		greg_t req = requested_regs[i], res = resulting_regs[i];
> +		if (i == REG_TRAPNO || i == REG_IP)
> +			continue;	/* don't care */
> +		if (i == REG_SP) {
> +			printf("\tSP: %llx -> %llx\n", (unsigned long long)req,
> +			       (unsigned long long)res);
> +			if (res == (req & 0xFFFFFFFF))
> +				continue;  /* OK; not expected to work */
> +		}
> +
> +		bool ignore_reg = false;
> +#if __i386__
> +		if (i == REG_UESP)
> +			ignore_reg = true;
> +#else
> +		if (i == REG_CSGSFS) {
> +			struct selectors *req_sels =
> +				(void *)&requested_regs[REG_CSGSFS];
> +			struct selectors *res_sels =
> +				(void *)&resulting_regs[REG_CSGSFS];
> +			if (req_sels->cs != res_sels->cs) {
> +				printf("[FAIL]\tCS mismatch: requested 0x%hx; got 0x%hx\n",
> +				       req_sels->cs, res_sels->cs);
> +				nerrs++;
> +			}
> +
> +			if (req_sels->ss != res_sels->ss) {
> +				printf("[FAIL]\tSS mismatch: requested 0x%hx; got 0x%hx\n",
> +				       req_sels->ss, res_sels->ss);
> +				nerrs++;
> +			}
> +
> +			continue;
> +		}
> +#endif
> +
> +		/* Sanity check on the kernel */
> +		if (i == REG_AX && requested_regs[i] != resulting_regs[i]) {
> +			printf("[FAIL]\tAX (saved SP) mismatch: requested 0x%llx; got 0x%llx\n",
> +			       (unsigned long long)requested_regs[i],
> +			       (unsigned long long)resulting_regs[i]);
> +			nerrs++;
> +			continue;
> +		}
> +
> +		if (requested_regs[i] != resulting_regs[i] && !ignore_reg) {
> +			printf("[FAIL]\tReg %d mismatch: requested 0x%llx; got 0x%llx\n",
> +			       i, (unsigned long long)requested_regs[i],
> +			       (unsigned long long)resulting_regs[i]);
> +			nerrs++;
> +		}
> +	}
> +
> +	if (nerrs == 0)
> +		printf("[OK]\tall registers okay\n");
> +
> +	return nerrs;
> +}
> +
> +static int test_bad_iret(int cs_bits, unsigned short ss, int force_cs)
> +{
> +	int cs = force_cs == -1 ? find_cs(cs_bits) : force_cs;
> +	if (cs == -1)
> +		return 0;
> +
> +	sig_cs = cs;
> +	sig_ss = ss;
> +
> +	printf("[RUN]\t%d-bit CS (%hx), bogus SS (%hx)\n",
> +	       cs_bits, sig_cs, sig_ss);
> +
> +	sig_trapped = 0;
> +	raise(SIGUSR1);
> +	if (sig_trapped) {
> +		char errdesc[32] = "";
> +		if (sig_err) {
> +			const char *src = (sig_err & 1) ? " EXT" : "";
> +			const char *table;
> +			if ((sig_err & 0x6) == 0x0)
> +				table = "GDT";
> +			else if ((sig_err & 0x6) == 0x4)
> +				table = "LDT";
> +			else if ((sig_err & 0x6) == 0x2)
> +				table = "IDT";
> +			else
> +				table = "???";
> +
> +			sprintf(errdesc, "%s%s index %d, ",
> +				table, src, sig_err >> 3);
> +		}
> +
> +		char trapname[32];
> +		if (sig_trapno == 13)
> +			strcpy(trapname, "GP");
> +		else if (sig_trapno == 11)
> +			strcpy(trapname, "NP");
> +		else if (sig_trapno == 12)
> +			strcpy(trapname, "SS");
> +		else if (sig_trapno == 32)
> +			strcpy(trapname, "IRET");  /* X86_TRAP_IRET */
> +		else
> +			sprintf(trapname, "%d", sig_trapno);
> +
> +		printf("[OK]\tGot #%s(0x%lx) (i.e. %s%s)\n",
> +		       trapname, (unsigned long)sig_err,
> +		       errdesc, strsignal(sig_trapped));
> +		return 0;
> +	} else {
> +		printf("[FAIL]\tDid not get SIGSEGV\n");
> +		return 1;
> +	}
> +}
> +
> +int main(void)
> +{
> +	int total_nerrs = 0;
> +	unsigned short my_cs, my_ss;
> +
> +#ifdef __x86_64__
> +	printf("[WARN]\t***** The 64-bit version requires a special kernel. *****\n");
> +	printf("[WARN]\t***** Build with -m32. *****\n");
> +	usleep(1000000);
> +#endif
> +
> +	asm volatile ("mov %%cs,%0" : "=r" (my_cs));
> +	asm volatile ("mov %%ss,%0" : "=r" (my_ss));
> +	setup_ldt();
> +
> +	stack_t stack = {
> +		.ss_sp = altstack_data,
> +		.ss_size = SIGSTKSZ,
> +	};
> +	if (sigaltstack(&stack, NULL) != 0)
> +		err(1, "sigaltstack");
> +
> +	sethandler(SIGUSR1, sigusr1, 0);
> +	sethandler(SIGTRAP, sigtrap, SA_ONSTACK);
> +
> +	total_nerrs += do_test(64, false, -1);
> +	total_nerrs += do_test(32, false, -1);
> +	total_nerrs += do_test(16, false, -1);
> +	total_nerrs += do_test(64, true, -1);
> +	total_nerrs += do_test(32, true, -1);
> +	total_nerrs += do_test(16, true, -1);
> +
> +	if (gdt_data16_idx) {
> +		total_nerrs += do_test(64, true, (gdt_data16_idx << 3) | 3);
> +		total_nerrs += do_test(32, true, (gdt_data16_idx << 3) | 3);
> +		total_nerrs += do_test(16, true, (gdt_data16_idx << 3) | 3);
> +	}
> +
> +	clearhandler(SIGTRAP);
> +	sethandler(SIGSEGV, sigtrap, SA_ONSTACK);
> +	sethandler(SIGBUS, sigtrap, SA_ONSTACK);
> +	sethandler(SIGILL, sigtrap, SA_ONSTACK);  /* 32-bit kernels do this */
> +
> +	test_bad_iret(64, (2 << 3) | 7, -1);
> +	test_bad_iret(32, (2 << 3) | 7, -1);
> +	test_bad_iret(16, (2 << 3) | 7, -1);
> +
> +	test_bad_iret(64, my_cs, -1);
> +	test_bad_iret(32, my_cs, -1);
> +	test_bad_iret(16, my_cs, -1);
> +
> +	/* IRET will fail with #NP */
> +	test_bad_iret(32, my_ss, (3 << 3) | 7);
> +
> +	/* IRET will fail with #SS on the espfix stack */
> +	test_bad_iret(32, (4 << 3) | 7, -1);
> +
> +	/* IRET will fail with #SS on the normal stack */
> +	if (gdt_npdata32_idx)
> +		test_bad_iret(32, (gdt_npdata32_idx << 3) | 3, -1);
> +
> +	return total_nerrs ? 1 : 0;
> +}
> 


-- 
Shuah Khan
Sr. Linux Kernel Developer
Open Source Innovation Group
Samsung Research America (Silicon Valley)
shuahkh@....samsung.com | (970) 217-8978
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ