// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2021 Benjamin Berg <benjamin@sipsolutions.net>
* Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
* Copyright (C) 2002- 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
*/
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <sched.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <mem_user.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <asm/unistd.h>
#include <as-layout.h>
#include <init.h>
#include <kern_util.h>
#include <mem.h>
#include <os.h>
#include <ptrace_user.h>
#include <registers.h>
#include <skas.h>
#include <sysdep/stub.h>
#include <sysdep/mcontext.h>
#include <linux/futex.h>
#include <linux/threads.h>
#include <timetravel.h>
#include <asm-generic/rwonce.h>
#include "../internal.h"
int is_skas_winch(int pid, int fd, void *data)
{
return pid == getpgrp();
}
static const char *ptrace_reg_name(int idx)
{
#define R(n) case HOST_##n: return #n
switch (idx) {
#ifdef __x86_64__
R(BX);
R(CX);
R(DI);
R(SI);
R(DX);
R(BP);
R(AX);
R(R8);
R(R9);
R(R10);
R(R11);
R(R12);
R(R13);
R(R14);
R(R15);
R(ORIG_AX);
R(CS);
R(SS);
R(EFLAGS);
#elif defined(__i386__)
R(IP);
R(SP);
R(EFLAGS);
R(AX);
R(BX);
R(CX);
R(DX);
R(SI);
R(DI);
R(BP);
R(CS);
R(SS);
R(DS);
R(FS);
R(ES);
R(GS);
R(ORIG_AX);
#endif
}
return "";
}
static int ptrace_dump_regs(int pid)
{
unsigned long regs[MAX_REG_NR];
int i;
if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0)
return -errno;
printk(UM_KERN_ERR "Stub registers -\n");
for (i = 0; i < ARRAY_SIZE(regs); i++) {
const char *regname = ptrace_reg_name(i);
printk(UM_KERN_ERR "\t%s\t(%2d): %lx\n", regname, i, regs[i]);
}
return 0;
}
/*
* Signals that are OK to receive in the stub - we'll just continue it.
* SIGWINCH will happen when UML is inside a detached screen.
*/
#define STUB_SIG_MASK ((1 << SIGALRM) | (1 << SIGWINCH))
/* Signals that the stub will finish with - anything else is an error */
#define STUB_DONE_MASK (1 << SIGTRAP)
void wait_stub_done(int pid)
{
int n, status, err;
while (1) {
CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED | __WALL));
if ((n < 0) || !WIFSTOPPED(status))
goto bad_wait;
if (((1 << WSTOPSIG(status)) & STUB_SIG_MASK) == 0)
break;
err = ptrace(PTRACE_CONT, pid, 0, 0);
if (err) {
printk(UM_KERN_ERR "%s : continue failed, errno = %d\n",
__func__, errno);
fatal_sigsegv();
}
}
if (((1 << WSTOPSIG(status)) & STUB_DONE_MASK) != 0)
return;
bad_wait:
err = ptrace_dump_regs(pid);
if (err)
printk(UM_KERN_ERR "Failed to get registers from stub, errno = %d\n",
-err);
printk(UM_KERN_ERR "%s : failed to wait for SIGTRAP, pid = %d, n = %d, errno = %d, status = 0x%x\n",
__func__, pid, n, errno, status);
fatal_sigsegv();
}
void wait_stub_done_seccomp(struct mm_id *mm_idp, int running, int wait_sigsys)
{
struct stub_data *data = (void *)mm_idp->stack;
int ret;
do {
const char byte = 0;
struct iovec iov = {
.iov_base = (void *)&byte,
.iov_len = sizeof(byte),
};
union {
char data[CMSG_SPACE(sizeof(mm_idp->syscall_fd_map))];
struct cmsghdr align;
} ctrl;
struct msghdr msgh = {
.msg_iov = &iov,
.msg_iovlen = 1,
};
if (!running) {
if (mm_idp->syscall_fd_num) {
unsigned int fds_size =
sizeof(int) * mm_idp->syscall_fd_num;
struct cmsghdr *cmsg;
msgh.msg_control = ctrl.data;
msgh.msg_controllen = CMSG_SPACE(fds_size);
cmsg = CMSG_FIRSTHDR(&am