]> Git Repo - J-linux.git/blob - arch/um/os-Linux/start_up.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / arch / um / os-Linux / start_up.c
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 }
This page took 0.04603 seconds and 4 git commands to generate.