Contributors: 7
Author Tokens Token Proportion Commits Commit Proportion
Benjamin Berg 381 95.25% 2 20.00%
Jeff Dike 7 1.75% 3 30.00%
David Gow 4 1.00% 1 10.00%
Johannes Berg 3 0.75% 1 10.00%
Gennady Sharapov 2 0.50% 1 10.00%
Richard Weinberger 2 0.50% 1 10.00%
Al Viro 1 0.25% 1 10.00%
Total 400 10

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
#include <sys/ptrace.h>
#include <sys/prctl.h>
#include <asm/unistd.h>
#include <sysdep/stub.h>
#include <stub-data.h>

void _start(void);

noinline static void real_init(void)
{
	struct stub_init_data init_data;
	unsigned long res;
	struct {
		void  *ss_sp;
		int    ss_flags;
		size_t ss_size;
	} stack = {
		.ss_size = STUB_DATA_PAGES * UM_KERN_PAGE_SIZE,
	};
	struct {
		void *sa_handler_;
		unsigned long sa_flags;
		void *sa_restorer;
		unsigned long long sa_mask;
	} sa = {
		/* Need to set SA_RESTORER (but the handler never returns) */
		.sa_flags = SA_ONSTACK | SA_NODEFER | SA_SIGINFO | 0x04000000,
		/* no need to mask any signals */
		.sa_mask = 0,
	};

	/* set a nice name */
	stub_syscall2(__NR_prctl, PR_SET_NAME, (unsigned long)"uml-userspace");

	/* Make sure this process dies if the kernel dies */
	stub_syscall2(__NR_prctl, PR_SET_PDEATHSIG, SIGKILL);

	/* read information from STDIN and close it */
	res = stub_syscall3(__NR_read, 0,
			    (unsigned long)&init_data, sizeof(init_data));
	if (res != sizeof(init_data))
		stub_syscall1(__NR_exit, 10);

	stub_syscall1(__NR_close, 0);

	/* map stub code + data */
	res = stub_syscall6(STUB_MMAP_NR,
			    init_data.stub_start, UM_KERN_PAGE_SIZE,
			    PROT_READ | PROT_EXEC, MAP_FIXED | MAP_SHARED,
			    init_data.stub_code_fd, init_data.stub_code_offset);
	if (res != init_data.stub_start)
		stub_syscall1(__NR_exit, 11);

	res = stub_syscall6(STUB_MMAP_NR,
			    init_data.stub_start + UM_KERN_PAGE_SIZE,
			    STUB_DATA_PAGES * UM_KERN_PAGE_SIZE,
			    PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED,
			    init_data.stub_data_fd, init_data.stub_data_offset);
	if (res != init_data.stub_start + UM_KERN_PAGE_SIZE)
		stub_syscall1(__NR_exit, 12);

	/* setup signal stack inside stub data */
	stack.ss_sp = (void *)init_data.stub_start + UM_KERN_PAGE_SIZE;
	stub_syscall2(__NR_sigaltstack, (unsigned long)&stack, 0);

	/* register SIGSEGV handler */
	sa.sa_handler_ = (void *) init_data.segv_handler;
	res = stub_syscall4(__NR_rt_sigaction, SIGSEGV, (unsigned long)&sa, 0,
			    sizeof(sa.sa_mask));
	if (res != 0)
		stub_syscall1(__NR_exit, 13);

	stub_syscall4(__NR_ptrace, PTRACE_TRACEME, 0, 0, 0);

	stub_syscall2(__NR_kill, stub_syscall0(__NR_getpid), SIGSTOP);

	stub_syscall1(__NR_exit, 14);

	__builtin_unreachable();
}

__attribute__((naked)) void _start(void)
{
	/*
	 * Since the stack after exec() starts at the top-most address,
	 * but that's exactly where we also want to map the stub data
	 * and code, this must:
	 *  - push the stack by 1 code and STUB_DATA_PAGES data pages
	 *  - call real_init()
	 * This way, real_init() can use the stack normally, while the
	 * original stack further down (higher address) will become
	 * inaccessible after the mmap() calls above.
	 */
	stub_start(real_init);
}