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