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