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 
badds(void)33 static void badds(void)
34 {
35 	__asm__ volatile("movw %0, %%ds" : : "r" (selector));
36 }
37 
bades(void)38 static void bades(void)
39 {
40 	__asm__ volatile("movw %0, %%es" : : "r" (selector));
41 }
42 
badfs(void)43 static void badfs(void)
44 {
45 	__asm__ volatile("movw %0, %%fs" : : "r" (selector));
46 }
47 
badgs(void)48 static void badgs(void)
49 {
50 	__asm__ volatile("movw %0, %%gs" : : "r" (selector));
51 }
52 
badss(void)53 static void badss(void)
54 {
55 	__asm__ volatile("movw %0, %%ss" : : "r" (selector));
56 }
57 
58 static void
resetseg(uint_t seg)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
resetcs(void)79 resetcs(void)
80 {
81 	return (resetseg(CS));
82 }
83 
84 static void
resetds(void)85 resetds(void)
86 {
87 	return (resetseg(DS));
88 }
89 
90 static void
resetes(void)91 resetes(void)
92 {
93 	return (resetseg(ES));
94 }
95 
96 static void
resetfs(void)97 resetfs(void)
98 {
99 	return (resetseg(FS));
100 }
101 
102 static void
resetgs(void)103 resetgs(void)
104 {
105 	return (resetseg(GS));
106 }
107 
108 static void
resetss(void)109 resetss(void)
110 {
111 	return (resetseg(SS));
112 }
113 
114 static void
inchild(void (* func)())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
main(int argc,char * argv[])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 }
157