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