xref: /linux/arch/um/os-Linux/start_up.c (revision 40d269c000bda9fcd276a0412a9cebd3f6e344c5)
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 static void stop_ptraced_child(int pid, int exitcode)
116 {
117 	int status, n;
118 
119 	if (ptrace(PTRACE_CONT, pid, 0, 0) < 0)
120 		fatal_perror("stop_ptraced_child : ptrace failed");
121 
122 	CATCH_EINTR(n = waitpid(pid, &status, 0));
123 	if (!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) {
124 		int exit_with = WEXITSTATUS(status);
125 		fatal("stop_ptraced_child : child exited with exitcode %d, "
126 		      "while expecting %d; status 0x%x\n", exit_with,
127 		      exitcode, status);
128 	}
129 }
130 
131 static void __init check_sysemu(void)
132 {
133 	int pid, n, status, count=0;
134 
135 	os_info("Checking syscall emulation for ptrace...");
136 	pid = start_ptraced_child();
137 
138 	if ((ptrace(PTRACE_SETOPTIONS, pid, 0,
139 		   (void *) PTRACE_O_TRACESYSGOOD) < 0))
140 		fatal_perror("check_sysemu: PTRACE_SETOPTIONS failed");
141 
142 	while (1) {
143 		count++;
144 		if (ptrace(PTRACE_SYSEMU_SINGLESTEP, pid, 0, 0) < 0)
145 			goto fail;
146 		CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
147 		if (n < 0)
148 			fatal_perror("check_sysemu: wait failed");
149 
150 		if (WIFSTOPPED(status) &&
151 		    (WSTOPSIG(status) == (SIGTRAP|0x80))) {
152 			if (!count) {
153 				non_fatal("check_sysemu: SYSEMU_SINGLESTEP "
154 					  "doesn't singlestep");
155 				goto fail;
156 			}
157 			n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET,
158 				   os_getpid());
159 			if (n < 0)
160 				fatal_perror("check_sysemu : failed to modify "
161 					     "system call return");
162 			break;
163 		}
164 		else if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP))
165 			count++;
166 		else {
167 			non_fatal("check_sysemu: expected SIGTRAP or "
168 				  "(SIGTRAP | 0x80), got status = %d\n",
169 				  status);
170 			goto fail;
171 		}
172 	}
173 	stop_ptraced_child(pid, 0);
174 
175 	os_info("OK\n");
176 
177 	return;
178 
179 fail:
180 	stop_ptraced_child(pid, 1);
181 	fatal("missing\n");
182 }
183 
184 static void __init check_ptrace(void)
185 {
186 	int pid, syscall, n, status;
187 
188 	os_info("Checking that ptrace can change system call numbers...");
189 	pid = start_ptraced_child();
190 
191 	if ((ptrace(PTRACE_SETOPTIONS, pid, 0,
192 		   (void *) PTRACE_O_TRACESYSGOOD) < 0))
193 		fatal_perror("check_ptrace: PTRACE_SETOPTIONS failed");
194 
195 	while (1) {
196 		if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
197 			fatal_perror("check_ptrace : ptrace failed");
198 
199 		CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
200 		if (n < 0)
201 			fatal_perror("check_ptrace : wait failed");
202 
203 		if (!WIFSTOPPED(status) ||
204 		   (WSTOPSIG(status) != (SIGTRAP | 0x80)))
205 			fatal("check_ptrace : expected (SIGTRAP|0x80), "
206 			       "got status = %d", status);
207 
208 		syscall = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET,
209 				 0);
210 		if (syscall == __NR_getpid) {
211 			n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET,
212 				   __NR_getppid);
213 			if (n < 0)
214 				fatal_perror("check_ptrace : failed to modify "
215 					     "system call");
216 			break;
217 		}
218 	}
219 	stop_ptraced_child(pid, 0);
220 	os_info("OK\n");
221 	check_sysemu();
222 }
223 
224 extern void check_tmpexec(void);
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