xref: /linux/arch/um/os-Linux/start_up.c (revision a55719847da0a780baa84d0baee745358f144c39)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
4  */
5 
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <stdarg.h>
9 #include <unistd.h>
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <sched.h>
13 #include <signal.h>
14 #include <string.h>
15 #include <sys/mman.h>
16 #include <sys/stat.h>
17 #include <sys/wait.h>
18 #include <sys/time.h>
19 #include <sys/resource.h>
20 #include <asm/unistd.h>
21 #include <init.h>
22 #include <os.h>
23 #include <mem_user.h>
24 #include <ptrace_user.h>
25 #include <registers.h>
26 #include <skas.h>
27 
28 static void ptrace_child(void)
29 {
30 	int ret;
31 	/* Calling os_getpid because some libcs cached getpid incorrectly */
32 	int pid = os_getpid(), ppid = getppid();
33 	int sc_result;
34 
35 	if (change_sig(SIGWINCH, 0) < 0 ||
36 	    ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) {
37 		perror("ptrace");
38 		kill(pid, SIGKILL);
39 	}
40 	kill(pid, SIGSTOP);
41 
42 	/*
43 	 * This syscall will be intercepted by the parent. Don't call more than
44 	 * once, please.
45 	 */
46 	sc_result = os_getpid();
47 
48 	if (sc_result == pid)
49 		/* Nothing modified by the parent, we are running normally. */
50 		ret = 1;
51 	else if (sc_result == ppid)
52 		/*
53 		 * Expected in check_ptrace and check_sysemu when they succeed
54 		 * in modifying the stack frame
55 		 */
56 		ret = 0;
57 	else
58 		/* Serious trouble! This could be caused by a bug in host 2.6
59 		 * SKAS3/2.6 patch before release -V6, together with a bug in
60 		 * the UML code itself.
61 		 */
62 		ret = 2;
63 
64 	exit(ret);
65 }
66 
67 static void fatal_perror(const char *str)
68 {
69 	perror(str);
70 	exit(1);
71 }
72 
73 static void fatal(char *fmt, ...)
74 {
75 	va_list list;
76 
77 	va_start(list, fmt);
78 	vfprintf(stderr, fmt, list);
79 	va_end(list);
80 
81 	exit(1);
82 }
83 
84 static void non_fatal(char *fmt, ...)
85 {
86 	va_list list;
87 
88 	va_start(list, fmt);
89 	vfprintf(stderr, fmt, list);
90 	va_end(list);
91 }
92 
93 static int start_ptraced_child(void)
94 {
95 	int pid, n, status;
96 
97 	fflush(stdout);
98 
99 	pid = fork();
100 	if (pid == 0)
101 		ptrace_child();
102 	else if (pid < 0)
103 		fatal_perror("start_ptraced_child : fork failed");
104 
105 	CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
106 	if (n < 0)
107 		fatal_perror("check_ptrace : waitpid failed");
108 	if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
109 		fatal("check_ptrace : expected SIGSTOP, got status = %d",
110 		      status);
111 
112 	return pid;
113 }
114 
115 /* When testing for SYSEMU support, if it is one of the broken versions, we
116  * must just avoid using sysemu, not panic, but only if SYSEMU features are
117  * broken.
118  * So only for SYSEMU features we test mustpanic, while normal host features
119  * must work anyway!
120  */
121 static int stop_ptraced_child(int pid, int exitcode, int mustexit)
122 {
123 	int status, n, ret = 0;
124 
125 	if (ptrace(PTRACE_CONT, pid, 0, 0) < 0) {
126 		perror("stop_ptraced_child : ptrace failed");
127 		return -1;
128 	}
129 	CATCH_EINTR(n = waitpid(pid, &status, 0));
130 	if (!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) {
131 		int exit_with = WEXITSTATUS(status);
132 		if (exit_with == 2)
133 			non_fatal("check_ptrace : child exited with status 2. "
134 				  "\nDisabling SYSEMU support.\n");
135 		non_fatal("check_ptrace : child exited with exitcode %d, while "
136 			  "expecting %d; status 0x%x\n", exit_with,
137 			  exitcode, status);
138 		if (mustexit)
139 			exit(1);
140 		ret = -1;
141 	}
142 
143 	return ret;
144 }
145 
146 static void __init check_sysemu(void)
147 {
148 	int pid, n, status, count=0;
149 
150 	os_info("Checking syscall emulation for ptrace...");
151 	pid = start_ptraced_child();
152 
153 	if ((ptrace(PTRACE_SETOPTIONS, pid, 0,
154 		   (void *) PTRACE_O_TRACESYSGOOD) < 0))
155 		fatal_perror("check_sysemu: PTRACE_SETOPTIONS failed");
156 
157 	while (1) {
158 		count++;
159 		if (ptrace(PTRACE_SYSEMU_SINGLESTEP, pid, 0, 0) < 0)
160 			goto fail;
161 		CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
162 		if (n < 0)
163 			fatal_perror("check_sysemu: wait failed");
164 
165 		if (WIFSTOPPED(status) &&
166 		    (WSTOPSIG(status) == (SIGTRAP|0x80))) {
167 			if (!count) {
168 				non_fatal("check_sysemu: SYSEMU_SINGLESTEP "
169 					  "doesn't singlestep");
170 				goto fail;
171 			}
172 			n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET,
173 				   os_getpid());
174 			if (n < 0)
175 				fatal_perror("check_sysemu : failed to modify "
176 					     "system call return");
177 			break;
178 		}
179 		else if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP))
180 			count++;
181 		else {
182 			non_fatal("check_sysemu: expected SIGTRAP or "
183 				  "(SIGTRAP | 0x80), got status = %d\n",
184 				  status);
185 			goto fail;
186 		}
187 	}
188 	if (stop_ptraced_child(pid, 0, 0) < 0)
189 		goto fail_stopped;
190 
191 	os_info("OK\n");
192 
193 	return;
194 
195 fail:
196 	stop_ptraced_child(pid, 1, 0);
197 fail_stopped:
198 	fatal("missing\n");
199 }
200 
201 static void __init check_ptrace(void)
202 {
203 	int pid, syscall, n, status;
204 
205 	os_info("Checking that ptrace can change system call numbers...");
206 	pid = start_ptraced_child();
207 
208 	if ((ptrace(PTRACE_SETOPTIONS, pid, 0,
209 		   (void *) PTRACE_O_TRACESYSGOOD) < 0))
210 		fatal_perror("check_ptrace: PTRACE_SETOPTIONS failed");
211 
212 	while (1) {
213 		if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
214 			fatal_perror("check_ptrace : ptrace failed");
215 
216 		CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
217 		if (n < 0)
218 			fatal_perror("check_ptrace : wait failed");
219 
220 		if (!WIFSTOPPED(status) ||
221 		   (WSTOPSIG(status) != (SIGTRAP | 0x80)))
222 			fatal("check_ptrace : expected (SIGTRAP|0x80), "
223 			       "got status = %d", status);
224 
225 		syscall = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET,
226 				 0);
227 		if (syscall == __NR_getpid) {
228 			n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET,
229 				   __NR_getppid);
230 			if (n < 0)
231 				fatal_perror("check_ptrace : failed to modify "
232 					     "system call");
233 			break;
234 		}
235 	}
236 	stop_ptraced_child(pid, 0, 1);
237 	os_info("OK\n");
238 	check_sysemu();
239 }
240 
241 extern void check_tmpexec(void);
242 
243 static void __init check_coredump_limit(void)
244 {
245 	struct rlimit lim;
246 	int err = getrlimit(RLIMIT_CORE, &lim);
247 
248 	if (err) {
249 		perror("Getting core dump limit");
250 		return;
251 	}
252 
253 	os_info("Core dump limits :\n\tsoft - ");
254 	if (lim.rlim_cur == RLIM_INFINITY)
255 		os_info("NONE\n");
256 	else
257 		os_info("%llu\n", (unsigned long long)lim.rlim_cur);
258 
259 	os_info("\thard - ");
260 	if (lim.rlim_max == RLIM_INFINITY)
261 		os_info("NONE\n");
262 	else
263 		os_info("%llu\n", (unsigned long long)lim.rlim_max);
264 }
265 
266 void  __init get_host_cpu_features(
267 		void (*flags_helper_func)(char *line),
268 		void (*cache_helper_func)(char *line))
269 {
270 	FILE *cpuinfo;
271 	char *line = NULL;
272 	size_t len = 0;
273 	int done_parsing = 0;
274 
275 	cpuinfo = fopen("/proc/cpuinfo", "r");
276 	if (cpuinfo == NULL) {
277 		os_info("Failed to get host CPU features\n");
278 	} else {
279 		while ((getline(&line, &len, cpuinfo)) != -1) {
280 			if (strstr(line, "flags")) {
281 				flags_helper_func(line);
282 				done_parsing++;
283 			}
284 			if (strstr(line, "cache_alignment")) {
285 				cache_helper_func(line);
286 				done_parsing++;
287 			}
288 			free(line);
289 			line = NULL;
290 			if (done_parsing > 1)
291 				break;
292 		}
293 		fclose(cpuinfo);
294 	}
295 }
296 
297 
298 void __init os_early_checks(void)
299 {
300 	int pid;
301 
302 	/* Print out the core dump limits early */
303 	check_coredump_limit();
304 
305 	check_ptrace();
306 
307 	/* Need to check this early because mmapping happens before the
308 	 * kernel is running.
309 	 */
310 	check_tmpexec();
311 
312 	pid = start_ptraced_child();
313 	if (init_pid_registers(pid))
314 		fatal("Failed to initialize default registers");
315 	stop_ptraced_child(pid, 1, 1);
316 }
317 
318 int __init parse_iomem(char *str, int *add)
319 {
320 	struct iomem_region *new;
321 	struct stat64 buf;
322 	char *file, *driver;
323 	int fd, size;
324 
325 	driver = str;
326 	file = strchr(str,',');
327 	if (file == NULL) {
328 		os_warn("parse_iomem : failed to parse iomem\n");
329 		goto out;
330 	}
331 	*file = '\0';
332 	file++;
333 	fd = open(file, O_RDWR, 0);
334 	if (fd < 0) {
335 		perror("parse_iomem - Couldn't open io file");
336 		goto out;
337 	}
338 
339 	if (fstat64(fd, &buf) < 0) {
340 		perror("parse_iomem - cannot stat_fd file");
341 		goto out_close;
342 	}
343 
344 	new = malloc(sizeof(*new));
345 	if (new == NULL) {
346 		perror("Couldn't allocate iomem_region struct");
347 		goto out_close;
348 	}
349 
350 	size = (buf.st_size + UM_KERN_PAGE_SIZE) & ~(UM_KERN_PAGE_SIZE - 1);
351 
352 	*new = ((struct iomem_region) { .next		= iomem_regions,
353 					.driver		= driver,
354 					.fd		= fd,
355 					.size		= size,
356 					.phys		= 0,
357 					.virt		= 0 });
358 	iomem_regions = new;
359 	iomem_size += new->size + UM_KERN_PAGE_SIZE;
360 
361 	return 0;
362  out_close:
363 	close(fd);
364  out:
365 	return 1;
366 }
367