um: pass siginfo to guest process
UML guest processes now get correct siginfo_t for SIGTRAP, SIGFPE, SIGILL and SIGBUS. Specifically, si_addr and si_code are now correct where previously they were si_addr = NULL and si_code = 128. Signed-off-by: Martin Pärtel <martin.partel@gmail.com> Signed-off-by: Richard Weinberger <richard@nod.at>
This commit is contained in:
		
							parent
							
								
									d4afcba95f
								
							
						
					
					
						commit
						d3c1cfcdb4
					
				| @ -60,7 +60,8 @@ extern unsigned long host_task_size; | ||||
| 
 | ||||
| extern int linux_main(int argc, char **argv); | ||||
| 
 | ||||
| extern void (*sig_info[])(int, struct uml_pt_regs *); | ||||
| struct siginfo; | ||||
| extern void (*sig_info[])(int, struct siginfo *si, struct uml_pt_regs *); | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
|  | ||||
| @ -20,7 +20,8 @@ struct irq_fd { | ||||
| 
 | ||||
| enum { IRQ_READ, IRQ_WRITE }; | ||||
| 
 | ||||
| extern void sigio_handler(int sig, struct uml_pt_regs *regs); | ||||
| struct siginfo; | ||||
| extern void sigio_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs); | ||||
| extern void free_irq_by_fd(int fd); | ||||
| extern void reactivate_fd(int fd, int irqnum); | ||||
| extern void deactivate_fd(int fd, int irqnum); | ||||
|  | ||||
| @ -9,6 +9,8 @@ | ||||
| #include "sysdep/ptrace.h" | ||||
| #include "sysdep/faultinfo.h" | ||||
| 
 | ||||
| struct siginfo; | ||||
| 
 | ||||
| extern int uml_exitcode; | ||||
| 
 | ||||
| extern int ncpus; | ||||
| @ -22,7 +24,7 @@ extern void free_stack(unsigned long stack, int order); | ||||
| 
 | ||||
| extern int do_signal(void); | ||||
| extern void interrupt_end(void); | ||||
| extern void relay_signal(int sig, struct uml_pt_regs *regs); | ||||
| extern void relay_signal(int sig, struct siginfo *si, struct uml_pt_regs *regs); | ||||
| 
 | ||||
| extern unsigned long segv(struct faultinfo fi, unsigned long ip, | ||||
| 			  int is_user, struct uml_pt_regs *regs); | ||||
| @ -33,9 +35,8 @@ extern unsigned int do_IRQ(int irq, struct uml_pt_regs *regs); | ||||
| extern int smp_sigio_handler(void); | ||||
| extern void initial_thread_cb(void (*proc)(void *), void *arg); | ||||
| extern int is_syscall(unsigned long addr); | ||||
| extern void timer_handler(int sig, struct uml_pt_regs *regs); | ||||
| 
 | ||||
| extern void timer_handler(int sig, struct uml_pt_regs *regs); | ||||
| extern void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs); | ||||
| 
 | ||||
| extern int start_uml(void); | ||||
| extern void paging_init(void); | ||||
| @ -59,9 +60,9 @@ extern unsigned long from_irq_stack(int nested); | ||||
| extern void syscall_trace(struct uml_pt_regs *regs, int entryexit); | ||||
| 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 segv_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs); | ||||
| extern void bus_handler(int sig, struct siginfo *si, struct uml_pt_regs *regs); | ||||
| extern void winch(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs); | ||||
| extern void fatal_sigsegv(void) __attribute__ ((noreturn)); | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -30,7 +30,7 @@ static struct irq_fd **last_irq_ptr = &active_fds; | ||||
| 
 | ||||
| extern void free_irqs(void); | ||||
| 
 | ||||
| void sigio_handler(int sig, struct uml_pt_regs *regs) | ||||
| void sigio_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) | ||||
| { | ||||
| 	struct irq_fd *irq_fd; | ||||
| 	int n; | ||||
|  | ||||
| @ -13,7 +13,7 @@ | ||||
| #include "kern_util.h" | ||||
| #include "os.h" | ||||
| 
 | ||||
| void timer_handler(int sig, struct uml_pt_regs *regs) | ||||
| void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) | ||||
| { | ||||
| 	unsigned long flags; | ||||
| 
 | ||||
|  | ||||
| @ -172,7 +172,7 @@ void fatal_sigsegv(void) | ||||
| 	os_dump_core(); | ||||
| } | ||||
| 
 | ||||
| void segv_handler(int sig, struct uml_pt_regs *regs) | ||||
| void segv_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) | ||||
| { | ||||
| 	struct faultinfo * fi = UPT_FAULTINFO(regs); | ||||
| 
 | ||||
| @ -258,8 +258,11 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| void relay_signal(int sig, struct uml_pt_regs *regs) | ||||
| void relay_signal(int sig, struct siginfo *si, struct uml_pt_regs *regs) | ||||
| { | ||||
| 	struct faultinfo *fi; | ||||
| 	struct siginfo clean_si; | ||||
| 
 | ||||
| 	if (!UPT_IS_USER(regs)) { | ||||
| 		if (sig == SIGBUS) | ||||
| 			printk(KERN_ERR "Bus error - the host /dev/shm or /tmp " | ||||
| @ -269,18 +272,40 @@ void relay_signal(int sig, struct uml_pt_regs *regs) | ||||
| 
 | ||||
| 	arch_examine_signal(sig, regs); | ||||
| 
 | ||||
| 	current->thread.arch.faultinfo = *UPT_FAULTINFO(regs); | ||||
| 	force_sig(sig, current); | ||||
| 	memset(&clean_si, 0, sizeof(clean_si)); | ||||
| 	clean_si.si_signo = si->si_signo; | ||||
| 	clean_si.si_errno = si->si_errno; | ||||
| 	clean_si.si_code = si->si_code; | ||||
| 	switch (sig) { | ||||
| 	case SIGILL: | ||||
| 	case SIGFPE: | ||||
| 	case SIGSEGV: | ||||
| 	case SIGBUS: | ||||
| 	case SIGTRAP: | ||||
| 		fi = UPT_FAULTINFO(regs); | ||||
| 		clean_si.si_addr = (void __user *) FAULT_ADDRESS(*fi); | ||||
| 		current->thread.arch.faultinfo = *fi; | ||||
| #ifdef __ARCH_SI_TRAPNO | ||||
| 		clean_si.si_trapno = si->si_trapno; | ||||
| #endif | ||||
| 		break; | ||||
| 	default: | ||||
| 		printk(KERN_ERR "Attempted to relay unknown signal %d (si_code = %d)\n", | ||||
| 			sig, si->si_code); | ||||
| 	} | ||||
| 
 | ||||
| 	force_sig_info(sig, &clean_si, current); | ||||
| } | ||||
| 
 | ||||
| void bus_handler(int sig, struct uml_pt_regs *regs) | ||||
| void bus_handler(int sig, struct siginfo *si, struct uml_pt_regs *regs) | ||||
| { | ||||
| 	if (current->thread.fault_catcher != NULL) | ||||
| 		UML_LONGJMP(current->thread.fault_catcher, 1); | ||||
| 	else relay_signal(sig, regs); | ||||
| 	else | ||||
| 		relay_signal(sig, si, regs); | ||||
| } | ||||
| 
 | ||||
| void winch(int sig, struct uml_pt_regs *regs) | ||||
| void winch(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) | ||||
| { | ||||
| 	do_IRQ(WINCH_IRQ, regs); | ||||
| } | ||||
|  | ||||
| @ -1 +1 @@ | ||||
| void alarm_handler(int, mcontext_t *); | ||||
| void alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc); | ||||
|  | ||||
| @ -13,8 +13,9 @@ | ||||
| #include "kern_util.h" | ||||
| #include "os.h" | ||||
| #include "sysdep/mcontext.h" | ||||
| #include "internal.h" | ||||
| 
 | ||||
| void (*sig_info[NSIG])(int, struct uml_pt_regs *) = { | ||||
| void (*sig_info[NSIG])(int, siginfo_t *, struct uml_pt_regs *) = { | ||||
| 	[SIGTRAP]	= relay_signal, | ||||
| 	[SIGFPE]	= relay_signal, | ||||
| 	[SIGILL]	= relay_signal, | ||||
| @ -24,7 +25,7 @@ void (*sig_info[NSIG])(int, struct uml_pt_regs *) = { | ||||
| 	[SIGIO]		= sigio_handler, | ||||
| 	[SIGVTALRM]	= timer_handler }; | ||||
| 
 | ||||
| static void sig_handler_common(int sig, mcontext_t *mc) | ||||
| static void sig_handler_common(int sig, siginfo_t *si, mcontext_t *mc) | ||||
| { | ||||
| 	struct uml_pt_regs r; | ||||
| 	int save_errno = errno; | ||||
| @ -40,7 +41,7 @@ static void sig_handler_common(int sig, mcontext_t *mc) | ||||
| 	if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGVTALRM)) | ||||
| 		unblock_signals(); | ||||
| 
 | ||||
| 	(*sig_info[sig])(sig, &r); | ||||
| 	(*sig_info[sig])(sig, si, &r); | ||||
| 
 | ||||
| 	errno = save_errno; | ||||
| } | ||||
| @ -60,7 +61,7 @@ static void sig_handler_common(int sig, mcontext_t *mc) | ||||
| static int signals_enabled; | ||||
| static unsigned int signals_pending; | ||||
| 
 | ||||
| void sig_handler(int sig, mcontext_t *mc) | ||||
| void sig_handler(int sig, siginfo_t *si, mcontext_t *mc) | ||||
| { | ||||
| 	int enabled; | ||||
| 
 | ||||
| @ -72,7 +73,7 @@ void sig_handler(int sig, mcontext_t *mc) | ||||
| 
 | ||||
| 	block_signals(); | ||||
| 
 | ||||
| 	sig_handler_common(sig, mc); | ||||
| 	sig_handler_common(sig, si, mc); | ||||
| 
 | ||||
| 	set_signals(enabled); | ||||
| } | ||||
| @ -85,10 +86,10 @@ static void real_alarm_handler(mcontext_t *mc) | ||||
| 		get_regs_from_mc(®s, mc); | ||||
| 	regs.is_user = 0; | ||||
| 	unblock_signals(); | ||||
| 	timer_handler(SIGVTALRM, ®s); | ||||
| 	timer_handler(SIGVTALRM, NULL, ®s); | ||||
| } | ||||
| 
 | ||||
| void alarm_handler(int sig, mcontext_t *mc) | ||||
| void alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc) | ||||
| { | ||||
| 	int enabled; | ||||
| 
 | ||||
| @ -119,7 +120,7 @@ void set_sigstack(void *sig_stack, int size) | ||||
| 		panic("enabling signal stack failed, errno = %d\n", errno); | ||||
| } | ||||
| 
 | ||||
| static void (*handlers[_NSIG])(int sig, mcontext_t *mc) = { | ||||
| static void (*handlers[_NSIG])(int sig, siginfo_t *si, mcontext_t *mc) = { | ||||
| 	[SIGSEGV] = sig_handler, | ||||
| 	[SIGBUS] = sig_handler, | ||||
| 	[SIGILL] = sig_handler, | ||||
| @ -132,7 +133,7 @@ static void (*handlers[_NSIG])(int sig, mcontext_t *mc) = { | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| static void hard_handler(int sig, siginfo_t *info, void *p) | ||||
| static void hard_handler(int sig, siginfo_t *si, void *p) | ||||
| { | ||||
| 	struct ucontext *uc = p; | ||||
| 	mcontext_t *mc = &uc->uc_mcontext; | ||||
| @ -161,7 +162,7 @@ static void hard_handler(int sig, siginfo_t *info, void *p) | ||||
| 		while ((sig = ffs(pending)) != 0){ | ||||
| 			sig--; | ||||
| 			pending &= ~(1 << sig); | ||||
| 			(*handlers[sig])(sig, mc); | ||||
| 			(*handlers[sig])(sig, si, mc); | ||||
| 		} | ||||
| 
 | ||||
| 		/*
 | ||||
| @ -273,9 +274,12 @@ void unblock_signals(void) | ||||
| 		 * Deal with SIGIO first because the alarm handler might | ||||
| 		 * schedule, leaving the pending SIGIO stranded until we come | ||||
| 		 * back here. | ||||
| 		 * | ||||
| 		 * SIGIO's handler doesn't use siginfo or mcontext, | ||||
| 		 * so they can be NULL. | ||||
| 		 */ | ||||
| 		if (save_pending & SIGIO_MASK) | ||||
| 			sig_handler_common(SIGIO, NULL); | ||||
| 			sig_handler_common(SIGIO, NULL, NULL); | ||||
| 
 | ||||
| 		if (save_pending & SIGVTALRM_MASK) | ||||
| 			real_alarm_handler(NULL); | ||||
|  | ||||
| @ -346,6 +346,7 @@ void userspace(struct uml_pt_regs *regs) | ||||
| 	int err, status, op, pid = userspace_pid[0]; | ||||
| 	/* To prevent races if using_sysemu changes under us.*/ | ||||
| 	int local_using_sysemu; | ||||
| 	siginfo_t si; | ||||
| 
 | ||||
| 	/* Handle any immediate reschedules or signals */ | ||||
| 	interrupt_end(); | ||||
| @ -407,13 +408,17 @@ void userspace(struct uml_pt_regs *regs) | ||||
| 
 | ||||
| 		if (WIFSTOPPED(status)) { | ||||
| 			int sig = WSTOPSIG(status); | ||||
| 
 | ||||
| 			ptrace(PTRACE_GETSIGINFO, pid, 0, &si); | ||||
| 
 | ||||
| 			switch (sig) { | ||||
| 			case SIGSEGV: | ||||
| 				if (PTRACE_FULL_FAULTINFO || | ||||
| 				    !ptrace_faultinfo) { | ||||
| 					get_skas_faultinfo(pid, | ||||
| 							   ®s->faultinfo); | ||||
| 					(*sig_info[SIGSEGV])(SIGSEGV, regs); | ||||
| 					(*sig_info[SIGSEGV])(SIGSEGV, &si, | ||||
| 							     regs); | ||||
| 				} | ||||
| 				else handle_segv(pid, regs); | ||||
| 				break; | ||||
| @ -421,14 +426,14 @@ void userspace(struct uml_pt_regs *regs) | ||||
| 			        handle_trap(pid, regs, local_using_sysemu); | ||||
| 				break; | ||||
| 			case SIGTRAP: | ||||
| 				relay_signal(SIGTRAP, regs); | ||||
| 				relay_signal(SIGTRAP, &si, regs); | ||||
| 				break; | ||||
| 			case SIGVTALRM: | ||||
| 				now = os_nsecs(); | ||||
| 				if (now < nsecs) | ||||
| 					break; | ||||
| 				block_signals(); | ||||
| 				(*sig_info[sig])(sig, regs); | ||||
| 				(*sig_info[sig])(sig, &si, regs); | ||||
| 				unblock_signals(); | ||||
| 				nsecs = timer.it_value.tv_sec * | ||||
| 					UM_NSEC_PER_SEC + | ||||
| @ -442,7 +447,7 @@ void userspace(struct uml_pt_regs *regs) | ||||
| 			case SIGFPE: | ||||
| 			case SIGWINCH: | ||||
| 				block_signals(); | ||||
| 				(*sig_info[sig])(sig, regs); | ||||
| 				(*sig_info[sig])(sig, &si, regs); | ||||
| 				unblock_signals(); | ||||
| 				break; | ||||
| 			default: | ||||
|  | ||||
| @ -87,7 +87,7 @@ static int after_sleep_interval(struct timespec *ts) | ||||
| 
 | ||||
| static void deliver_alarm(void) | ||||
| { | ||||
| 	alarm_handler(SIGVTALRM, NULL); | ||||
| 	alarm_handler(SIGVTALRM, NULL, NULL); | ||||
| } | ||||
| 
 | ||||
| static unsigned long long sleep_time(unsigned long long nsecs) | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user