xref: /linux/arch/um/os-Linux/start_up.c (revision 49ff7d871242d7fd8adb8a2d8347c5d94dda808b)
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 
29 static void ptrace_child(void)
30 {
31 	int ret;
32 	/* Calling os_getpid because some libcs cached getpid incorrectly */
33 	int pid = os_getpid(), ppid = getppid();
34 	int sc_result;
35 
36 	if (change_sig(SIGWINCH, 0) < 0 ||
37 	    ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) {
38 		perror("ptrace");
39 		kill(pid, SIGKILL);
40 	}
41 	kill(pid, SIGSTOP);
42 
43 	/*
44 	 * This syscall will be intercepted by the parent. Don't call more than
45 	 * once, please.
46 	 */
47 	sc_result = os_getpid();
48 
49 	if (sc_result == pid)
50 		/* Nothing modified by the parent, we are running normally. */
51 		ret = 1;
52 	else if (sc_result == ppid)
53 		/*
54 		 * Expected in check_ptrace and check_sysemu when they succeed
55 		 * in modifying the stack frame
56 		 */
57 		ret = 0;
58 	else
59 		/* Serious trouble! This could be caused by a bug in host 2.6
60 		 * SKAS3/2.6 patch before release -V6, together with a bug in
61 		 * the UML code itself.
62 		 */
63 		ret = 2;
64 
65 	exit(ret);
66 }
67 
68 static void fatal_perror(const char *str)
69 {
70 	perror(str);
71 	exit(1);
72 }
73 
74 static void fatal(char *fmt, ...)
75 {
76 	va_list list;
77 
78 	va_start(list, fmt);
79 	vfprintf(stderr, fmt, list);
80 	va_end(list);
81 
82 	exit(1);
83 }
84 
85 static void non_fatal(char *fmt, ...)
86 {
87 	va_list list;
88 
89 	va_start(list, fmt);
90 	vfprintf(stderr, fmt, list);
91 	va_end(list);
92 }
93 
94 static int start_ptraced_child(void)
95 {
96 	int pid, n, status;
97 
98 	fflush(stdout);
99 
100 	pid = fork();
101 	if (pid == 0)
102 		ptrace_child();
103 	else if (pid < 0)
104 		fatal_perror("start_ptraced_child : fork failed");
105 
106 	CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
107 	if (n < 0)
108 		fatal_perror("check_ptrace : waitpid failed");
109 	if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
110 		fatal("check_ptrace : expected SIGSTOP, got status = %d",
111 		      status);
112 
113 	return pid;
114 }
115 
116 static void stop_ptraced_child(int pid, int exitcode)
117 {
118 	int status, n;
119 
120 	if (ptrace(PTRACE_CONT, pid, 0, 0) < 0)
121 		fatal_perror("stop_ptraced_child : ptrace failed");
122 
123 	CATCH_EINTR(n = waitpid(pid, &status, 0));
124 	if (!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) {
125 		int exit_with = WEXITSTATUS(status);
126 		fatal("stop_ptraced_child : child exited with exitcode %d, "
127 		      "while expecting %d; status 0x%x\n", exit_with,
128 		      exitcode, status);
129 	}
130 }
131 
132 static void __init check_sysemu(void)
133 {
134 	int pid, n, status, count=0;
135 
136 	os_info("Checking syscall emulation for ptrace...");
137 	pid = start_ptraced_child();
138 
139 	if ((ptrace(PTRACE_SETOPTIONS, pid, 0,
140 		   (void *) PTRACE_O_TRACESYSGOOD) < 0))
141 		fatal_perror("check_sysemu: PTRACE_SETOPTIONS failed");
142 
143 	while (1) {
144 		count++;
145 		if (ptrace(PTRACE_SYSEMU_SINGLESTEP, pid, 0, 0) < 0)
146 			goto fail;
147 		CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
148 		if (n < 0)
149 			fatal_perror("check_sysemu: wait failed");
150 
151 		if (WIFSTOPPED(status) &&
152 		    (WSTOPSIG(status) == (SIGTRAP|0x80))) {
153 			if (!count) {
154 				non_fatal("check_sysemu: SYSEMU_SINGLESTEP "
155 					  "doesn't singlestep");
156 				goto fail;
157 			}
158 			n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET,
159 				   os_getpid());
160 			if (n < 0)
161 				fatal_perror("check_sysemu : failed to modify "
162 					     "system call return");
163 			break;
164 		}
165 		else if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP))
166 			count++;
167 		else {
168 			non_fatal("check_sysemu: expected SIGTRAP or "
169 				  "(SIGTRAP | 0x80), got status = %d\n",
170 				  status);
171 			goto fail;
172 		}
173 	}
174 	stop_ptraced_child(pid, 0);
175 
176 	os_info("OK\n");
177 
178 	return;
179 
180 fail:
181 	stop_ptraced_child(pid, 1);
182 	fatal("missing\n");
183 }
184 
185 static void __init check_ptrace(void)
186 {
187 	int pid, syscall, n, status;
188 
189 	os_info("Checking that ptrace can change system call numbers...");
190 	pid = start_ptraced_child();
191 
192 	if ((ptrace(PTRACE_SETOPTIONS, pid, 0,
193 		   (void *) PTRACE_O_TRACESYSGOOD) < 0))
194 		fatal_perror("check_ptrace: PTRACE_SETOPTIONS failed");
195 
196 	while (1) {
197 		if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
198 			fatal_perror("check_ptrace : ptrace failed");
199 
200 		CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
201 		if (n < 0)
202 			fatal_perror("check_ptrace : wait failed");
203 
204 		if (!WIFSTOPPED(status) ||
205 		   (WSTOPSIG(status) != (SIGTRAP | 0x80)))
206 			fatal("check_ptrace : expected (SIGTRAP|0x80), "
207 			       "got status = %d", status);
208 
209 		syscall = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET,
210 				 0);
211 		if (syscall == __NR_getpid) {
212 			n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET,
213 				   __NR_getppid);
214 			if (n < 0)
215 				fatal_perror("check_ptrace : failed to modify "
216 					     "system call");
217 			break;
218 		}
219 	}
220 	stop_ptraced_child(pid, 0);
221 	os_info("OK\n");
222 	check_sysemu();
223 }
224 
225 extern void check_tmpexec(void);
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