brintos

brintos / linux-shallow public Read only

0
0
Text · 2.5 KiB · 5f3d4fc Raw
105 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * sysret_ss_attrs.c - test that syscalls return valid hidden SS attributes4 * Copyright (c) 2015 Andrew Lutomirski5 *6 * On AMD CPUs, SYSRET can return with a valid SS descriptor with with7 * the hidden attributes set to an unusable state.  Make sure the kernel8 * doesn't let this happen.9 */10 11#define _GNU_SOURCE12 13#include <stdlib.h>14#include <unistd.h>15#include <stdio.h>16#include <string.h>17#include <sys/mman.h>18#include <err.h>19#include <stddef.h>20#include <stdbool.h>21#include <pthread.h>22 23static void *threadproc(void *ctx)24{25	/*26	 * Do our best to cause sleeps on this CPU to exit the kernel and27	 * re-enter with SS = 0.28	 */29	while (true)30		;31 32	return NULL;33}34 35#ifdef __x86_64__36extern unsigned long call32_from_64(void *stack, void (*function)(void));37 38asm (".pushsection .text\n\t"39     ".code32\n\t"40     "test_ss:\n\t"41     "pushl $0\n\t"42     "popl %eax\n\t"43     "ret\n\t"44     ".code64");45extern void test_ss(void);46#endif47 48int main()49{50	/*51	 * Start a busy-looping thread on the same CPU we're on.52	 * For simplicity, just stick everything to CPU 0.  This will53	 * fail in some containers, but that's probably okay.54	 */55	cpu_set_t cpuset;56	CPU_ZERO(&cpuset);57	CPU_SET(0, &cpuset);58	if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0)59		printf("[WARN]\tsched_setaffinity failed\n");60 61	pthread_t thread;62	if (pthread_create(&thread, 0, threadproc, 0) != 0)63		err(1, "pthread_create");64 65#ifdef __x86_64__66	unsigned char *stack32 = mmap(NULL, 4096, PROT_READ | PROT_WRITE,67				      MAP_32BIT | MAP_ANONYMOUS | MAP_PRIVATE,68				      -1, 0);69	if (stack32 == MAP_FAILED)70		err(1, "mmap");71#endif72 73	printf("[RUN]\tSyscalls followed by SS validation\n");74 75	for (int i = 0; i < 1000; i++) {76		/*77		 * Go to sleep and return using sysret (if we're 64-bit78		 * or we're 32-bit on AMD on a 64-bit kernel).  On AMD CPUs,79		 * SYSRET doesn't fix up the cached SS descriptor, so the80		 * kernel needs some kind of workaround to make sure that we81		 * end the system call with a valid stack segment.  This82		 * can be a confusing failure because the SS *selector*83		 * is the same regardless.84		 */85		usleep(2);86 87#ifdef __x86_64__88		/*89		 * On 32-bit, just doing a syscall through glibc is enough90		 * to cause a crash if our cached SS descriptor is invalid.91		 * On 64-bit, it's not, so try extra hard.92		 */93		call32_from_64(stack32 + 4088, test_ss);94#endif95	}96 97	printf("[OK]\tWe survived\n");98 99#ifdef __x86_64__100	munmap(stack32, 4096);101#endif102 103	return 0;104}105