1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2019 Joyent, Inc.
  14  */
  15 
  16 #include <stdlib.h>
  17 #include <ucontext.h>
  18 #include <sys/wait.h>
  19 #include <unistd.h>
  20 #include <sys/regset.h>
  21 #include <sys/resource.h>
  22 #include <err.h>
  23 
  24 /*
  25  * Load a bunch of bad selectors into the seg regs: this will typically cause
  26  * the child process to core dump, but it shouldn't panic the kernel...
  27  *
  28  * It's especially interesting to run this on CPU0.
  29  */
  30 
  31 unsigned short selector;
  32 
  33 static void badds(void)
  34 {
  35         __asm__ volatile("movw %0, %%ds" : : "r" (selector));
  36 }
  37 
  38 static void bades(void)
  39 {
  40         __asm__ volatile("movw %0, %%es" : : "r" (selector));
  41 }
  42 
  43 static void badfs(void)
  44 {
  45         __asm__ volatile("movw %0, %%fs" : : "r" (selector));
  46 }
  47 
  48 static void badgs(void)
  49 {
  50         __asm__ volatile("movw %0, %%gs" : : "r" (selector));
  51 }
  52 
  53 static void badss(void)
  54 {
  55         __asm__ volatile("movw %0, %%ss" : : "r" (selector));
  56 }
  57 
  58 static void
  59 resetseg(uint_t seg)
  60 {
  61         ucontext_t ucp;
  62         volatile int done = 0;
  63 
  64         int rc = getcontext(&ucp);
  65         if (done) {
  66                 (void) getcontext(&ucp);
  67                 return;
  68         }
  69 
  70         if (rc == 0) {
  71                 done = 1;
  72                 ucp.uc_mcontext.gregs[seg] = selector;
  73                 (void) setcontext(&ucp);
  74         }
  75         abort();
  76 }
  77 
  78 static void
  79 resetcs(void)
  80 {
  81         return (resetseg(CS));
  82 }
  83 
  84 static void
  85 resetds(void)
  86 {
  87         return (resetseg(DS));
  88 }
  89 
  90 static void
  91 resetes(void)
  92 {
  93         return (resetseg(ES));
  94 }
  95 
  96 static void
  97 resetfs(void)
  98 {
  99         return (resetseg(FS));
 100 }
 101 
 102 static void
 103 resetgs(void)
 104 {
 105         return (resetseg(GS));
 106 }
 107 
 108 static void
 109 resetss(void)
 110 {
 111         return (resetseg(SS));
 112 }
 113 
 114 static void
 115 inchild(void (*func)())
 116 {
 117         pid_t pid;
 118 
 119         switch ((pid = fork())) {
 120         case 0:
 121                 func();
 122                 exit(EXIT_SUCCESS);
 123         case -1:
 124                 exit(EXIT_FAILURE);
 125         default:
 126                 (void) waitpid(pid, NULL, 0);
 127                 return;
 128         }
 129 
 130 }
 131 
 132 int
 133 main(int argc, char *argv[])
 134 {
 135         struct rlimit rl = { 0, };
 136 
 137         if (setrlimit(RLIMIT_CORE, &rl) != 0) {
 138                 err(EXIT_FAILURE, "failed to disable cores");
 139         }
 140 
 141         for (selector = 0; selector < 512; selector++) {
 142                 inchild(resetcs);
 143                 inchild(resetds);
 144                 inchild(resetes);
 145                 inchild(resetfs);
 146                 inchild(resetgs);
 147                 inchild(resetss);
 148                 inchild(badds);
 149                 inchild(bades);
 150                 inchild(badfs);
 151                 inchild(badgs);
 152                 inchild(badss);
 153         }
 154 
 155         exit(EXIT_SUCCESS);
 156 }