2025cf9e19
Based on 1 normalized pattern(s): this program is free software you can redistribute it and or modify it under the terms and conditions of the gnu general public license version 2 as published by the free software foundation this program is distributed in the hope it will be useful but without any warranty without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license for more details extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference in 263 file(s). Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Allison Randal <allison@lohutok.net> Reviewed-by: Alexios Zavras <alexios.zavras@intel.com> Cc: linux-spdx@vger.kernel.org Link: https://lkml.kernel.org/r/20190529141901.208660670@linutronix.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
105 lines
2.5 KiB
C
105 lines
2.5 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* sysret_ss_attrs.c - test that syscalls return valid hidden SS attributes
|
|
* Copyright (c) 2015 Andrew Lutomirski
|
|
*
|
|
* On AMD CPUs, SYSRET can return with a valid SS descriptor with with
|
|
* the hidden attributes set to an unusable state. Make sure the kernel
|
|
* doesn't let this happen.
|
|
*/
|
|
|
|
#define _GNU_SOURCE
|
|
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/mman.h>
|
|
#include <err.h>
|
|
#include <stddef.h>
|
|
#include <stdbool.h>
|
|
#include <pthread.h>
|
|
|
|
static void *threadproc(void *ctx)
|
|
{
|
|
/*
|
|
* Do our best to cause sleeps on this CPU to exit the kernel and
|
|
* re-enter with SS = 0.
|
|
*/
|
|
while (true)
|
|
;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#ifdef __x86_64__
|
|
extern unsigned long call32_from_64(void *stack, void (*function)(void));
|
|
|
|
asm (".pushsection .text\n\t"
|
|
".code32\n\t"
|
|
"test_ss:\n\t"
|
|
"pushl $0\n\t"
|
|
"popl %eax\n\t"
|
|
"ret\n\t"
|
|
".code64");
|
|
extern void test_ss(void);
|
|
#endif
|
|
|
|
int main()
|
|
{
|
|
/*
|
|
* Start a busy-looping thread on the same CPU we're on.
|
|
* For simplicity, just stick everything to CPU 0. This will
|
|
* fail in some containers, but that's probably okay.
|
|
*/
|
|
cpu_set_t cpuset;
|
|
CPU_ZERO(&cpuset);
|
|
CPU_SET(0, &cpuset);
|
|
if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0)
|
|
printf("[WARN]\tsched_setaffinity failed\n");
|
|
|
|
pthread_t thread;
|
|
if (pthread_create(&thread, 0, threadproc, 0) != 0)
|
|
err(1, "pthread_create");
|
|
|
|
#ifdef __x86_64__
|
|
unsigned char *stack32 = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
|
|
MAP_32BIT | MAP_ANONYMOUS | MAP_PRIVATE,
|
|
-1, 0);
|
|
if (stack32 == MAP_FAILED)
|
|
err(1, "mmap");
|
|
#endif
|
|
|
|
printf("[RUN]\tSyscalls followed by SS validation\n");
|
|
|
|
for (int i = 0; i < 1000; i++) {
|
|
/*
|
|
* Go to sleep and return using sysret (if we're 64-bit
|
|
* or we're 32-bit on AMD on a 64-bit kernel). On AMD CPUs,
|
|
* SYSRET doesn't fix up the cached SS descriptor, so the
|
|
* kernel needs some kind of workaround to make sure that we
|
|
* end the system call with a valid stack segment. This
|
|
* can be a confusing failure because the SS *selector*
|
|
* is the same regardless.
|
|
*/
|
|
usleep(2);
|
|
|
|
#ifdef __x86_64__
|
|
/*
|
|
* On 32-bit, just doing a syscall through glibc is enough
|
|
* to cause a crash if our cached SS descriptor is invalid.
|
|
* On 64-bit, it's not, so try extra hard.
|
|
*/
|
|
call32_from_64(stack32 + 4088, test_ss);
|
|
#endif
|
|
}
|
|
|
|
printf("[OK]\tWe survived\n");
|
|
|
|
#ifdef __x86_64__
|
|
munmap(stack32, 4096);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|