0001
0002
0003
0004
0005
0006 #include <stdio.h>
0007 #include <stdlib.h>
0008 #include <stdarg.h>
0009 #include <unistd.h>
0010 #include <errno.h>
0011 #include <fcntl.h>
0012 #include <sched.h>
0013 #include <signal.h>
0014 #include <string.h>
0015 #include <sys/mman.h>
0016 #include <sys/stat.h>
0017 #include <sys/wait.h>
0018 #include <sys/time.h>
0019 #include <sys/resource.h>
0020 #include <asm/unistd.h>
0021 #include <init.h>
0022 #include <os.h>
0023 #include <mem_user.h>
0024 #include <ptrace_user.h>
0025 #include <registers.h>
0026 #include <skas.h>
0027
0028 static void ptrace_child(void)
0029 {
0030 int ret;
0031
0032 int pid = os_getpid(), ppid = getppid();
0033 int sc_result;
0034
0035 if (change_sig(SIGWINCH, 0) < 0 ||
0036 ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) {
0037 perror("ptrace");
0038 kill(pid, SIGKILL);
0039 }
0040 kill(pid, SIGSTOP);
0041
0042
0043
0044
0045
0046 sc_result = os_getpid();
0047
0048 if (sc_result == pid)
0049
0050 ret = 1;
0051 else if (sc_result == ppid)
0052
0053
0054
0055
0056 ret = 0;
0057 else
0058
0059
0060
0061
0062 ret = 2;
0063
0064 exit(ret);
0065 }
0066
0067 static void fatal_perror(const char *str)
0068 {
0069 perror(str);
0070 exit(1);
0071 }
0072
0073 static void fatal(char *fmt, ...)
0074 {
0075 va_list list;
0076
0077 va_start(list, fmt);
0078 vfprintf(stderr, fmt, list);
0079 va_end(list);
0080
0081 exit(1);
0082 }
0083
0084 static void non_fatal(char *fmt, ...)
0085 {
0086 va_list list;
0087
0088 va_start(list, fmt);
0089 vfprintf(stderr, fmt, list);
0090 va_end(list);
0091 }
0092
0093 static int start_ptraced_child(void)
0094 {
0095 int pid, n, status;
0096
0097 fflush(stdout);
0098
0099 pid = fork();
0100 if (pid == 0)
0101 ptrace_child();
0102 else if (pid < 0)
0103 fatal_perror("start_ptraced_child : fork failed");
0104
0105 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
0106 if (n < 0)
0107 fatal_perror("check_ptrace : waitpid failed");
0108 if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
0109 fatal("check_ptrace : expected SIGSTOP, got status = %d",
0110 status);
0111
0112 return pid;
0113 }
0114
0115
0116
0117
0118
0119
0120
0121 static int stop_ptraced_child(int pid, int exitcode, int mustexit)
0122 {
0123 int status, n, ret = 0;
0124
0125 if (ptrace(PTRACE_CONT, pid, 0, 0) < 0) {
0126 perror("stop_ptraced_child : ptrace failed");
0127 return -1;
0128 }
0129 CATCH_EINTR(n = waitpid(pid, &status, 0));
0130 if (!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) {
0131 int exit_with = WEXITSTATUS(status);
0132 if (exit_with == 2)
0133 non_fatal("check_ptrace : child exited with status 2. "
0134 "\nDisabling SYSEMU support.\n");
0135 non_fatal("check_ptrace : child exited with exitcode %d, while "
0136 "expecting %d; status 0x%x\n", exit_with,
0137 exitcode, status);
0138 if (mustexit)
0139 exit(1);
0140 ret = -1;
0141 }
0142
0143 return ret;
0144 }
0145
0146
0147 static int force_sysemu_disabled = 0;
0148
0149 static int __init nosysemu_cmd_param(char *str, int* add)
0150 {
0151 force_sysemu_disabled = 1;
0152 return 0;
0153 }
0154
0155 __uml_setup("nosysemu", nosysemu_cmd_param,
0156 "nosysemu\n"
0157 " Turns off syscall emulation patch for ptrace (SYSEMU).\n"
0158 " SYSEMU is a performance-patch introduced by Laurent Vivier. It changes\n"
0159 " behaviour of ptrace() and helps reduce host context switch rates.\n"
0160 " To make it work, you need a kernel patch for your host, too.\n"
0161 " See http://perso.wanadoo.fr/laurent.vivier/UML/ for further \n"
0162 " information.\n\n");
0163
0164 static void __init check_sysemu(void)
0165 {
0166 unsigned long regs[MAX_REG_NR];
0167 int pid, n, status, count=0;
0168
0169 os_info("Checking syscall emulation patch for ptrace...");
0170 sysemu_supported = 0;
0171 pid = start_ptraced_child();
0172
0173 if (ptrace(PTRACE_SYSEMU, pid, 0, 0) < 0)
0174 goto fail;
0175
0176 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
0177 if (n < 0)
0178 fatal_perror("check_sysemu : wait failed");
0179 if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
0180 fatal("check_sysemu : expected SIGTRAP, got status = %d\n",
0181 status);
0182
0183 if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0)
0184 fatal_perror("check_sysemu : PTRACE_GETREGS failed");
0185 if (PT_SYSCALL_NR(regs) != __NR_getpid) {
0186 non_fatal("check_sysemu got system call number %d, "
0187 "expected %d...", PT_SYSCALL_NR(regs), __NR_getpid);
0188 goto fail;
0189 }
0190
0191 n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, os_getpid());
0192 if (n < 0) {
0193 non_fatal("check_sysemu : failed to modify system call "
0194 "return");
0195 goto fail;
0196 }
0197
0198 if (stop_ptraced_child(pid, 0, 0) < 0)
0199 goto fail_stopped;
0200
0201 sysemu_supported = 1;
0202 os_info("OK\n");
0203 set_using_sysemu(!force_sysemu_disabled);
0204
0205 os_info("Checking advanced syscall emulation patch for ptrace...");
0206 pid = start_ptraced_child();
0207
0208 if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0,
0209 (void *) PTRACE_O_TRACESYSGOOD) < 0))
0210 fatal_perror("check_sysemu: PTRACE_OLDSETOPTIONS failed");
0211
0212 while (1) {
0213 count++;
0214 if (ptrace(PTRACE_SYSEMU_SINGLESTEP, pid, 0, 0) < 0)
0215 goto fail;
0216 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
0217 if (n < 0)
0218 fatal_perror("check_sysemu: wait failed");
0219
0220 if (WIFSTOPPED(status) &&
0221 (WSTOPSIG(status) == (SIGTRAP|0x80))) {
0222 if (!count) {
0223 non_fatal("check_sysemu: SYSEMU_SINGLESTEP "
0224 "doesn't singlestep");
0225 goto fail;
0226 }
0227 n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET,
0228 os_getpid());
0229 if (n < 0)
0230 fatal_perror("check_sysemu : failed to modify "
0231 "system call return");
0232 break;
0233 }
0234 else if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP))
0235 count++;
0236 else {
0237 non_fatal("check_sysemu: expected SIGTRAP or "
0238 "(SIGTRAP | 0x80), got status = %d\n",
0239 status);
0240 goto fail;
0241 }
0242 }
0243 if (stop_ptraced_child(pid, 0, 0) < 0)
0244 goto fail_stopped;
0245
0246 sysemu_supported = 2;
0247 os_info("OK\n");
0248
0249 if (!force_sysemu_disabled)
0250 set_using_sysemu(sysemu_supported);
0251 return;
0252
0253 fail:
0254 stop_ptraced_child(pid, 1, 0);
0255 fail_stopped:
0256 non_fatal("missing\n");
0257 }
0258
0259 static void __init check_ptrace(void)
0260 {
0261 int pid, syscall, n, status;
0262
0263 os_info("Checking that ptrace can change system call numbers...");
0264 pid = start_ptraced_child();
0265
0266 if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0,
0267 (void *) PTRACE_O_TRACESYSGOOD) < 0))
0268 fatal_perror("check_ptrace: PTRACE_OLDSETOPTIONS failed");
0269
0270 while (1) {
0271 if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
0272 fatal_perror("check_ptrace : ptrace failed");
0273
0274 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
0275 if (n < 0)
0276 fatal_perror("check_ptrace : wait failed");
0277
0278 if (!WIFSTOPPED(status) ||
0279 (WSTOPSIG(status) != (SIGTRAP | 0x80)))
0280 fatal("check_ptrace : expected (SIGTRAP|0x80), "
0281 "got status = %d", status);
0282
0283 syscall = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET,
0284 0);
0285 if (syscall == __NR_getpid) {
0286 n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET,
0287 __NR_getppid);
0288 if (n < 0)
0289 fatal_perror("check_ptrace : failed to modify "
0290 "system call");
0291 break;
0292 }
0293 }
0294 stop_ptraced_child(pid, 0, 1);
0295 os_info("OK\n");
0296 check_sysemu();
0297 }
0298
0299 extern void check_tmpexec(void);
0300
0301 static void __init check_coredump_limit(void)
0302 {
0303 struct rlimit lim;
0304 int err = getrlimit(RLIMIT_CORE, &lim);
0305
0306 if (err) {
0307 perror("Getting core dump limit");
0308 return;
0309 }
0310
0311 os_info("Core dump limits :\n\tsoft - ");
0312 if (lim.rlim_cur == RLIM_INFINITY)
0313 os_info("NONE\n");
0314 else
0315 os_info("%llu\n", (unsigned long long)lim.rlim_cur);
0316
0317 os_info("\thard - ");
0318 if (lim.rlim_max == RLIM_INFINITY)
0319 os_info("NONE\n");
0320 else
0321 os_info("%llu\n", (unsigned long long)lim.rlim_max);
0322 }
0323
0324 void __init get_host_cpu_features(
0325 void (*flags_helper_func)(char *line),
0326 void (*cache_helper_func)(char *line))
0327 {
0328 FILE *cpuinfo;
0329 char *line = NULL;
0330 size_t len = 0;
0331 int done_parsing = 0;
0332
0333 cpuinfo = fopen("/proc/cpuinfo", "r");
0334 if (cpuinfo == NULL) {
0335 os_info("Failed to get host CPU features\n");
0336 } else {
0337 while ((getline(&line, &len, cpuinfo)) != -1) {
0338 if (strstr(line, "flags")) {
0339 flags_helper_func(line);
0340 done_parsing++;
0341 }
0342 if (strstr(line, "cache_alignment")) {
0343 cache_helper_func(line);
0344 done_parsing++;
0345 }
0346 free(line);
0347 line = NULL;
0348 if (done_parsing > 1)
0349 break;
0350 }
0351 fclose(cpuinfo);
0352 }
0353 }
0354
0355
0356 void __init os_early_checks(void)
0357 {
0358 int pid;
0359
0360
0361 check_coredump_limit();
0362
0363 check_ptrace();
0364
0365
0366
0367
0368 check_tmpexec();
0369
0370 pid = start_ptraced_child();
0371 if (init_pid_registers(pid))
0372 fatal("Failed to initialize default registers");
0373 stop_ptraced_child(pid, 1, 1);
0374 }
0375
0376 int __init parse_iomem(char *str, int *add)
0377 {
0378 struct iomem_region *new;
0379 struct stat64 buf;
0380 char *file, *driver;
0381 int fd, size;
0382
0383 driver = str;
0384 file = strchr(str,',');
0385 if (file == NULL) {
0386 os_warn("parse_iomem : failed to parse iomem\n");
0387 goto out;
0388 }
0389 *file = '\0';
0390 file++;
0391 fd = open(file, O_RDWR, 0);
0392 if (fd < 0) {
0393 perror("parse_iomem - Couldn't open io file");
0394 goto out;
0395 }
0396
0397 if (fstat64(fd, &buf) < 0) {
0398 perror("parse_iomem - cannot stat_fd file");
0399 goto out_close;
0400 }
0401
0402 new = malloc(sizeof(*new));
0403 if (new == NULL) {
0404 perror("Couldn't allocate iomem_region struct");
0405 goto out_close;
0406 }
0407
0408 size = (buf.st_size + UM_KERN_PAGE_SIZE) & ~(UM_KERN_PAGE_SIZE - 1);
0409
0410 *new = ((struct iomem_region) { .next = iomem_regions,
0411 .driver = driver,
0412 .fd = fd,
0413 .size = size,
0414 .phys = 0,
0415 .virt = 0 });
0416 iomem_regions = new;
0417 iomem_size += new->size + UM_KERN_PAGE_SIZE;
0418
0419 return 0;
0420 out_close:
0421 close(fd);
0422 out:
0423 return 1;
0424 }