162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <stdarg.h> 762306a36Sopenharmony_ci#include <stdio.h> 862306a36Sopenharmony_ci#include <stdlib.h> 962306a36Sopenharmony_ci#include <unistd.h> 1062306a36Sopenharmony_ci#include <errno.h> 1162306a36Sopenharmony_ci#include <signal.h> 1262306a36Sopenharmony_ci#include <string.h> 1362306a36Sopenharmony_ci#include <termios.h> 1462306a36Sopenharmony_ci#include <sys/wait.h> 1562306a36Sopenharmony_ci#include <sys/mman.h> 1662306a36Sopenharmony_ci#include <sys/utsname.h> 1762306a36Sopenharmony_ci#include <sys/random.h> 1862306a36Sopenharmony_ci#include <init.h> 1962306a36Sopenharmony_ci#include <os.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_civoid stack_protections(unsigned long address) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci if (mprotect((void *) address, UM_THREAD_SIZE, 2462306a36Sopenharmony_ci PROT_READ | PROT_WRITE | PROT_EXEC) < 0) 2562306a36Sopenharmony_ci panic("protecting stack failed, errno = %d", errno); 2662306a36Sopenharmony_ci} 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ciint raw(int fd) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci struct termios tt; 3162306a36Sopenharmony_ci int err; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci CATCH_EINTR(err = tcgetattr(fd, &tt)); 3462306a36Sopenharmony_ci if (err < 0) 3562306a36Sopenharmony_ci return -errno; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci cfmakeraw(&tt); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci CATCH_EINTR(err = tcsetattr(fd, TCSADRAIN, &tt)); 4062306a36Sopenharmony_ci if (err < 0) 4162306a36Sopenharmony_ci return -errno; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci /* 4462306a36Sopenharmony_ci * XXX tcsetattr could have applied only some changes 4562306a36Sopenharmony_ci * (and cfmakeraw() is a set of changes) 4662306a36Sopenharmony_ci */ 4762306a36Sopenharmony_ci return 0; 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_civoid setup_machinename(char *machine_out) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci struct utsname host; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci uname(&host); 5562306a36Sopenharmony_ci#ifdef UML_CONFIG_UML_X86 5662306a36Sopenharmony_ci# ifndef UML_CONFIG_64BIT 5762306a36Sopenharmony_ci if (!strcmp(host.machine, "x86_64")) { 5862306a36Sopenharmony_ci strcpy(machine_out, "i686"); 5962306a36Sopenharmony_ci return; 6062306a36Sopenharmony_ci } 6162306a36Sopenharmony_ci# else 6262306a36Sopenharmony_ci if (!strcmp(host.machine, "i686")) { 6362306a36Sopenharmony_ci strcpy(machine_out, "x86_64"); 6462306a36Sopenharmony_ci return; 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci# endif 6762306a36Sopenharmony_ci#endif 6862306a36Sopenharmony_ci strcpy(machine_out, host.machine); 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_civoid setup_hostinfo(char *buf, int len) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci struct utsname host; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci uname(&host); 7662306a36Sopenharmony_ci snprintf(buf, len, "%s %s %s %s %s", host.sysname, host.nodename, 7762306a36Sopenharmony_ci host.release, host.version, host.machine); 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci/* 8162306a36Sopenharmony_ci * We cannot use glibc's abort(). It makes use of tgkill() which 8262306a36Sopenharmony_ci * has no effect within UML's kernel threads. 8362306a36Sopenharmony_ci * After that glibc would execute an invalid instruction to kill 8462306a36Sopenharmony_ci * the calling process and UML crashes with SIGSEGV. 8562306a36Sopenharmony_ci */ 8662306a36Sopenharmony_cistatic inline void __attribute__ ((noreturn)) uml_abort(void) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci sigset_t sig; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci fflush(NULL); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci if (!sigemptyset(&sig) && !sigaddset(&sig, SIGABRT)) 9362306a36Sopenharmony_ci sigprocmask(SIG_UNBLOCK, &sig, 0); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci for (;;) 9662306a36Sopenharmony_ci if (kill(getpid(), SIGABRT) < 0) 9762306a36Sopenharmony_ci exit(127); 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cissize_t os_getrandom(void *buf, size_t len, unsigned int flags) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci return getrandom(buf, len, flags); 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci/* 10662306a36Sopenharmony_ci * UML helper threads must not handle SIGWINCH/INT/TERM 10762306a36Sopenharmony_ci */ 10862306a36Sopenharmony_civoid os_fix_helper_signals(void) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci signal(SIGWINCH, SIG_IGN); 11162306a36Sopenharmony_ci signal(SIGINT, SIG_DFL); 11262306a36Sopenharmony_ci signal(SIGTERM, SIG_DFL); 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_civoid os_dump_core(void) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci int pid; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci signal(SIGSEGV, SIG_DFL); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci /* 12262306a36Sopenharmony_ci * We are about to SIGTERM this entire process group to ensure that 12362306a36Sopenharmony_ci * nothing is around to run after the kernel exits. The 12462306a36Sopenharmony_ci * kernel wants to abort, not die through SIGTERM, so we 12562306a36Sopenharmony_ci * ignore it here. 12662306a36Sopenharmony_ci */ 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci signal(SIGTERM, SIG_IGN); 12962306a36Sopenharmony_ci kill(0, SIGTERM); 13062306a36Sopenharmony_ci /* 13162306a36Sopenharmony_ci * Most of the other processes associated with this UML are 13262306a36Sopenharmony_ci * likely sTopped, so give them a SIGCONT so they see the 13362306a36Sopenharmony_ci * SIGTERM. 13462306a36Sopenharmony_ci */ 13562306a36Sopenharmony_ci kill(0, SIGCONT); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* 13862306a36Sopenharmony_ci * Now, having sent signals to everyone but us, make sure they 13962306a36Sopenharmony_ci * die by ptrace. Processes can survive what's been done to 14062306a36Sopenharmony_ci * them so far - the mechanism I understand is receiving a 14162306a36Sopenharmony_ci * SIGSEGV and segfaulting immediately upon return. There is 14262306a36Sopenharmony_ci * always a SIGSEGV pending, and (I'm guessing) signals are 14362306a36Sopenharmony_ci * processed in numeric order so the SIGTERM (signal 15 vs 14462306a36Sopenharmony_ci * SIGSEGV being signal 11) is never handled. 14562306a36Sopenharmony_ci * 14662306a36Sopenharmony_ci * Run a waitpid loop until we get some kind of error. 14762306a36Sopenharmony_ci * Hopefully, it's ECHILD, but there's not a lot we can do if 14862306a36Sopenharmony_ci * it's something else. Tell os_kill_ptraced_process not to 14962306a36Sopenharmony_ci * wait for the child to report its death because there's 15062306a36Sopenharmony_ci * nothing reasonable to do if that fails. 15162306a36Sopenharmony_ci */ 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci while ((pid = waitpid(-1, NULL, WNOHANG | __WALL)) > 0) 15462306a36Sopenharmony_ci os_kill_ptraced_process(pid, 0); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci uml_abort(); 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_civoid um_early_printk(const char *s, unsigned int n) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci printf("%.*s", n, s); 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic int quiet_info; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic int __init quiet_cmd_param(char *str, int *add) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci quiet_info = 1; 16962306a36Sopenharmony_ci return 0; 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci__uml_setup("quiet", quiet_cmd_param, 17362306a36Sopenharmony_ci"quiet\n" 17462306a36Sopenharmony_ci" Turns off information messages during boot.\n\n"); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci/* 17762306a36Sopenharmony_ci * The os_info/os_warn functions will be called by helper threads. These 17862306a36Sopenharmony_ci * have a very limited stack size and using the libc formatting functions 17962306a36Sopenharmony_ci * may overflow the stack. 18062306a36Sopenharmony_ci * So pull in the kernel vscnprintf and use that instead with a fixed 18162306a36Sopenharmony_ci * on-stack buffer. 18262306a36Sopenharmony_ci */ 18362306a36Sopenharmony_ciint vscnprintf(char *buf, size_t size, const char *fmt, va_list args); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_civoid os_info(const char *fmt, ...) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci char buf[256]; 18862306a36Sopenharmony_ci va_list list; 18962306a36Sopenharmony_ci int len; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci if (quiet_info) 19262306a36Sopenharmony_ci return; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci va_start(list, fmt); 19562306a36Sopenharmony_ci len = vscnprintf(buf, sizeof(buf), fmt, list); 19662306a36Sopenharmony_ci fwrite(buf, len, 1, stderr); 19762306a36Sopenharmony_ci va_end(list); 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_civoid os_warn(const char *fmt, ...) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci char buf[256]; 20362306a36Sopenharmony_ci va_list list; 20462306a36Sopenharmony_ci int len; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci va_start(list, fmt); 20762306a36Sopenharmony_ci len = vscnprintf(buf, sizeof(buf), fmt, list); 20862306a36Sopenharmony_ci fwrite(buf, len, 1, stderr); 20962306a36Sopenharmony_ci va_end(list); 21062306a36Sopenharmony_ci} 211