brintos

brintos / linux-shallow public Read only

0
0
Text · 22.3 KiB · 3a29346 Raw
928 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * ldt_gdt.c - Test cases for LDT and GDT access4 * Copyright (c) 2015 Andrew Lutomirski5 */6 7#define _GNU_SOURCE8#include <err.h>9#include <stdio.h>10#include <stdint.h>11#include <signal.h>12#include <setjmp.h>13#include <stdlib.h>14#include <string.h>15#include <errno.h>16#include <unistd.h>17#include <sys/syscall.h>18#include <asm/ldt.h>19#include <sys/types.h>20#include <sys/wait.h>21#include <stdbool.h>22#include <pthread.h>23#include <sched.h>24#include <linux/futex.h>25#include <sys/mman.h>26#include <asm/prctl.h>27#include <sys/prctl.h>28 29#define AR_ACCESSED		(1<<8)30 31#define AR_TYPE_RODATA		(0 * (1<<9))32#define AR_TYPE_RWDATA		(1 * (1<<9))33#define AR_TYPE_RODATA_EXPDOWN	(2 * (1<<9))34#define AR_TYPE_RWDATA_EXPDOWN	(3 * (1<<9))35#define AR_TYPE_XOCODE		(4 * (1<<9))36#define AR_TYPE_XRCODE		(5 * (1<<9))37#define AR_TYPE_XOCODE_CONF	(6 * (1<<9))38#define AR_TYPE_XRCODE_CONF	(7 * (1<<9))39 40#define AR_DPL3			(3 * (1<<13))41 42#define AR_S			(1 << 12)43#define AR_P			(1 << 15)44#define AR_AVL			(1 << 20)45#define AR_L			(1 << 21)46#define AR_DB			(1 << 22)47#define AR_G			(1 << 23)48 49#ifdef __x86_64__50# define INT80_CLOBBERS "r8", "r9", "r10", "r11"51#else52# define INT80_CLOBBERS53#endif54 55static int nerrs;56 57/* Points to an array of 1024 ints, each holding its own index. */58static const unsigned int *counter_page;59static struct user_desc *low_user_desc;60static struct user_desc *low_user_desc_clear;  /* Use to delete GDT entry */61static int gdt_entry_num;62 63static void check_invalid_segment(uint16_t index, int ldt)64{65	uint32_t has_limit = 0, has_ar = 0, limit, ar;66	uint32_t selector = (index << 3) | (ldt << 2) | 3;67 68	asm ("lsl %[selector], %[limit]\n\t"69	     "jnz 1f\n\t"70	     "movl $1, %[has_limit]\n\t"71	     "1:"72	     : [limit] "=r" (limit), [has_limit] "+rm" (has_limit)73	     : [selector] "r" (selector));74	asm ("larl %[selector], %[ar]\n\t"75	     "jnz 1f\n\t"76	     "movl $1, %[has_ar]\n\t"77	     "1:"78	     : [ar] "=r" (ar), [has_ar] "+rm" (has_ar)79	     : [selector] "r" (selector));80 81	if (has_limit || has_ar) {82		printf("[FAIL]\t%s entry %hu is valid but should be invalid\n",83		       (ldt ? "LDT" : "GDT"), index);84		nerrs++;85	} else {86		printf("[OK]\t%s entry %hu is invalid\n",87		       (ldt ? "LDT" : "GDT"), index);88	}89}90 91static void check_valid_segment(uint16_t index, int ldt,92				uint32_t expected_ar, uint32_t expected_limit,93				bool verbose)94{95	uint32_t has_limit = 0, has_ar = 0, limit, ar;96	uint32_t selector = (index << 3) | (ldt << 2) | 3;97 98	asm ("lsl %[selector], %[limit]\n\t"99	     "jnz 1f\n\t"100	     "movl $1, %[has_limit]\n\t"101	     "1:"102	     : [limit] "=r" (limit), [has_limit] "+rm" (has_limit)103	     : [selector] "r" (selector));104	asm ("larl %[selector], %[ar]\n\t"105	     "jnz 1f\n\t"106	     "movl $1, %[has_ar]\n\t"107	     "1:"108	     : [ar] "=r" (ar), [has_ar] "+rm" (has_ar)109	     : [selector] "r" (selector));110 111	if (!has_limit || !has_ar) {112		printf("[FAIL]\t%s entry %hu is invalid but should be valid\n",113		       (ldt ? "LDT" : "GDT"), index);114		nerrs++;115		return;116	}117 118	/* The SDM says "bits 19:16 are undefined".  Thanks. */119	ar &= ~0xF0000;120 121	/*122	 * NB: Different Linux versions do different things with the123	 * accessed bit in set_thread_area().124	 */125	if (ar != expected_ar && ar != (expected_ar | AR_ACCESSED)) {126		printf("[FAIL]\t%s entry %hu has AR 0x%08X but expected 0x%08X\n",127		       (ldt ? "LDT" : "GDT"), index, ar, expected_ar);128		nerrs++;129	} else if (limit != expected_limit) {130		printf("[FAIL]\t%s entry %hu has limit 0x%08X but expected 0x%08X\n",131		       (ldt ? "LDT" : "GDT"), index, limit, expected_limit);132		nerrs++;133	} else if (verbose) {134		printf("[OK]\t%s entry %hu has AR 0x%08X and limit 0x%08X\n",135		       (ldt ? "LDT" : "GDT"), index, ar, limit);136	}137}138 139static bool install_valid_mode(const struct user_desc *d, uint32_t ar,140			       bool oldmode, bool ldt)141{142	struct user_desc desc = *d;143	int ret;144 145	if (!ldt) {146#ifndef __i386__147		/* No point testing set_thread_area in a 64-bit build */148		return false;149#endif150		if (!gdt_entry_num)151			return false;152		desc.entry_number = gdt_entry_num;153 154		ret = syscall(SYS_set_thread_area, &desc);155	} else {156		ret = syscall(SYS_modify_ldt, oldmode ? 1 : 0x11,157			      &desc, sizeof(desc));158 159		if (ret < -1)160			errno = -ret;161 162		if (ret != 0 && errno == ENOSYS) {163			printf("[OK]\tmodify_ldt returned -ENOSYS\n");164			return false;165		}166	}167 168	if (ret == 0) {169		uint32_t limit = desc.limit;170		if (desc.limit_in_pages)171			limit = (limit << 12) + 4095;172		check_valid_segment(desc.entry_number, ldt, ar, limit, true);173		return true;174	} else {175		if (desc.seg_32bit) {176			printf("[FAIL]\tUnexpected %s failure %d\n",177			       ldt ? "modify_ldt" : "set_thread_area",178			       errno);179			nerrs++;180			return false;181		} else {182			printf("[OK]\t%s rejected 16 bit segment\n",183			       ldt ? "modify_ldt" : "set_thread_area");184			return false;185		}186	}187}188 189static bool install_valid(const struct user_desc *desc, uint32_t ar)190{191	bool ret = install_valid_mode(desc, ar, false, true);192 193	if (desc->contents <= 1 && desc->seg_32bit &&194	    !desc->seg_not_present) {195		/* Should work in the GDT, too. */196		install_valid_mode(desc, ar, false, false);197	}198 199	return ret;200}201 202static void install_invalid(const struct user_desc *desc, bool oldmode)203{204	int ret = syscall(SYS_modify_ldt, oldmode ? 1 : 0x11,205			  desc, sizeof(*desc));206	if (ret < -1)207		errno = -ret;208	if (ret == 0) {209		check_invalid_segment(desc->entry_number, 1);210	} else if (errno == ENOSYS) {211		printf("[OK]\tmodify_ldt returned -ENOSYS\n");212	} else {213		if (desc->seg_32bit) {214			printf("[FAIL]\tUnexpected modify_ldt failure %d\n",215			       errno);216			nerrs++;217		} else {218			printf("[OK]\tmodify_ldt rejected 16 bit segment\n");219		}220	}221}222 223static int safe_modify_ldt(int func, struct user_desc *ptr,224			   unsigned long bytecount)225{226	int ret = syscall(SYS_modify_ldt, 0x11, ptr, bytecount);227	if (ret < -1)228		errno = -ret;229	return ret;230}231 232static void fail_install(struct user_desc *desc)233{234	if (safe_modify_ldt(0x11, desc, sizeof(*desc)) == 0) {235		printf("[FAIL]\tmodify_ldt accepted a bad descriptor\n");236		nerrs++;237	} else if (errno == ENOSYS) {238		printf("[OK]\tmodify_ldt returned -ENOSYS\n");239	} else {240		printf("[OK]\tmodify_ldt failure %d\n", errno);241	}242}243 244static void do_simple_tests(void)245{246	struct user_desc desc = {247		.entry_number    = 0,248		.base_addr       = 0,249		.limit           = 10,250		.seg_32bit       = 1,251		.contents        = 2, /* Code, not conforming */252		.read_exec_only  = 0,253		.limit_in_pages  = 0,254		.seg_not_present = 0,255		.useable         = 0256	};257	install_valid(&desc, AR_DPL3 | AR_TYPE_XRCODE | AR_S | AR_P | AR_DB);258 259	desc.limit_in_pages = 1;260	install_valid(&desc, AR_DPL3 | AR_TYPE_XRCODE |261		      AR_S | AR_P | AR_DB | AR_G);262 263	check_invalid_segment(1, 1);264 265	desc.entry_number = 2;266	install_valid(&desc, AR_DPL3 | AR_TYPE_XRCODE |267		      AR_S | AR_P | AR_DB | AR_G);268 269	check_invalid_segment(1, 1);270 271	desc.base_addr = 0xf0000000;272	install_valid(&desc, AR_DPL3 | AR_TYPE_XRCODE |273		      AR_S | AR_P | AR_DB | AR_G);274 275	desc.useable = 1;276	install_valid(&desc, AR_DPL3 | AR_TYPE_XRCODE |277		      AR_S | AR_P | AR_DB | AR_G | AR_AVL);278 279	desc.seg_not_present = 1;280	install_valid(&desc, AR_DPL3 | AR_TYPE_XRCODE |281		      AR_S | AR_DB | AR_G | AR_AVL);282 283	desc.seg_32bit = 0;284	install_valid(&desc, AR_DPL3 | AR_TYPE_XRCODE |285		      AR_S | AR_G | AR_AVL);286 287	desc.seg_32bit = 1;288	desc.contents = 0;289	install_valid(&desc, AR_DPL3 | AR_TYPE_RWDATA |290		      AR_S | AR_DB | AR_G | AR_AVL);291 292	desc.read_exec_only = 1;293	install_valid(&desc, AR_DPL3 | AR_TYPE_RODATA |294		      AR_S | AR_DB | AR_G | AR_AVL);295 296	desc.contents = 1;297	install_valid(&desc, AR_DPL3 | AR_TYPE_RODATA_EXPDOWN |298		      AR_S | AR_DB | AR_G | AR_AVL);299 300	desc.read_exec_only = 0;301	desc.limit_in_pages = 0;302	install_valid(&desc, AR_DPL3 | AR_TYPE_RWDATA_EXPDOWN |303		      AR_S | AR_DB | AR_AVL);304 305	desc.contents = 3;306	install_valid(&desc, AR_DPL3 | AR_TYPE_XRCODE_CONF |307		      AR_S | AR_DB | AR_AVL);308 309	desc.read_exec_only = 1;310	install_valid(&desc, AR_DPL3 | AR_TYPE_XOCODE_CONF |311		      AR_S | AR_DB | AR_AVL);312 313	desc.read_exec_only = 0;314	desc.contents = 2;315	install_valid(&desc, AR_DPL3 | AR_TYPE_XRCODE |316		      AR_S | AR_DB | AR_AVL);317 318	desc.read_exec_only = 1;319 320#ifdef __x86_64__321	desc.lm = 1;322	install_valid(&desc, AR_DPL3 | AR_TYPE_XOCODE |323		      AR_S | AR_DB | AR_AVL);324	desc.lm = 0;325#endif326 327	bool entry1_okay = install_valid(&desc, AR_DPL3 | AR_TYPE_XOCODE |328					 AR_S | AR_DB | AR_AVL);329 330	if (entry1_okay) {331		printf("[RUN]\tTest fork\n");332		pid_t child = fork();333		if (child == 0) {334			nerrs = 0;335			check_valid_segment(desc.entry_number, 1,336					    AR_DPL3 | AR_TYPE_XOCODE |337					    AR_S | AR_DB | AR_AVL, desc.limit,338					    true);339			check_invalid_segment(1, 1);340			exit(nerrs ? 1 : 0);341		} else {342			int status;343			if (waitpid(child, &status, 0) != child ||344			    !WIFEXITED(status)) {345				printf("[FAIL]\tChild died\n");346				nerrs++;347			} else if (WEXITSTATUS(status) != 0) {348				printf("[FAIL]\tChild failed\n");349				nerrs++;350			} else {351				printf("[OK]\tChild succeeded\n");352			}353		}354 355		printf("[RUN]\tTest size\n");356		int i;357		for (i = 0; i < 8192; i++) {358			desc.entry_number = i;359			desc.limit = i;360			if (safe_modify_ldt(0x11, &desc, sizeof(desc)) != 0) {361				printf("[FAIL]\tFailed to install entry %d\n", i);362				nerrs++;363				break;364			}365		}366		for (int j = 0; j < i; j++) {367			check_valid_segment(j, 1, AR_DPL3 | AR_TYPE_XOCODE |368					    AR_S | AR_DB | AR_AVL, j, false);369		}370		printf("[DONE]\tSize test\n");371	} else {372		printf("[SKIP]\tSkipping fork and size tests because we have no LDT\n");373	}374 375	/* Test entry_number too high. */376	desc.entry_number = 8192;377	fail_install(&desc);378 379	/* Test deletion and actions mistakeable for deletion. */380	memset(&desc, 0, sizeof(desc));381	install_valid(&desc, AR_DPL3 | AR_TYPE_RWDATA | AR_S | AR_P);382 383	desc.seg_not_present = 1;384	install_valid(&desc, AR_DPL3 | AR_TYPE_RWDATA | AR_S);385 386	desc.seg_not_present = 0;387	desc.read_exec_only = 1;388	install_valid(&desc, AR_DPL3 | AR_TYPE_RODATA | AR_S | AR_P);389 390	desc.read_exec_only = 0;391	desc.seg_not_present = 1;392	install_valid(&desc, AR_DPL3 | AR_TYPE_RWDATA | AR_S);393 394	desc.read_exec_only = 1;395	desc.limit = 1;396	install_valid(&desc, AR_DPL3 | AR_TYPE_RODATA | AR_S);397 398	desc.limit = 0;399	desc.base_addr = 1;400	install_valid(&desc, AR_DPL3 | AR_TYPE_RODATA | AR_S);401 402	desc.base_addr = 0;403	install_invalid(&desc, false);404 405	desc.seg_not_present = 0;406	desc.seg_32bit = 1;407	desc.read_exec_only = 0;408	desc.limit = 0xfffff;409 410	install_valid(&desc, AR_DPL3 | AR_TYPE_RWDATA | AR_S | AR_P | AR_DB);411 412	desc.limit_in_pages = 1;413 414	install_valid(&desc, AR_DPL3 | AR_TYPE_RWDATA | AR_S | AR_P | AR_DB | AR_G);415	desc.read_exec_only = 1;416	install_valid(&desc, AR_DPL3 | AR_TYPE_RODATA | AR_S | AR_P | AR_DB | AR_G);417	desc.contents = 1;418	desc.read_exec_only = 0;419	install_valid(&desc, AR_DPL3 | AR_TYPE_RWDATA_EXPDOWN | AR_S | AR_P | AR_DB | AR_G);420	desc.read_exec_only = 1;421	install_valid(&desc, AR_DPL3 | AR_TYPE_RODATA_EXPDOWN | AR_S | AR_P | AR_DB | AR_G);422 423	desc.limit = 0;424	install_invalid(&desc, true);425}426 427/*428 * 0: thread is idle429 * 1: thread armed430 * 2: thread should clear LDT entry 0431 * 3: thread should exit432 */433static volatile unsigned int ftx;434 435static void *threadproc(void *ctx)436{437	cpu_set_t cpuset;438	CPU_ZERO(&cpuset);439	CPU_SET(1, &cpuset);440	if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0)441		err(1, "sched_setaffinity to CPU 1");	/* should never fail */442 443	while (1) {444		syscall(SYS_futex, &ftx, FUTEX_WAIT, 0, NULL, NULL, 0);445		while (ftx != 2) {446			if (ftx >= 3)447				return NULL;448		}449 450		/* clear LDT entry 0 */451		const struct user_desc desc = {};452		if (syscall(SYS_modify_ldt, 1, &desc, sizeof(desc)) != 0)453			err(1, "modify_ldt");454 455		/* If ftx == 2, set it to zero.  If ftx == 100, quit. */456		unsigned int x = -2;457		asm volatile ("lock xaddl %[x], %[ftx]" :458			      [x] "+r" (x), [ftx] "+m" (ftx));459		if (x != 2)460			return NULL;461	}462}463 464#ifdef __i386__465 466#ifndef SA_RESTORE467#define SA_RESTORER 0x04000000468#endif469 470/*471 * The UAPI header calls this 'struct sigaction', which conflicts with472 * glibc.  Sigh.473 */474struct fake_ksigaction {475	void *handler;  /* the real type is nasty */476	unsigned long sa_flags;477	void (*sa_restorer)(void);478	unsigned char sigset[8];479};480 481static void fix_sa_restorer(int sig)482{483	struct fake_ksigaction ksa;484 485	if (syscall(SYS_rt_sigaction, sig, NULL, &ksa, 8) == 0) {486		/*487		 * glibc has a nasty bug: it sometimes writes garbage to488		 * sa_restorer.  This interacts quite badly with anything489		 * that fiddles with SS because it can trigger legacy490		 * stack switching.  Patch it up.  See:491		 *492		 * https://sourceware.org/bugzilla/show_bug.cgi?id=21269493		 */494		if (!(ksa.sa_flags & SA_RESTORER) && ksa.sa_restorer) {495			ksa.sa_restorer = NULL;496			if (syscall(SYS_rt_sigaction, sig, &ksa, NULL,497				    sizeof(ksa.sigset)) != 0)498				err(1, "rt_sigaction");499		}500	}501}502#else503static void fix_sa_restorer(int sig)504{505	/* 64-bit glibc works fine. */506}507#endif508 509static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),510		       int flags)511{512	struct sigaction sa;513	memset(&sa, 0, sizeof(sa));514	sa.sa_sigaction = handler;515	sa.sa_flags = SA_SIGINFO | flags;516	sigemptyset(&sa.sa_mask);517	if (sigaction(sig, &sa, 0))518		err(1, "sigaction");519 520	fix_sa_restorer(sig);521}522 523static jmp_buf jmpbuf;524 525static void sigsegv(int sig, siginfo_t *info, void *ctx_void)526{527	siglongjmp(jmpbuf, 1);528}529 530static void do_multicpu_tests(void)531{532	cpu_set_t cpuset;533	pthread_t thread;534	int failures = 0, iters = 5, i;535	unsigned short orig_ss;536 537	CPU_ZERO(&cpuset);538	CPU_SET(1, &cpuset);539	if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0) {540		printf("[SKIP]\tCannot set affinity to CPU 1\n");541		return;542	}543 544	CPU_ZERO(&cpuset);545	CPU_SET(0, &cpuset);546	if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0) {547		printf("[SKIP]\tCannot set affinity to CPU 0\n");548		return;549	}550 551	sethandler(SIGSEGV, sigsegv, 0);552#ifdef __i386__553	/* True 32-bit kernels send SIGILL instead of SIGSEGV on IRET faults. */554	sethandler(SIGILL, sigsegv, 0);555#endif556 557	printf("[RUN]\tCross-CPU LDT invalidation\n");558 559	if (pthread_create(&thread, 0, threadproc, 0) != 0)560		err(1, "pthread_create");561 562	asm volatile ("mov %%ss, %0" : "=rm" (orig_ss));563 564	for (i = 0; i < 5; i++) {565		if (sigsetjmp(jmpbuf, 1) != 0)566			continue;567 568		/* Make sure the thread is ready after the last test. */569		while (ftx != 0)570			;571 572		struct user_desc desc = {573			.entry_number    = 0,574			.base_addr       = 0,575			.limit           = 0xfffff,576			.seg_32bit       = 1,577			.contents        = 0, /* Data */578			.read_exec_only  = 0,579			.limit_in_pages  = 1,580			.seg_not_present = 0,581			.useable         = 0582		};583 584		if (safe_modify_ldt(0x11, &desc, sizeof(desc)) != 0) {585			if (errno != ENOSYS)586				err(1, "modify_ldt");587			printf("[SKIP]\tmodify_ldt unavailable\n");588			break;589		}590 591		/* Arm the thread. */592		ftx = 1;593		syscall(SYS_futex, &ftx, FUTEX_WAKE, 0, NULL, NULL, 0);594 595		asm volatile ("mov %0, %%ss" : : "r" (0x7));596 597		/* Go! */598		ftx = 2;599 600		while (ftx != 0)601			;602 603		/*604		 * On success, modify_ldt will segfault us synchronously,605		 * and we'll escape via siglongjmp.606		 */607 608		failures++;609		asm volatile ("mov %0, %%ss" : : "rm" (orig_ss));610	}611 612	ftx = 100;  /* Kill the thread. */613	syscall(SYS_futex, &ftx, FUTEX_WAKE, 0, NULL, NULL, 0);614 615	if (pthread_join(thread, NULL) != 0)616		err(1, "pthread_join");617 618	if (failures) {619		printf("[FAIL]\t%d of %d iterations failed\n", failures, iters);620		nerrs++;621	} else {622		printf("[OK]\tAll %d iterations succeeded\n", iters);623	}624}625 626static int finish_exec_test(void)627{628	/*629	 * Older kernel versions did inherit the LDT on exec() which is630	 * wrong because exec() starts from a clean state.631	 */632	check_invalid_segment(0, 1);633 634	return nerrs ? 1 : 0;635}636 637static void do_exec_test(void)638{639	printf("[RUN]\tTest exec\n");640 641	struct user_desc desc = {642		.entry_number    = 0,643		.base_addr       = 0,644		.limit           = 42,645		.seg_32bit       = 1,646		.contents        = 2, /* Code, not conforming */647		.read_exec_only  = 0,648		.limit_in_pages  = 0,649		.seg_not_present = 0,650		.useable         = 0651	};652	install_valid(&desc, AR_DPL3 | AR_TYPE_XRCODE | AR_S | AR_P | AR_DB);653 654	pid_t child = fork();655	if (child == 0) {656		execl("/proc/self/exe", "ldt_gdt_test_exec", NULL);657		printf("[FAIL]\tCould not exec self\n");658		exit(1);	/* exec failed */659	} else {660		int status;661		if (waitpid(child, &status, 0) != child ||662		    !WIFEXITED(status)) {663			printf("[FAIL]\tChild died\n");664			nerrs++;665		} else if (WEXITSTATUS(status) != 0) {666			printf("[FAIL]\tChild failed\n");667			nerrs++;668		} else {669			printf("[OK]\tChild succeeded\n");670		}671	}672}673 674static void setup_counter_page(void)675{676	unsigned int *page = mmap(NULL, 4096, PROT_READ | PROT_WRITE,677			 MAP_ANONYMOUS | MAP_PRIVATE | MAP_32BIT, -1, 0);678	if (page == MAP_FAILED)679		err(1, "mmap");680 681	for (int i = 0; i < 1024; i++)682		page[i] = i;683	counter_page = page;684}685 686static int invoke_set_thread_area(void)687{688	int ret;689	asm volatile ("int $0x80"690		      : "=a" (ret), "+m" (low_user_desc) :691			"a" (243), "b" (low_user_desc)692		      : INT80_CLOBBERS);693	return ret;694}695 696static void setup_low_user_desc(void)697{698	low_user_desc = mmap(NULL, 2 * sizeof(struct user_desc),699			     PROT_READ | PROT_WRITE,700			     MAP_ANONYMOUS | MAP_PRIVATE | MAP_32BIT, -1, 0);701	if (low_user_desc == MAP_FAILED)702		err(1, "mmap");703 704	low_user_desc->entry_number	= -1;705	low_user_desc->base_addr	= (unsigned long)&counter_page[1];706	low_user_desc->limit		= 0xfffff;707	low_user_desc->seg_32bit	= 1;708	low_user_desc->contents		= 0; /* Data, grow-up*/709	low_user_desc->read_exec_only	= 0;710	low_user_desc->limit_in_pages	= 1;711	low_user_desc->seg_not_present	= 0;712	low_user_desc->useable		= 0;713 714	if (invoke_set_thread_area() == 0) {715		gdt_entry_num = low_user_desc->entry_number;716		printf("[NOTE]\tset_thread_area is available; will use GDT index %d\n", gdt_entry_num);717	} else {718		printf("[NOTE]\tset_thread_area is unavailable\n");719	}720 721	low_user_desc_clear = low_user_desc + 1;722	low_user_desc_clear->entry_number = gdt_entry_num;723	low_user_desc_clear->read_exec_only = 1;724	low_user_desc_clear->seg_not_present = 1;725}726 727static void test_gdt_invalidation(void)728{729	if (!gdt_entry_num)730		return;	/* 64-bit only system -- we can't use set_thread_area */731 732	unsigned short prev_sel;733	unsigned short sel;734	unsigned int eax;735	const char *result;736#ifdef __x86_64__737	unsigned long saved_base;738	unsigned long new_base;739#endif740 741	/* Test DS */742	invoke_set_thread_area();743	eax = 243;744	sel = (gdt_entry_num << 3) | 3;745	asm volatile ("movw %%ds, %[prev_sel]\n\t"746		      "movw %[sel], %%ds\n\t"747#ifdef __i386__748		      "pushl %%ebx\n\t"749#endif750		      "movl %[arg1], %%ebx\n\t"751		      "int $0x80\n\t"	/* Should invalidate ds */752#ifdef __i386__753		      "popl %%ebx\n\t"754#endif755		      "movw %%ds, %[sel]\n\t"756		      "movw %[prev_sel], %%ds"757		      : [prev_sel] "=&r" (prev_sel), [sel] "+r" (sel),758			"+a" (eax)759		      : "m" (low_user_desc_clear),760			[arg1] "r" ((unsigned int)(unsigned long)low_user_desc_clear)761		      : INT80_CLOBBERS);762 763	if (sel != 0) {764		result = "FAIL";765		nerrs++;766	} else {767		result = "OK";768	}769	printf("[%s]\tInvalidate DS with set_thread_area: new DS = 0x%hx\n",770	       result, sel);771 772	/* Test ES */773	invoke_set_thread_area();774	eax = 243;775	sel = (gdt_entry_num << 3) | 3;776	asm volatile ("movw %%es, %[prev_sel]\n\t"777		      "movw %[sel], %%es\n\t"778#ifdef __i386__779		      "pushl %%ebx\n\t"780#endif781		      "movl %[arg1], %%ebx\n\t"782		      "int $0x80\n\t"	/* Should invalidate es */783#ifdef __i386__784		      "popl %%ebx\n\t"785#endif786		      "movw %%es, %[sel]\n\t"787		      "movw %[prev_sel], %%es"788		      : [prev_sel] "=&r" (prev_sel), [sel] "+r" (sel),789			"+a" (eax)790		      : "m" (low_user_desc_clear),791			[arg1] "r" ((unsigned int)(unsigned long)low_user_desc_clear)792		      : INT80_CLOBBERS);793 794	if (sel != 0) {795		result = "FAIL";796		nerrs++;797	} else {798		result = "OK";799	}800	printf("[%s]\tInvalidate ES with set_thread_area: new ES = 0x%hx\n",801	       result, sel);802 803	/* Test FS */804	invoke_set_thread_area();805	eax = 243;806	sel = (gdt_entry_num << 3) | 3;807#ifdef __x86_64__808	syscall(SYS_arch_prctl, ARCH_GET_FS, &saved_base);809#endif810	asm volatile ("movw %%fs, %[prev_sel]\n\t"811		      "movw %[sel], %%fs\n\t"812#ifdef __i386__813		      "pushl %%ebx\n\t"814#endif815		      "movl %[arg1], %%ebx\n\t"816		      "int $0x80\n\t"	/* Should invalidate fs */817#ifdef __i386__818		      "popl %%ebx\n\t"819#endif820		      "movw %%fs, %[sel]\n\t"821		      : [prev_sel] "=&r" (prev_sel), [sel] "+r" (sel),822			"+a" (eax)823		      : "m" (low_user_desc_clear),824			[arg1] "r" ((unsigned int)(unsigned long)low_user_desc_clear)825		      : INT80_CLOBBERS);826 827#ifdef __x86_64__828	syscall(SYS_arch_prctl, ARCH_GET_FS, &new_base);829#endif830 831	/* Restore FS/BASE for glibc */832	asm volatile ("movw %[prev_sel], %%fs" : : [prev_sel] "rm" (prev_sel));833#ifdef __x86_64__834	if (saved_base)835		syscall(SYS_arch_prctl, ARCH_SET_FS, saved_base);836#endif837 838	if (sel != 0) {839		result = "FAIL";840		nerrs++;841	} else {842		result = "OK";843	}844	printf("[%s]\tInvalidate FS with set_thread_area: new FS = 0x%hx\n",845	       result, sel);846 847#ifdef __x86_64__848	if (sel == 0 && new_base != 0) {849		nerrs++;850		printf("[FAIL]\tNew FSBASE was 0x%lx\n", new_base);851	} else {852		printf("[OK]\tNew FSBASE was zero\n");853	}854#endif855 856	/* Test GS */857	invoke_set_thread_area();858	eax = 243;859	sel = (gdt_entry_num << 3) | 3;860#ifdef __x86_64__861	syscall(SYS_arch_prctl, ARCH_GET_GS, &saved_base);862#endif863	asm volatile ("movw %%gs, %[prev_sel]\n\t"864		      "movw %[sel], %%gs\n\t"865#ifdef __i386__866		      "pushl %%ebx\n\t"867#endif868		      "movl %[arg1], %%ebx\n\t"869		      "int $0x80\n\t"	/* Should invalidate gs */870#ifdef __i386__871		      "popl %%ebx\n\t"872#endif873		      "movw %%gs, %[sel]\n\t"874		      : [prev_sel] "=&r" (prev_sel), [sel] "+r" (sel),875			"+a" (eax)876		      : "m" (low_user_desc_clear),877			[arg1] "r" ((unsigned int)(unsigned long)low_user_desc_clear)878		      : INT80_CLOBBERS);879 880#ifdef __x86_64__881	syscall(SYS_arch_prctl, ARCH_GET_GS, &new_base);882#endif883 884	/* Restore GS/BASE for glibc */885	asm volatile ("movw %[prev_sel], %%gs" : : [prev_sel] "rm" (prev_sel));886#ifdef __x86_64__887	if (saved_base)888		syscall(SYS_arch_prctl, ARCH_SET_GS, saved_base);889#endif890 891	if (sel != 0) {892		result = "FAIL";893		nerrs++;894	} else {895		result = "OK";896	}897	printf("[%s]\tInvalidate GS with set_thread_area: new GS = 0x%hx\n",898	       result, sel);899 900#ifdef __x86_64__901	if (sel == 0 && new_base != 0) {902		nerrs++;903		printf("[FAIL]\tNew GSBASE was 0x%lx\n", new_base);904	} else {905		printf("[OK]\tNew GSBASE was zero\n");906	}907#endif908}909 910int main(int argc, char **argv)911{912	if (argc == 1 && !strcmp(argv[0], "ldt_gdt_test_exec"))913		return finish_exec_test();914 915	setup_counter_page();916	setup_low_user_desc();917 918	do_simple_tests();919 920	do_multicpu_tests();921 922	do_exec_test();923 924	test_gdt_invalidation();925 926	return nerrs ? 1 : 0;927}928