aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2018-04-16 17:12:31 -0400
committerEric W. Biederman <ebiederm@xmission.com>2018-04-28 09:46:49 -0400
commit530621b79f9e884db5ae4fa44cab020da76b0d0c (patch)
tree6ed7d909fdef132c2d71dda8b541b8c641b7f326 /arch/um
parent31931c93dfe05a76385a443ed28244a50e915a46 (diff)
signal/um: More carefully relay signals in relay_signal.
There is a bug in relay signal. It assumes that when a signal is relayed the signal never uses a signal independent si_code, such as SI_USER, SI_KERNEL, SI_QUEUE, ... SI_SIGIO etc. In practice siginfo was assuming it was relaying a signal with the SIL_FAULT layout. As that is the common cases for the signals it supported that is a reasonable assumption. Further user mode linux must be very careful when relaying different kinds of signals to prevent an information leak. This means simply increasing the kinds of signals that are handled in relay_signal is non-trivial. Therefore use siginfo_layout and force_sig_fault to simplify the signal relaying in relay_signal. By taking advantage of the fact that user mode linux only works on x86 and x86_64 we can assume that si_trapno can be ignored, and that si_errno is always zero. For the signals SIGLL, SIGFPE, SIGSEGV, SIGBUS, and SIGTRAP the only fault handler I know of that sets si_errno is SIGTRAP TRAP_HWBKPT on a few oddball architectures. Those architectures have been modified to use force_sig_ptrace_errno_trap. Similarly only a few architectures set __ARCH_SI_TRAPNO. At the point uml supports those architectures again these additional cases can be examined and supported if desired in relay_signal. Cc: Jeff Dike <jdike@addtoit.com> Cc: Richard Weinberger <richard@nod.at> Cc: Anton Ivanov <anton.ivanov@kot-begemot.co.uk> Cc: Martin Pärtel <martin.partel@gmail.com> Cc: user-mode-linux-devel@lists.sourceforge.net Cc: linux-um@lists.infradead.org Fixes: d3c1cfcdb43e ("um: pass siginfo to guest process") Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Diffstat (limited to 'arch/um')
-rw-r--r--arch/um/kernel/trap.c38
1 files changed, 14 insertions, 24 deletions
diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c
index d18be983814a..ec9a42c14c56 100644
--- a/arch/um/kernel/trap.c
+++ b/arch/um/kernel/trap.c
@@ -286,9 +286,7 @@ out:
286 286
287void relay_signal(int sig, struct siginfo *si, struct uml_pt_regs *regs) 287void relay_signal(int sig, struct siginfo *si, struct uml_pt_regs *regs)
288{ 288{
289 struct faultinfo *fi; 289 int code, err;
290 struct siginfo clean_si;
291
292 if (!UPT_IS_USER(regs)) { 290 if (!UPT_IS_USER(regs)) {
293 if (sig == SIGBUS) 291 if (sig == SIGBUS)
294 printk(KERN_ERR "Bus error - the host /dev/shm or /tmp " 292 printk(KERN_ERR "Bus error - the host /dev/shm or /tmp "
@@ -298,29 +296,21 @@ void relay_signal(int sig, struct siginfo *si, struct uml_pt_regs *regs)
298 296
299 arch_examine_signal(sig, regs); 297 arch_examine_signal(sig, regs);
300 298
301 clear_siginfo(&clean_si); 299 /* Is the signal layout for the signal known?
302 clean_si.si_signo = si->si_signo; 300 * Signal data must be scrubbed to prevent information leaks.
303 clean_si.si_errno = si->si_errno; 301 */
304 clean_si.si_code = si->si_code; 302 code = si->si_code;
305 switch (sig) { 303 err = si->si_errno;
306 case SIGILL: 304 if ((err == 0) && (siginfo_layout(sig, code) == SIL_FAULT)) {
307 case SIGFPE: 305 struct faultinfo *fi = UPT_FAULTINFO(regs);
308 case SIGSEGV:
309 case SIGBUS:
310 case SIGTRAP:
311 fi = UPT_FAULTINFO(regs);
312 clean_si.si_addr = (void __user *) FAULT_ADDRESS(*fi);
313 current->thread.arch.faultinfo = *fi; 306 current->thread.arch.faultinfo = *fi;
314#ifdef __ARCH_SI_TRAPNO 307 force_sig_fault(sig, code, (void __user *)FAULT_ADDRESS(*fi),
315 clean_si.si_trapno = si->si_trapno; 308 current);
316#endif 309 } else {
317 break; 310 printk(KERN_ERR "Attempted to relay unknown signal %d (si_code = %d) with errno %d\n",
318 default: 311 sig, code, err);
319 printk(KERN_ERR "Attempted to relay unknown signal %d (si_code = %d)\n", 312 force_sig(sig, current);
320 sig, si->si_code);
321 } 313 }
322
323 force_sig_info(sig, &clean_si, current);
324} 314}
325 315
326void bus_handler(int sig, struct siginfo *si, struct uml_pt_regs *regs) 316void bus_handler(int sig, struct siginfo *si, struct uml_pt_regs *regs)