root/tools/testing/selftests/x86/test_mremap_vdso.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. try_to_remap
  2. main

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * 32-bit test to check vDSO mremap.
   4  *
   5  * Copyright (c) 2016 Dmitry Safonov
   6  * Suggested-by: Andrew Lutomirski
   7  */
   8 /*
   9  * Can be built statically:
  10  * gcc -Os -Wall -static -m32 test_mremap_vdso.c
  11  */
  12 #define _GNU_SOURCE
  13 #include <stdio.h>
  14 #include <errno.h>
  15 #include <unistd.h>
  16 #include <string.h>
  17 
  18 #include <sys/mman.h>
  19 #include <sys/auxv.h>
  20 #include <sys/syscall.h>
  21 #include <sys/wait.h>
  22 
  23 #define PAGE_SIZE       4096
  24 
  25 static int try_to_remap(void *vdso_addr, unsigned long size)
  26 {
  27         void *dest_addr, *new_addr;
  28 
  29         /* Searching for memory location where to remap */
  30         dest_addr = mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
  31         if (dest_addr == MAP_FAILED) {
  32                 printf("[WARN]\tmmap failed (%d): %m\n", errno);
  33                 return 0;
  34         }
  35 
  36         printf("[NOTE]\tMoving vDSO: [%p, %#lx] -> [%p, %#lx]\n",
  37                 vdso_addr, (unsigned long)vdso_addr + size,
  38                 dest_addr, (unsigned long)dest_addr + size);
  39         fflush(stdout);
  40 
  41         new_addr = mremap(vdso_addr, size, size,
  42                         MREMAP_FIXED|MREMAP_MAYMOVE, dest_addr);
  43         if ((unsigned long)new_addr == (unsigned long)-1) {
  44                 munmap(dest_addr, size);
  45                 if (errno == EINVAL) {
  46                         printf("[NOTE]\tvDSO partial move failed, will try with bigger size\n");
  47                         return -1; /* Retry with larger */
  48                 }
  49                 printf("[FAIL]\tmremap failed (%d): %m\n", errno);
  50                 return 1;
  51         }
  52 
  53         return 0;
  54 
  55 }
  56 
  57 int main(int argc, char **argv, char **envp)
  58 {
  59         pid_t child;
  60 
  61         child = fork();
  62         if (child == -1) {
  63                 printf("[WARN]\tfailed to fork (%d): %m\n", errno);
  64                 return 1;
  65         }
  66 
  67         if (child == 0) {
  68                 unsigned long vdso_size = PAGE_SIZE;
  69                 unsigned long auxval;
  70                 int ret = -1;
  71 
  72                 auxval = getauxval(AT_SYSINFO_EHDR);
  73                 printf("\tAT_SYSINFO_EHDR is %#lx\n", auxval);
  74                 if (!auxval || auxval == -ENOENT) {
  75                         printf("[WARN]\tgetauxval failed\n");
  76                         return 0;
  77                 }
  78 
  79                 /* Simpler than parsing ELF header */
  80                 while (ret < 0) {
  81                         ret = try_to_remap((void *)auxval, vdso_size);
  82                         vdso_size += PAGE_SIZE;
  83                 }
  84 
  85 #ifdef __i386__
  86                 /* Glibc is likely to explode now - exit with raw syscall */
  87                 asm volatile ("int $0x80" : : "a" (__NR_exit), "b" (!!ret));
  88 #else /* __x86_64__ */
  89                 syscall(SYS_exit, ret);
  90 #endif
  91         } else {
  92                 int status;
  93 
  94                 if (waitpid(child, &status, 0) != child ||
  95                         !WIFEXITED(status)) {
  96                         printf("[FAIL]\tmremap() of the vDSO does not work on this kernel!\n");
  97                         return 1;
  98                 } else if (WEXITSTATUS(status) != 0) {
  99                         printf("[FAIL]\tChild failed with %d\n",
 100                                         WEXITSTATUS(status));
 101                         return 1;
 102                 }
 103                 printf("[OK]\n");
 104         }
 105 
 106         return 0;
 107 }

/* [<][>][^][v][top][bottom][index][help] */