mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-12 05:48:40 +00:00
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
10 changed files with 71 additions and 34 deletions
|
@ -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 a new issue