Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3e6f2ac4 authored by Jeff Dike's avatar Jeff Dike Committed by Linus Torvalds
Browse files

uml: kill processes instead of panicing kernel



UML was panicing in the case of failures of libc calls which shouldn't happen.
 This is an overreaction since a failure from libc doesn't normally mean that
kernel data structures are in an unknown state.  Instead, the current process
should just be killed if there is no way to recover.

The case that prompted this was a failure of PTRACE_SETREGS restoring the same
state that was read by PTRACE_GETREGS.  It appears that when a process tries
to load a bogus value into a segment register, it segfaults (as expected) and
the value is actually loaded and is seen by PTRACE_GETREGS (not expected).

This case is fixed by forcing a fatal SIGSEGV on the process so that it
immediately dies.  fatal_sigsegv was added for this purpose.  It was declared
as noreturn, so in order to pursuade gcc that it actually does not return, I
added a call to os_dump_core (and declared it noreturn) so that I get a core
file if somehow the process survives.

All other calls in arch/um/os-Linux/skas/process.c got the same treatment,
with failures causing the process to die instead of a kernel panic, with some
exceptions.

userspace_tramp exits with status 1 if anything goes wrong there.  That will
cause start_userspace to return an error.  copy_context_skas0 and
map_stub_pages also now return errors instead of panicing.  Callers of thes
functions were changed to check for errors and do something appropriate.
Usually that's to return an error to their callers.
check_skas3_ptrace_faultinfo just exits since that's too early to do anything
else.

save_registers, restore_registers, and init_registers now return status
instead of panicing on failure, with their callers doing something
appropriate.

There were also duplicate declarations of save_registers and restore_registers
in os.h - these are gone.

I noticed and fixed up some whitespace damage.

Signed-off-by: default avatarJeff Dike <jdike@linux.intel.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent d25f2e12
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ extern int singlestepping(void *t);
extern void segv_handler(int sig, struct uml_pt_regs *regs);
extern void bus_handler(int sig, struct uml_pt_regs *regs);
extern void winch(int sig, struct uml_pt_regs *regs);
extern void fatal_sigsegv(void) __attribute__ ((noreturn));


#endif
+3 −5
Original line number Diff line number Diff line
@@ -238,7 +238,7 @@ extern int raw(int fd);
extern void setup_machinename(char *machine_out);
extern void setup_hostinfo(char *buf, int len);
extern int setjmp_wrapper(void (*proc)(void *, void *), ...);
extern void os_dump_core(void);
extern void os_dump_core(void) __attribute__ ((noreturn));

/* time.c */
extern void idle_sleep(unsigned long long nsecs);
@@ -267,11 +267,9 @@ extern int protect(struct mm_id * mm_idp, unsigned long addr,
extern int is_skas_winch(int pid, int fd, void *data);
extern int start_userspace(unsigned long stub_stack);
extern int copy_context_skas0(unsigned long stack, int pid);
extern void save_registers(int pid, struct uml_pt_regs *regs);
extern void restore_registers(int pid, struct uml_pt_regs *regs);
extern void userspace(struct uml_pt_regs *regs);
extern void map_stub_pages(int fd, unsigned long code,
			   unsigned long data, unsigned long stack);
extern int map_stub_pages(int fd, unsigned long code, unsigned long data,
			  unsigned long stack);
extern void new_thread(void *stack, jmp_buf *buf, void (*handler)(void));
extern void switch_threads(jmp_buf *me, jmp_buf *you);
extern int start_idle_thread(void *stack, jmp_buf *switch_buf);
+3 −3
Original line number Diff line number Diff line
@@ -13,9 +13,9 @@ extern int save_fp_registers(int pid, unsigned long *fp_regs);
extern int restore_fp_registers(int pid, unsigned long *fp_regs);
extern int save_fpx_registers(int pid, unsigned long *fp_regs);
extern int restore_fpx_registers(int pid, unsigned long *fp_regs);
extern void save_registers(int pid, struct uml_pt_regs *regs);
extern void restore_registers(int pid, struct uml_pt_regs *regs);
extern void init_registers(int pid);
extern int save_registers(int pid, struct uml_pt_regs *regs);
extern int restore_registers(int pid, struct uml_pt_regs *regs);
extern int init_registers(int pid);
extern void get_safe_registers(unsigned long *regs);
extern unsigned long get_thread_reg(int reg, jmp_buf *buf);

+5 −0
Original line number Diff line number Diff line
@@ -114,6 +114,11 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm)
			to_mm->id.u.pid = copy_context_skas0(stack,
							     from_mm->id.u.pid);
		else to_mm->id.u.pid = start_userspace(stack);

		if (to_mm->id.u.pid < 0) {
			ret = to_mm->id.u.pid;
			goto out_free;
		}
	}

	ret = init_new_ldt(to_mm, from_mm);
+16 −4
Original line number Diff line number Diff line
@@ -6,19 +6,25 @@
#include "linux/init.h"
#include "linux/sched.h"
#include "as-layout.h"
#include "kern.h"
#include "os.h"
#include "skas.h"

int new_mm(unsigned long stack)
{
	int fd;
	int fd, err;

	fd = os_open_file("/proc/mm", of_cloexec(of_write(OPENFLAGS())), 0);
	if (fd < 0)
		return fd;

	if (skas_needs_stub)
		map_stub_pages(fd, STUB_CODE, STUB_DATA, stack);
	if (skas_needs_stub) {
		err = map_stub_pages(fd, STUB_CODE, STUB_DATA, stack);
		if (err) {
			os_close_file(fd);
			return err;
		}
	}

	return fd;
}
@@ -49,8 +55,14 @@ int __init start_uml(void)
{
	stack_protections((unsigned long) &cpu0_irqstack);
	set_sigstack(cpu0_irqstack, THREAD_SIZE);
	if (proc_mm)
	if (proc_mm) {
		userspace_pid[0] = start_userspace(0);
		if (userspace_pid[0] < 0) {
			printf("start_uml - start_userspace returned %d\n",
			       userspace_pid[0]);
			exit(1);
		}
	}

	init_new_thread_signals();

Loading