| /* |
| * gsbase.c, a gsbase test |
| * Copyright (c) 2014 Andy Lutomirski |
| * GPL v2 |
| */ |
| |
| #include <stdio.h> |
| #include <stdbool.h> |
| #include <sys/syscall.h> |
| #include <unistd.h> |
| #include <err.h> |
| #include <sys/user.h> |
| #include <asm/prctl.h> |
| #include <sys/prctl.h> |
| #include <sys/mman.h> |
| |
| #ifndef __x86_64__ |
| # error This test is 64-bit only |
| #endif |
| |
| static unsigned char *testptr, *testptr2; |
| |
| static unsigned char read_gs_testvals(void) |
| { |
| unsigned char ret; |
| asm volatile ("movb %%gs:%1, %0" : "=r" (ret) : "m" (*testptr)); |
| return ret; |
| } |
| |
| int main() |
| { |
| int errors = 0; |
| |
| testptr = mmap((void *)0x200000000UL, 1, PROT_READ | PROT_WRITE, |
| MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0); |
| if (testptr == MAP_FAILED) |
| err(1, "mmap"); |
| |
| testptr2 = mmap((void *)0x300000000UL, 1, PROT_READ | PROT_WRITE, |
| MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0); |
| if (testptr2 == MAP_FAILED) |
| err(1, "mmap"); |
| |
| *testptr = 0; |
| *testptr2 = 1; |
| |
| if (syscall(SYS_arch_prctl, ARCH_SET_GS, |
| (unsigned long)testptr2 - (unsigned long)testptr) != 0) |
| err(1, "ARCH_SET_GS"); |
| |
| usleep(100); |
| |
| if (read_gs_testvals() == 1) { |
| printf("[OK]\tARCH_SET_GS worked\n"); |
| } else { |
| printf("[FAIL]\tARCH_SET_GS failed\n"); |
| errors++; |
| } |
| |
| asm volatile ("mov %0,%%gs" : : "r" (0)); |
| |
| if (read_gs_testvals() == 0) { |
| printf("[OK]\tWriting 0 to gs worked\n"); |
| } else { |
| printf("[FAIL]\tWriting 0 to gs failed\n"); |
| errors++; |
| } |
| |
| usleep(100); |
| |
| if (read_gs_testvals() == 0) { |
| printf("[OK]\tgsbase is still zero\n"); |
| } else { |
| printf("[FAIL]\tgsbase reset itself to 1\n"); |
| errors++; |
| } |
| |
| return errors == 0 ? 0 : 1; |
| } |