Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Martin Pärtel and committed by
Richard Weinberger
d3c1cfcd d4afcba9

+71 -34
+2 -1
arch/um/include/shared/as-layout.h
··· 60 60 61 61 extern int linux_main(int argc, char **argv); 62 62 63 - extern void (*sig_info[])(int, struct uml_pt_regs *); 63 + struct siginfo; 64 + extern void (*sig_info[])(int, struct siginfo *si, struct uml_pt_regs *); 64 65 65 66 #endif 66 67
+2 -1
arch/um/include/shared/irq_user.h
··· 20 20 21 21 enum { IRQ_READ, IRQ_WRITE }; 22 22 23 - extern void sigio_handler(int sig, struct uml_pt_regs *regs); 23 + struct siginfo; 24 + extern void sigio_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs); 24 25 extern void free_irq_by_fd(int fd); 25 26 extern void reactivate_fd(int fd, int irqnum); 26 27 extern void deactivate_fd(int fd, int irqnum);
+7 -6
arch/um/include/shared/kern_util.h
··· 9 9 #include "sysdep/ptrace.h" 10 10 #include "sysdep/faultinfo.h" 11 11 12 + struct siginfo; 13 + 12 14 extern int uml_exitcode; 13 15 14 16 extern int ncpus; ··· 24 22 25 23 extern int do_signal(void); 26 24 extern void interrupt_end(void); 27 - extern void relay_signal(int sig, struct uml_pt_regs *regs); 25 + extern void relay_signal(int sig, struct siginfo *si, struct uml_pt_regs *regs); 28 26 29 27 extern unsigned long segv(struct faultinfo fi, unsigned long ip, 30 28 int is_user, struct uml_pt_regs *regs); ··· 35 33 extern int smp_sigio_handler(void); 36 34 extern void initial_thread_cb(void (*proc)(void *), void *arg); 37 35 extern int is_syscall(unsigned long addr); 38 - extern void timer_handler(int sig, struct uml_pt_regs *regs); 39 36 40 - extern void timer_handler(int sig, struct uml_pt_regs *regs); 37 + extern void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs); 41 38 42 39 extern int start_uml(void); 43 40 extern void paging_init(void); ··· 60 59 extern void syscall_trace(struct uml_pt_regs *regs, int entryexit); 61 60 extern int singlestepping(void *t); 62 61 63 - extern void segv_handler(int sig, struct uml_pt_regs *regs); 64 - extern void bus_handler(int sig, struct uml_pt_regs *regs); 65 - extern void winch(int sig, struct uml_pt_regs *regs); 62 + extern void segv_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs); 63 + extern void bus_handler(int sig, struct siginfo *si, struct uml_pt_regs *regs); 64 + extern void winch(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs); 66 65 extern void fatal_sigsegv(void) __attribute__ ((noreturn)); 67 66 68 67
+1 -1
arch/um/kernel/irq.c
··· 30 30 31 31 extern void free_irqs(void); 32 32 33 - void sigio_handler(int sig, struct uml_pt_regs *regs) 33 + void sigio_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) 34 34 { 35 35 struct irq_fd *irq_fd; 36 36 int n;
+1 -1
arch/um/kernel/time.c
··· 13 13 #include "kern_util.h" 14 14 #include "os.h" 15 15 16 - void timer_handler(int sig, struct uml_pt_regs *regs) 16 + void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) 17 17 { 18 18 unsigned long flags; 19 19
+32 -7
arch/um/kernel/trap.c
··· 172 172 os_dump_core(); 173 173 } 174 174 175 - void segv_handler(int sig, struct uml_pt_regs *regs) 175 + void segv_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) 176 176 { 177 177 struct faultinfo * fi = UPT_FAULTINFO(regs); 178 178 ··· 258 258 return 0; 259 259 } 260 260 261 - void relay_signal(int sig, struct uml_pt_regs *regs) 261 + void relay_signal(int sig, struct siginfo *si, struct uml_pt_regs *regs) 262 262 { 263 + struct faultinfo *fi; 264 + struct siginfo clean_si; 265 + 263 266 if (!UPT_IS_USER(regs)) { 264 267 if (sig == SIGBUS) 265 268 printk(KERN_ERR "Bus error - the host /dev/shm or /tmp " ··· 272 269 273 270 arch_examine_signal(sig, regs); 274 271 275 - current->thread.arch.faultinfo = *UPT_FAULTINFO(regs); 276 - force_sig(sig, current); 272 + memset(&clean_si, 0, sizeof(clean_si)); 273 + clean_si.si_signo = si->si_signo; 274 + clean_si.si_errno = si->si_errno; 275 + clean_si.si_code = si->si_code; 276 + switch (sig) { 277 + case SIGILL: 278 + case SIGFPE: 279 + case SIGSEGV: 280 + case SIGBUS: 281 + case SIGTRAP: 282 + fi = UPT_FAULTINFO(regs); 283 + clean_si.si_addr = (void __user *) FAULT_ADDRESS(*fi); 284 + current->thread.arch.faultinfo = *fi; 285 + #ifdef __ARCH_SI_TRAPNO 286 + clean_si.si_trapno = si->si_trapno; 287 + #endif 288 + break; 289 + default: 290 + printk(KERN_ERR "Attempted to relay unknown signal %d (si_code = %d)\n", 291 + sig, si->si_code); 292 + } 293 + 294 + force_sig_info(sig, &clean_si, current); 277 295 } 278 296 279 - void bus_handler(int sig, struct uml_pt_regs *regs) 297 + void bus_handler(int sig, struct siginfo *si, struct uml_pt_regs *regs) 280 298 { 281 299 if (current->thread.fault_catcher != NULL) 282 300 UML_LONGJMP(current->thread.fault_catcher, 1); 283 - else relay_signal(sig, regs); 301 + else 302 + relay_signal(sig, si, regs); 284 303 } 285 304 286 - void winch(int sig, struct uml_pt_regs *regs) 305 + void winch(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) 287 306 { 288 307 do_IRQ(WINCH_IRQ, regs); 289 308 }
+1 -1
arch/um/os-Linux/internal.h
··· 1 - void alarm_handler(int, mcontext_t *); 1 + void alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc);
+15 -11
arch/um/os-Linux/signal.c
··· 13 13 #include "kern_util.h" 14 14 #include "os.h" 15 15 #include "sysdep/mcontext.h" 16 + #include "internal.h" 16 17 17 - void (*sig_info[NSIG])(int, struct uml_pt_regs *) = { 18 + void (*sig_info[NSIG])(int, siginfo_t *, struct uml_pt_regs *) = { 18 19 [SIGTRAP] = relay_signal, 19 20 [SIGFPE] = relay_signal, 20 21 [SIGILL] = relay_signal, ··· 25 24 [SIGIO] = sigio_handler, 26 25 [SIGVTALRM] = timer_handler }; 27 26 28 - static void sig_handler_common(int sig, mcontext_t *mc) 27 + static void sig_handler_common(int sig, siginfo_t *si, mcontext_t *mc) 29 28 { 30 29 struct uml_pt_regs r; 31 30 int save_errno = errno; ··· 41 40 if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGVTALRM)) 42 41 unblock_signals(); 43 42 44 - (*sig_info[sig])(sig, &r); 43 + (*sig_info[sig])(sig, si, &r); 45 44 46 45 errno = save_errno; 47 46 } ··· 61 60 static int signals_enabled; 62 61 static unsigned int signals_pending; 63 62 64 - void sig_handler(int sig, mcontext_t *mc) 63 + void sig_handler(int sig, siginfo_t *si, mcontext_t *mc) 65 64 { 66 65 int enabled; 67 66 ··· 73 72 74 73 block_signals(); 75 74 76 - sig_handler_common(sig, mc); 75 + sig_handler_common(sig, si, mc); 77 76 78 77 set_signals(enabled); 79 78 } ··· 86 85 get_regs_from_mc(&regs, mc); 87 86 regs.is_user = 0; 88 87 unblock_signals(); 89 - timer_handler(SIGVTALRM, &regs); 88 + timer_handler(SIGVTALRM, NULL, &regs); 90 89 } 91 90 92 - void alarm_handler(int sig, mcontext_t *mc) 91 + void alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc) 93 92 { 94 93 int enabled; 95 94 ··· 120 119 panic("enabling signal stack failed, errno = %d\n", errno); 121 120 } 122 121 123 - static void (*handlers[_NSIG])(int sig, mcontext_t *mc) = { 122 + static void (*handlers[_NSIG])(int sig, siginfo_t *si, mcontext_t *mc) = { 124 123 [SIGSEGV] = sig_handler, 125 124 [SIGBUS] = sig_handler, 126 125 [SIGILL] = sig_handler, ··· 133 132 }; 134 133 135 134 136 - static void hard_handler(int sig, siginfo_t *info, void *p) 135 + static void hard_handler(int sig, siginfo_t *si, void *p) 137 136 { 138 137 struct ucontext *uc = p; 139 138 mcontext_t *mc = &uc->uc_mcontext; ··· 162 161 while ((sig = ffs(pending)) != 0){ 163 162 sig--; 164 163 pending &= ~(1 << sig); 165 - (*handlers[sig])(sig, mc); 164 + (*handlers[sig])(sig, si, mc); 166 165 } 167 166 168 167 /* ··· 274 273 * Deal with SIGIO first because the alarm handler might 275 274 * schedule, leaving the pending SIGIO stranded until we come 276 275 * back here. 276 + * 277 + * SIGIO's handler doesn't use siginfo or mcontext, 278 + * so they can be NULL. 277 279 */ 278 280 if (save_pending & SIGIO_MASK) 279 - sig_handler_common(SIGIO, NULL); 281 + sig_handler_common(SIGIO, NULL, NULL); 280 282 281 283 if (save_pending & SIGVTALRM_MASK) 282 284 real_alarm_handler(NULL);
+9 -4
arch/um/os-Linux/skas/process.c
··· 346 346 int err, status, op, pid = userspace_pid[0]; 347 347 /* To prevent races if using_sysemu changes under us.*/ 348 348 int local_using_sysemu; 349 + siginfo_t si; 349 350 350 351 /* Handle any immediate reschedules or signals */ 351 352 interrupt_end(); ··· 408 407 409 408 if (WIFSTOPPED(status)) { 410 409 int sig = WSTOPSIG(status); 410 + 411 + ptrace(PTRACE_GETSIGINFO, pid, 0, &si); 412 + 411 413 switch (sig) { 412 414 case SIGSEGV: 413 415 if (PTRACE_FULL_FAULTINFO || 414 416 !ptrace_faultinfo) { 415 417 get_skas_faultinfo(pid, 416 418 &regs->faultinfo); 417 - (*sig_info[SIGSEGV])(SIGSEGV, regs); 419 + (*sig_info[SIGSEGV])(SIGSEGV, &si, 420 + regs); 418 421 } 419 422 else handle_segv(pid, regs); 420 423 break; ··· 426 421 handle_trap(pid, regs, local_using_sysemu); 427 422 break; 428 423 case SIGTRAP: 429 - relay_signal(SIGTRAP, regs); 424 + relay_signal(SIGTRAP, &si, regs); 430 425 break; 431 426 case SIGVTALRM: 432 427 now = os_nsecs(); 433 428 if (now < nsecs) 434 429 break; 435 430 block_signals(); 436 - (*sig_info[sig])(sig, regs); 431 + (*sig_info[sig])(sig, &si, regs); 437 432 unblock_signals(); 438 433 nsecs = timer.it_value.tv_sec * 439 434 UM_NSEC_PER_SEC + ··· 447 442 case SIGFPE: 448 443 case SIGWINCH: 449 444 block_signals(); 450 - (*sig_info[sig])(sig, regs); 445 + (*sig_info[sig])(sig, &si, regs); 451 446 unblock_signals(); 452 447 break; 453 448 default:
+1 -1
arch/um/os-Linux/time.c
··· 87 87 88 88 static void deliver_alarm(void) 89 89 { 90 - alarm_handler(SIGVTALRM, NULL); 90 + alarm_handler(SIGVTALRM, NULL, NULL); 91 91 } 92 92 93 93 static unsigned long long sleep_time(unsigned long long nsecs)