You can subscribe to this list here.
1999 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(8) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2000 |
Jan
(19) |
Feb
(11) |
Mar
(56) |
Apr
(31) |
May
(37) |
Jun
(21) |
Jul
(30) |
Aug
(31) |
Sep
(25) |
Oct
(60) |
Nov
(28) |
Dec
(57) |
2001 |
Jan
(47) |
Feb
(119) |
Mar
(279) |
Apr
(198) |
May
(336) |
Jun
(201) |
Jul
(136) |
Aug
(123) |
Sep
(123) |
Oct
(185) |
Nov
(66) |
Dec
(97) |
2002 |
Jan
(318) |
Feb
(101) |
Mar
(167) |
Apr
(233) |
May
(249) |
Jun
(134) |
Jul
(195) |
Aug
(99) |
Sep
(278) |
Oct
(435) |
Nov
(326) |
Dec
(325) |
2003 |
Jan
(214) |
Feb
(309) |
Mar
(142) |
Apr
(141) |
May
(210) |
Jun
(86) |
Jul
(133) |
Aug
(218) |
Sep
(315) |
Oct
(152) |
Nov
(162) |
Dec
(288) |
2004 |
Jan
(277) |
Feb
(267) |
Mar
(182) |
Apr
(168) |
May
(254) |
Jun
(131) |
Jul
(168) |
Aug
(177) |
Sep
(262) |
Oct
(309) |
Nov
(262) |
Dec
(255) |
2005 |
Jan
(258) |
Feb
(169) |
Mar
(282) |
Apr
(208) |
May
(262) |
Jun
(187) |
Jul
(207) |
Aug
(171) |
Sep
(283) |
Oct
(216) |
Nov
(307) |
Dec
(107) |
2006 |
Jan
(207) |
Feb
(82) |
Mar
(192) |
Apr
(165) |
May
(121) |
Jun
(108) |
Jul
(120) |
Aug
(126) |
Sep
(101) |
Oct
(216) |
Nov
(95) |
Dec
(125) |
2007 |
Jan
(176) |
Feb
(117) |
Mar
(240) |
Apr
(120) |
May
(81) |
Jun
(82) |
Jul
(62) |
Aug
(120) |
Sep
(103) |
Oct
(109) |
Nov
(181) |
Dec
(87) |
2008 |
Jan
(145) |
Feb
(69) |
Mar
(31) |
Apr
(98) |
May
(91) |
Jun
(43) |
Jul
(68) |
Aug
(135) |
Sep
(48) |
Oct
(18) |
Nov
(29) |
Dec
(16) |
2009 |
Jan
(26) |
Feb
(15) |
Mar
(83) |
Apr
(39) |
May
(23) |
Jun
(35) |
Jul
(11) |
Aug
(3) |
Sep
(11) |
Oct
(2) |
Nov
(28) |
Dec
(8) |
2010 |
Jan
(4) |
Feb
(40) |
Mar
(4) |
Apr
(46) |
May
(35) |
Jun
(46) |
Jul
(10) |
Aug
(4) |
Sep
(50) |
Oct
(70) |
Nov
(31) |
Dec
(24) |
2011 |
Jan
(17) |
Feb
(8) |
Mar
(35) |
Apr
(50) |
May
(75) |
Jun
(55) |
Jul
(72) |
Aug
(272) |
Sep
(10) |
Oct
(9) |
Nov
(11) |
Dec
(15) |
2012 |
Jan
(36) |
Feb
(49) |
Mar
(54) |
Apr
(47) |
May
(8) |
Jun
(82) |
Jul
(20) |
Aug
(50) |
Sep
(51) |
Oct
(20) |
Nov
(10) |
Dec
(25) |
2013 |
Jan
(34) |
Feb
(4) |
Mar
(24) |
Apr
(40) |
May
(101) |
Jun
(30) |
Jul
(55) |
Aug
(84) |
Sep
(53) |
Oct
(49) |
Nov
(61) |
Dec
(36) |
2014 |
Jan
(26) |
Feb
(22) |
Mar
(30) |
Apr
(4) |
May
(43) |
Jun
(33) |
Jul
(44) |
Aug
(61) |
Sep
(46) |
Oct
(154) |
Nov
(16) |
Dec
(12) |
2015 |
Jan
(18) |
Feb
(2) |
Mar
(122) |
Apr
(23) |
May
(56) |
Jun
(29) |
Jul
(35) |
Aug
(15) |
Sep
|
Oct
(45) |
Nov
(94) |
Dec
(38) |
2016 |
Jan
(50) |
Feb
(39) |
Mar
(39) |
Apr
(1) |
May
(14) |
Jun
(12) |
Jul
(19) |
Aug
(12) |
Sep
(9) |
Oct
(1) |
Nov
(13) |
Dec
(7) |
2017 |
Jan
(6) |
Feb
(1) |
Mar
(16) |
Apr
(5) |
May
(61) |
Jun
(18) |
Jul
(43) |
Aug
(1) |
Sep
(8) |
Oct
(25) |
Nov
(30) |
Dec
(6) |
2018 |
Jan
(5) |
Feb
(2) |
Mar
(25) |
Apr
(15) |
May
(2) |
Jun
(1) |
Jul
|
Aug
|
Sep
|
Oct
(1) |
Nov
|
Dec
|
2019 |
Jan
|
Feb
(2) |
Mar
|
Apr
(1) |
May
|
Jun
(1) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: Richard W. <ric...@gm...> - 2016-03-26 17:58:47
|
On Sun, Jan 10, 2016 at 6:13 AM, Peter Hurley <pe...@hu...> wrote: > Evaluate the conditions which prevent this tty being the controlling > terminal in one place, just before setting the controlling terminal. > > Signed-off-by: Peter Hurley <pe...@hu...> > --- > drivers/tty/tty_io.c | 17 ++++++++--------- > 1 file changed, 8 insertions(+), 9 deletions(-) Peter, This commit breaks existing userspace. I noticed that on UserModeLinux with Debian Squeeze as userspace, getty does not give me a controlling tty upon login. It does not seem to happen on newer distros. But still this needs further investigation. Please me know what debug information you need. -- Thanks, //richard |
From: Eli C. <eli...@gm...> - 2016-03-19 16:59:05
|
This patch extends save_fp_registers() and restore_fp_registers() to use PTRACE_GETREGSET and PTRACE_SETREGSET with the XSTATE note type, adding support for new processor state extensions between context switches. When the new ptrace requests are unavailable, it falls back to the old PTRACE_GETFPREGS and PTRACE_SETFPREGS methods, which have been renamed to save_i387_registers() and restore_i387_registers(). Now these functions expect *fp_regs to have the space of an _xstate struct. Thus, this also makes ptrace in UML responde to PTRACE_GETFPREGS/_SETFPREG requests with a user_i387_struct (thus independent from HOST_FP_SIZE), and by calling save_i387_registers() and restore_i387_registers() instead of the extended save_fp_registers() and restore_fp_registers() functions. Signed-off-by: Eli Cooper <eli...@gm...> --- arch/um/include/shared/registers.h | 2 ++ arch/um/kernel/process.c | 2 +- arch/x86/um/os-Linux/registers.c | 49 +++++++++++++++++++++++++++++++++-- arch/x86/um/ptrace_32.c | 5 ++-- arch/x86/um/ptrace_64.c | 16 ++++++------ arch/x86/um/shared/sysdep/ptrace_64.h | 4 +-- 6 files changed, 62 insertions(+), 16 deletions(-) diff --git a/arch/um/include/shared/registers.h b/arch/um/include/shared/registers.h index f5b7635..a74449b 100644 --- a/arch/um/include/shared/registers.h +++ b/arch/um/include/shared/registers.h @@ -9,6 +9,8 @@ #include <sysdep/ptrace.h> #include <sysdep/archsetjmp.h> +extern int save_i387_registers(int pid, unsigned long *fp_regs); +extern int restore_i387_registers(int pid, unsigned long *fp_regs); 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); diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index 48af59a..d55a473 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -402,6 +402,6 @@ int elf_core_copy_fpregs(struct task_struct *t, elf_fpregset_t *fpu) { int cpu = current_thread_info()->cpu; - return save_fp_registers(userspace_pid[cpu], (unsigned long *) fpu); + return save_i387_registers(userspace_pid[cpu], (unsigned long *) fpu); } diff --git a/arch/x86/um/os-Linux/registers.c b/arch/x86/um/os-Linux/registers.c index 41bfe84..00f54a9 100644 --- a/arch/x86/um/os-Linux/registers.c +++ b/arch/x86/um/os-Linux/registers.c @@ -11,21 +11,56 @@ #endif #include <longjmp.h> #include <sysdep/ptrace_user.h> +#include <sys/uio.h> +#include <asm/sigcontext.h> +#include <linux/elf.h> -int save_fp_registers(int pid, unsigned long *fp_regs) +int have_xstate_support; + +int save_i387_registers(int pid, unsigned long *fp_regs) { if (ptrace(PTRACE_GETFPREGS, pid, 0, fp_regs) < 0) return -errno; return 0; } -int restore_fp_registers(int pid, unsigned long *fp_regs) +int save_fp_registers(int pid, unsigned long *fp_regs) +{ + struct iovec iov; + + if (have_xstate_support) { + iov.iov_base = fp_regs; + iov.iov_len = sizeof(struct _xstate); + if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) < 0) + return -errno; + return 0; + } else { + return save_i387_registers(pid, fp_regs); + } +} + +int restore_i387_registers(int pid, unsigned long *fp_regs) { if (ptrace(PTRACE_SETFPREGS, pid, 0, fp_regs) < 0) return -errno; return 0; } +int restore_fp_registers(int pid, unsigned long *fp_regs) +{ + struct iovec iov; + + if (have_xstate_support) { + iov.iov_base = fp_regs; + iov.iov_len = sizeof(struct _xstate); + if (ptrace(PTRACE_SETREGSET, pid, NT_X86_XSTATE, &iov) < 0) + return -errno; + return 0; + } else { + return restore_i387_registers(pid, fp_regs); + } +} + #ifdef __i386__ int have_fpx_regs = 1; int save_fpx_registers(int pid, unsigned long *fp_regs) @@ -85,6 +120,16 @@ int put_fp_registers(int pid, unsigned long *regs) return restore_fp_registers(pid, regs); } +void arch_init_registers(int pid) +{ + struct _xstate fp_regs; + struct iovec iov; + + iov.iov_base = &fp_regs; + iov.iov_len = sizeof(struct _xstate); + if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) == 0) + have_xstate_support = 1; +} #endif unsigned long get_thread_reg(int reg, jmp_buf *buf) diff --git a/arch/x86/um/ptrace_32.c b/arch/x86/um/ptrace_32.c index 47c78d5..ebd4dd6 100644 --- a/arch/x86/um/ptrace_32.c +++ b/arch/x86/um/ptrace_32.c @@ -194,7 +194,8 @@ static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *c int err, n, cpu = ((struct thread_info *) child->stack)->cpu; struct user_i387_struct fpregs; - err = save_fp_registers(userspace_pid[cpu], (unsigned long *) &fpregs); + err = save_i387_registers(userspace_pid[cpu], + (unsigned long *) &fpregs); if (err) return err; @@ -214,7 +215,7 @@ static int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *c if (n > 0) return -EFAULT; - return restore_fp_registers(userspace_pid[cpu], + return restore_i387_registers(userspace_pid[cpu], (unsigned long *) &fpregs); } diff --git a/arch/x86/um/ptrace_64.c b/arch/x86/um/ptrace_64.c index a629694..faab418 100644 --- a/arch/x86/um/ptrace_64.c +++ b/arch/x86/um/ptrace_64.c @@ -222,14 +222,14 @@ int is_syscall(unsigned long addr) static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) { int err, n, cpu = ((struct thread_info *) child->stack)->cpu; - long fpregs[HOST_FP_SIZE]; + struct user_i387_struct fpregs; - BUG_ON(sizeof(*buf) != sizeof(fpregs)); - err = save_fp_registers(userspace_pid[cpu], fpregs); + err = save_i387_registers(userspace_pid[cpu], + (unsigned long *) &fpregs); if (err) return err; - n = copy_to_user(buf, fpregs, sizeof(fpregs)); + n = copy_to_user(buf, &fpregs, sizeof(fpregs)); if (n > 0) return -EFAULT; @@ -239,14 +239,14 @@ static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *c static int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) { int n, cpu = ((struct thread_info *) child->stack)->cpu; - long fpregs[HOST_FP_SIZE]; + struct user_i387_struct fpregs; - BUG_ON(sizeof(*buf) != sizeof(fpregs)); - n = copy_from_user(fpregs, buf, sizeof(fpregs)); + n = copy_from_user(&fpregs, buf, sizeof(fpregs)); if (n > 0) return -EFAULT; - return restore_fp_registers(userspace_pid[cpu], fpregs); + return restore_i387_registers(userspace_pid[cpu], + (unsigned long *) &fpregs); } long subarch_ptrace(struct task_struct *child, long request, diff --git a/arch/x86/um/shared/sysdep/ptrace_64.h b/arch/x86/um/shared/sysdep/ptrace_64.h index 919789f..0dc223a 100644 --- a/arch/x86/um/shared/sysdep/ptrace_64.h +++ b/arch/x86/um/shared/sysdep/ptrace_64.h @@ -57,8 +57,6 @@ #define UPT_SYSCALL_ARG5(r) UPT_R8(r) #define UPT_SYSCALL_ARG6(r) UPT_R9(r) -static inline void arch_init_registers(int pid) -{ -} +extern void arch_init_registers(int pid); #endif -- 2.7.2 |
From: Eli C. <eli...@gm...> - 2016-03-19 16:59:03
|
Extends fpstate to _xstate, in order to hold AVX/YMM registers. To avoid oversized stack frame, the following functions have been refactored by using malloc. - sig_handler_common - timer_real_alarm_handler Signed-off-by: Eli Cooper <eli...@gm...> --- arch/um/os-Linux/signal.c | 28 ++++++++++++++++++++-------- arch/x86/um/signal.c | 23 +++++++++++------------ arch/x86/um/user-offsets.c | 2 +- 3 files changed, 32 insertions(+), 21 deletions(-) diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index 7801666..8acaf4e 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c @@ -29,23 +29,29 @@ void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = { static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc) { - struct uml_pt_regs r; + struct uml_pt_regs *r; int save_errno = errno; - r.is_user = 0; + r = malloc(sizeof(struct uml_pt_regs)); + if (!r) + panic("out of memory"); + + r->is_user = 0; if (sig == SIGSEGV) { /* For segfaults, we want the data from the sigcontext. */ - get_regs_from_mc(&r, mc); - GET_FAULTINFO_FROM_MC(r.faultinfo, mc); + get_regs_from_mc(r, mc); + GET_FAULTINFO_FROM_MC(r->faultinfo, mc); } /* enable signals if sig isn't IRQ signal */ if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGALRM)) unblock_signals(); - (*sig_info[sig])(sig, si, &r); + (*sig_info[sig])(sig, si, r); errno = save_errno; + + free(r); } /* @@ -83,11 +89,17 @@ void sig_handler(int sig, struct siginfo *si, mcontext_t *mc) static void timer_real_alarm_handler(mcontext_t *mc) { - struct uml_pt_regs regs; + struct uml_pt_regs *regs; + + regs = malloc(sizeof(struct uml_pt_regs)); + if (!regs) + panic("out of memory"); if (mc != NULL) - get_regs_from_mc(®s, mc); - timer_handler(SIGALRM, NULL, ®s); + get_regs_from_mc(regs, mc); + timer_handler(SIGALRM, NULL, regs); + + free(regs); } void timer_alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc) diff --git a/arch/x86/um/signal.c b/arch/x86/um/signal.c index dac23ee..49e5036 100644 --- a/arch/x86/um/signal.c +++ b/arch/x86/um/signal.c @@ -226,7 +226,7 @@ static int copy_sc_from_user(struct pt_regs *regs, #endif { err = copy_from_user(regs->regs.fp, (void *)sc.fpstate, - sizeof(struct user_i387_struct)); + sizeof(struct _xstate)); if (err) return 1; } @@ -234,7 +234,7 @@ static int copy_sc_from_user(struct pt_regs *regs, } static int copy_sc_to_user(struct sigcontext __user *to, - struct _fpstate __user *to_fp, struct pt_regs *regs, + struct _xstate __user *to_fp, struct pt_regs *regs, unsigned long mask) { struct sigcontext sc; @@ -300,23 +300,22 @@ static int copy_sc_to_user(struct sigcontext __user *to, return 1; } - err = convert_fxsr_to_user(to_fp, &fpx); + err = convert_fxsr_to_user(&to_fp->fpstate, &fpx); if (err) return 1; - err |= __put_user(fpx.swd, &to_fp->status); - err |= __put_user(X86_FXSR_MAGIC, &to_fp->magic); + err |= __put_user(fpx.swd, &to_fp->fpstate.status); + err |= __put_user(X86_FXSR_MAGIC, &to_fp->fpstate.magic); if (err) return 1; - if (copy_to_user(&to_fp->_fxsr_env[0], &fpx, + if (copy_to_user(&to_fp->fpstate._fxsr_env[0], &fpx, sizeof(struct user_fxsr_struct))) return 1; } else #endif { - if (copy_to_user(to_fp, regs->regs.fp, - sizeof(struct user_i387_struct))) + if (copy_to_user(to_fp, regs->regs.fp, sizeof(struct _xstate))) return 1; } @@ -325,7 +324,7 @@ static int copy_sc_to_user(struct sigcontext __user *to, #ifdef CONFIG_X86_32 static int copy_ucontext_to_user(struct ucontext __user *uc, - struct _fpstate __user *fp, sigset_t *set, + struct _xstate __user *fp, sigset_t *set, unsigned long sp) { int err = 0; @@ -341,7 +340,7 @@ struct sigframe char __user *pretcode; int sig; struct sigcontext sc; - struct _fpstate fpstate; + struct _xstate fpstate; unsigned long extramask[_NSIG_WORDS-1]; char retcode[8]; }; @@ -354,7 +353,7 @@ struct rt_sigframe void __user *puc; struct siginfo info; struct ucontext uc; - struct _fpstate fpstate; + struct _xstate fpstate; char retcode[8]; }; @@ -483,7 +482,7 @@ struct rt_sigframe char __user *pretcode; struct ucontext uc; struct siginfo info; - struct _fpstate fpstate; + struct _xstate fpstate; }; int setup_signal_stack_si(unsigned long stack_top, struct ksignal *ksig, diff --git a/arch/x86/um/user-offsets.c b/arch/x86/um/user-offsets.c index 470564b..cb3c223 100644 --- a/arch/x86/um/user-offsets.c +++ b/arch/x86/um/user-offsets.c @@ -50,7 +50,7 @@ void foo(void) DEFINE(HOST_GS, GS); DEFINE(HOST_ORIG_AX, ORIG_EAX); #else - DEFINE(HOST_FP_SIZE, sizeof(struct _fpstate) / sizeof(unsigned long)); + DEFINE(HOST_FP_SIZE, sizeof(struct _xstate) / sizeof(unsigned long)); DEFINE_LONGS(HOST_BX, RBX); DEFINE_LONGS(HOST_CX, RCX); DEFINE_LONGS(HOST_DI, RDI); -- 2.7.2 |
From: Eli C. <eli...@gm...> - 2016-03-19 16:59:01
|
This series first fixes a bug that results in corrupted FPU state after invoking signal handlers. It also adds support for the extended processor state (XSTATE) for x86_64 UML, especially the YMM registers used by AVX(2) instructions. Tested with a minimal multi-threaded FPU-intensive test program (see below). This series supersedes the previous sigreturn fix as that one is incorrect when the process is multi-threaded. Changes since v2: - Add an improved sigreturn fix to this series - Merge the ptrace changes into the last commit - Make the selftest program multi-threaded Changes since v1: - Refactor functions with oversized stack frame - Add a tiny selftest program to the cover letter Eli Cooper (3): um: fix FPU state preservation around signal handlers um: extend fpstate to _xstate to support YMM registers um: add extended processor state save/restore support arch/um/include/shared/registers.h | 2 ++ arch/um/kernel/process.c | 2 +- arch/um/os-Linux/signal.c | 28 ++++++++++++++------ arch/x86/um/os-Linux/registers.c | 49 +++++++++++++++++++++++++++++++++-- arch/x86/um/ptrace_32.c | 5 ++-- arch/x86/um/ptrace_64.c | 16 ++++++------ arch/x86/um/shared/sysdep/ptrace_64.h | 4 +-- arch/x86/um/signal.c | 37 +++++++++----------------- arch/x86/um/user-offsets.c | 2 +- 9 files changed, 95 insertions(+), 50 deletions(-) -- /* Test if context switches preserve YMM registers, multi-threaded version * The main function, threads and the signal handler all have their unique * ymm0 value, and constantly detect if someone steps on their toes. * Should loop forever. */ #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <signal.h> #include <unistd.h> #include <pthread.h> #include <sys/time.h> #include <immintrin.h> #define N 10 void sighandler(int signum) { int n = 0xffff; register uint32_t eax asm("eax"); __m256i m0 = _mm256_set_epi64x(0x1234L << 32, 0, 0, 0); while (n--) { asm("vextracti128 $1,%ymm0,%xmm1"); asm("vpextrd $3,%xmm1,%eax"); if (eax != 0x1234) exit(3); } } void thread(void *arg) { long n = (long)arg; register uint32_t eax asm("eax"); __m256i m0 = _mm256_set_epi64x(n << 32, 0, 0, 0); do { asm("vextracti128 $1,%ymm0,%xmm1"); asm("vpextrd $3,%xmm1,%eax"); } while (eax == n); exit(2); } int main() { register uint32_t eax asm("eax"); pthread_t threads[N]; struct itimerval itv; struct timeval tv; struct sigaction act; tv.tv_sec = 0; tv.tv_usec = 100000; itv.it_interval = tv; itv.it_value = tv; act.sa_handler = sighandler; act.sa_flags = 0; sigemptyset(&act.sa_mask); sigaction(SIGALRM, &act, NULL); setitimer(ITIMER_REAL, &itv, NULL); for (long i = 0; i < N; i++) pthread_create(threads + i, NULL, (void *)thread, (void *)i); __m256i m0 = _mm256_set_epi64x(0xabcdL << 32, 0, 0, 0); do { asm("vextracti128 $1,%ymm0,%xmm1"); asm("vpextrd $3,%xmm1,%eax"); } while (eax == 0xabcd); printf("%lx\n", eax); return 1; } |
From: Eli C. <eli...@gm...> - 2016-03-19 16:59:01
|
This patch makes UML saves/restores FPU state from/to the fpstate in pt_regs when setting up or returning from a signal stack, rather than calling ptrace directly. This ensures that FPU state is correctly preserved around signal handlers in a multi-threaded scenario. Signed-off-by: Eli Cooper <eli...@gm...> --- arch/x86/um/signal.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/arch/x86/um/signal.c b/arch/x86/um/signal.c index 14fcd01..dac23ee 100644 --- a/arch/x86/um/signal.c +++ b/arch/x86/um/signal.c @@ -225,20 +225,10 @@ static int copy_sc_from_user(struct pt_regs *regs, } else #endif { - struct user_i387_struct fp; - - err = copy_from_user(&fp, (void *)sc.fpstate, + err = copy_from_user(regs->regs.fp, (void *)sc.fpstate, sizeof(struct user_i387_struct)); if (err) return 1; - - err = restore_fp_registers(pid, (unsigned long *) &fp); - if (err < 0) { - printk(KERN_ERR "copy_sc_from_user - " - "restore_fp_registers failed, errno = %d\n", - -err); - return 1; - } } return 0; } @@ -325,10 +315,8 @@ static int copy_sc_to_user(struct sigcontext __user *to, } else #endif { - struct user_i387_struct fp; - - err = save_fp_registers(pid, (unsigned long *) &fp); - if (copy_to_user(to_fp, &fp, sizeof(struct user_i387_struct))) + if (copy_to_user(to_fp, regs->regs.fp, + sizeof(struct user_i387_struct))) return 1; } -- 2.7.2 |
From: Richard W. <ri...@no...> - 2016-03-18 20:12:18
|
Jeff, Eli, Am 18.03.2016 um 17:42 schrieb Jeff Dike: > On Sat, Mar 19, 2016 at 12:13:47AM +0800, Eli Cooper wrote: >> I agree that we should keep userspace() minimal. So what in the first >> place is the FPU state save/restore code for? Or, what (except for >> sigreturn) could possibly mess the FPU state of the ptrace'd process >> without it? > > My (vague) recollection was that with libc in there, I couldn't be > confident that it wouldn't unexpectedly use FP for something. So, > saving and restoring FP state was a hedge against that happening. > > Jeff > git blame points to: commit fbfe9c847edf57ac8232aeafb290f272289893a3 Author: Ingo van Lil <in...@gm...> Date: Wed Sep 14 16:21:23 2011 -0700 um: Save FPU registers between task switches Some time ago Jeff prepared 42daba316557 ("uml: stop saving process FP state") for UML to stop saving the process FP state between task switches. The assumption was that since with SKAS0 every guest process runs inside a host process context the host OS will take care of keeping the proper FP state. Unfortunately this is not true for multi-threaded applications, where all guest threads share a single host process context yet all may use the FPU on their own. Although I haven't verified it I suspect things to be even worse in SKAS3 mode where all guest processes run inside a single host process. The patch reintroduces the saving and restoring of the FP context between task switches. [ri...@no...: Ingo posted this patch in 2009, sadly it was never applied and got lost. Now in 2011 the problem was reported by Gunnar.] Signed-off-by: Ingo van Lil <in...@gm...> Signed-off-by: Richard Weinberger <ri...@no...> Reported-by: <gun...@ho...> Tested-by: <gun...@ho...> Cc: Stanislav Meduna <st...@me...> Signed-off-by: Andrew Morton <ak...@li...> Signed-off-by: Linus Torvalds <tor...@li...> So, it is not that easy. :=) Thanks, //richard |
From: Jeff D. <jd...@ad...> - 2016-03-18 17:01:49
|
On Sat, Mar 19, 2016 at 12:13:47AM +0800, Eli Cooper wrote: > I agree that we should keep userspace() minimal. So what in the first > place is the FPU state save/restore code for? Or, what (except for > sigreturn) could possibly mess the FPU state of the ptrace'd process > without it? My (vague) recollection was that with libc in there, I couldn't be confident that it wouldn't unexpectedly use FP for something. So, saving and restoring FP state was a hedge against that happening. Jeff -- Jeff Dike AddToIt 978-254-0789 (o) 978-394-8986 (c) |
From: Eli C. <eli...@gm...> - 2016-03-18 16:12:06
|
Hi Richard, On 2016/3/18 16:20, Richard Weinberger wrote: > I wonder how other architectures handle this case? > Ideally I'd like to avoid as much extra code as possible in userspace(). Please forgive my ignorance of other architectures. But to the best of my knowledge, FPU state is not saved and restored around a system call in x86. I agree that we should keep userspace() minimal. So what in the first place is the FPU state save/restore code for? Or, what (except for sigreturn) could possibly mess the FPU state of the ptrace'd process without it? I tried commenting out the FPU restore code in userspace() and tested with a bunch of kernel modules and userland programs. Nothing bad happened so far as I can tell. Thanks, Eli |
From: Richard W. <ri...@no...> - 2016-03-18 08:20:59
|
Eli, Am 18.03.2016 um 02:41 schrieb Eli Cooper: > Hi Richard, > > On 2016/3/18 6:21, Richard Weinberger wrote: >> Where exactly are the FPU regs restored in the sigregturn case? >> Not sure if I fully understand the error scenario. > > Well, sys_sigreturn() or sys_rt_sigreturn() calls copy_sc_from_user(), > and the latter copies fpstate, which is the saved FPU state before the > signal handler was invoked, from sigframe and restores it. > That is correct: after returning from the signal handler, the process is > in the same FPU state before it was invoked. > > However, userspace() saves the FPU state before a system call and > restores it after. In the sigreturn case, after sys_sigreturn() returns, > which has already made FPU in the right state, userspace() overwrites it > by making it in the state prior to the sigreturn was called (i.e., the > signal handler's state). That leaves the process in question a corrupted > FPU state. Okay. That's what I thought/feared. I wonder how other architectures handle this case? Ideally I'd like to avoid as much extra code as possible in userspace(). Thanks, //richard |
From: Eli C. <eli...@gm...> - 2016-03-18 01:39:46
|
Hi Richard, On 2016/3/18 6:21, Richard Weinberger wrote: > Where exactly are the FPU regs restored in the sigregturn case? > Not sure if I fully understand the error scenario. Well, sys_sigreturn() or sys_rt_sigreturn() calls copy_sc_from_user(), and the latter copies fpstate, which is the saved FPU state before the signal handler was invoked, from sigframe and restores it. That is correct: after returning from the signal handler, the process is in the same FPU state before it was invoked. However, userspace() saves the FPU state before a system call and restores it after. In the sigreturn case, after sys_sigreturn() returns, which has already made FPU in the right state, userspace() overwrites it by making it in the state prior to the sigreturn was called (i.e., the signal handler's state). That leaves the process in question a corrupted FPU state. Eli |
From: Richard W. <ri...@no...> - 2016-03-17 22:21:54
|
Eli, Am 16.03.2016 um 02:25 schrieb Eli Cooper: > This patch prevents userspace() from incorrectly restoring FPU registers > after a sigreturn or rt_sigreturn system call, which has already restored > FPU registers to the state prior to the signal handler was invoked. > > Fixes FPU state corruption after invoking the signal handler. First of all, thanks a lot for hunting down these nasty issues! Where exactly are the FPU regs restored in the sigregturn case? Not sure if I fully understand the error scenario. Thanks, //richard |
From: Eli C. <eli...@gm...> - 2016-03-16 08:48:55
|
This patch extends save_fp_registers() and restore_fp_registers() to use PTRACE_GETREGSET and PTRACE_SETREGSET with the XSTATE note type, adding support for new processor state extensions. Now these functions expect *fp_regs to have the space of an _xstate struct. When the new ptrace requests are unavailable, it falls back to the old PTRACE_GETFPREGS and PTRACE_SETFPREGS methods, which have been renamed to save_i387_registers() and restore_i387_registers(). Signed-off-by: Eli Cooper <eli...@gm...> --- arch/um/include/shared/registers.h | 2 ++ arch/um/kernel/process.c | 2 +- arch/x86/um/os-Linux/registers.c | 49 +++++++++++++++++++++++++++++++++-- arch/x86/um/shared/sysdep/ptrace_64.h | 4 +-- 4 files changed, 51 insertions(+), 6 deletions(-) diff --git a/arch/um/include/shared/registers.h b/arch/um/include/shared/registers.h index f5b7635..a74449b 100644 --- a/arch/um/include/shared/registers.h +++ b/arch/um/include/shared/registers.h @@ -9,6 +9,8 @@ #include <sysdep/ptrace.h> #include <sysdep/archsetjmp.h> +extern int save_i387_registers(int pid, unsigned long *fp_regs); +extern int restore_i387_registers(int pid, unsigned long *fp_regs); 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); diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index 48af59a..d55a473 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -402,6 +402,6 @@ int elf_core_copy_fpregs(struct task_struct *t, elf_fpregset_t *fpu) { int cpu = current_thread_info()->cpu; - return save_fp_registers(userspace_pid[cpu], (unsigned long *) fpu); + return save_i387_registers(userspace_pid[cpu], (unsigned long *) fpu); } diff --git a/arch/x86/um/os-Linux/registers.c b/arch/x86/um/os-Linux/registers.c index 41bfe84..00f54a9 100644 --- a/arch/x86/um/os-Linux/registers.c +++ b/arch/x86/um/os-Linux/registers.c @@ -11,21 +11,56 @@ #endif #include <longjmp.h> #include <sysdep/ptrace_user.h> +#include <sys/uio.h> +#include <asm/sigcontext.h> +#include <linux/elf.h> -int save_fp_registers(int pid, unsigned long *fp_regs) +int have_xstate_support; + +int save_i387_registers(int pid, unsigned long *fp_regs) { if (ptrace(PTRACE_GETFPREGS, pid, 0, fp_regs) < 0) return -errno; return 0; } -int restore_fp_registers(int pid, unsigned long *fp_regs) +int save_fp_registers(int pid, unsigned long *fp_regs) +{ + struct iovec iov; + + if (have_xstate_support) { + iov.iov_base = fp_regs; + iov.iov_len = sizeof(struct _xstate); + if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) < 0) + return -errno; + return 0; + } else { + return save_i387_registers(pid, fp_regs); + } +} + +int restore_i387_registers(int pid, unsigned long *fp_regs) { if (ptrace(PTRACE_SETFPREGS, pid, 0, fp_regs) < 0) return -errno; return 0; } +int restore_fp_registers(int pid, unsigned long *fp_regs) +{ + struct iovec iov; + + if (have_xstate_support) { + iov.iov_base = fp_regs; + iov.iov_len = sizeof(struct _xstate); + if (ptrace(PTRACE_SETREGSET, pid, NT_X86_XSTATE, &iov) < 0) + return -errno; + return 0; + } else { + return restore_i387_registers(pid, fp_regs); + } +} + #ifdef __i386__ int have_fpx_regs = 1; int save_fpx_registers(int pid, unsigned long *fp_regs) @@ -85,6 +120,16 @@ int put_fp_registers(int pid, unsigned long *regs) return restore_fp_registers(pid, regs); } +void arch_init_registers(int pid) +{ + struct _xstate fp_regs; + struct iovec iov; + + iov.iov_base = &fp_regs; + iov.iov_len = sizeof(struct _xstate); + if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) == 0) + have_xstate_support = 1; +} #endif unsigned long get_thread_reg(int reg, jmp_buf *buf) diff --git a/arch/x86/um/shared/sysdep/ptrace_64.h b/arch/x86/um/shared/sysdep/ptrace_64.h index 919789f..0dc223a 100644 --- a/arch/x86/um/shared/sysdep/ptrace_64.h +++ b/arch/x86/um/shared/sysdep/ptrace_64.h @@ -57,8 +57,6 @@ #define UPT_SYSCALL_ARG5(r) UPT_R8(r) #define UPT_SYSCALL_ARG6(r) UPT_R9(r) -static inline void arch_init_registers(int pid) -{ -} +extern void arch_init_registers(int pid); #endif -- 2.7.2 |
From: Eli C. <eli...@gm...> - 2016-03-16 08:48:54
|
Extends _fpstate to _xstate, in order to hold AVX/YMM registers. To avoid oversized stack frame, the following functions has been refactored by using (k)malloc. - copy_sc_to_user - copy_sc_from_user - sig_handler_common - timer_real_alarm_handler Signed-off-by: Eli Cooper <eli...@gm...> --- arch/um/os-Linux/signal.c | 28 ++++++++++++++++------- arch/x86/um/signal.c | 57 ++++++++++++++++++++++++++++++---------------- arch/x86/um/user-offsets.c | 2 +- 3 files changed, 59 insertions(+), 28 deletions(-) diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index 7801666..8acaf4e 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c @@ -29,23 +29,29 @@ void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = { static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc) { - struct uml_pt_regs r; + struct uml_pt_regs *r; int save_errno = errno; - r.is_user = 0; + r = malloc(sizeof(struct uml_pt_regs)); + if (!r) + panic("out of memory"); + + r->is_user = 0; if (sig == SIGSEGV) { /* For segfaults, we want the data from the sigcontext. */ - get_regs_from_mc(&r, mc); - GET_FAULTINFO_FROM_MC(r.faultinfo, mc); + get_regs_from_mc(r, mc); + GET_FAULTINFO_FROM_MC(r->faultinfo, mc); } /* enable signals if sig isn't IRQ signal */ if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGALRM)) unblock_signals(); - (*sig_info[sig])(sig, si, &r); + (*sig_info[sig])(sig, si, r); errno = save_errno; + + free(r); } /* @@ -83,11 +89,17 @@ void sig_handler(int sig, struct siginfo *si, mcontext_t *mc) static void timer_real_alarm_handler(mcontext_t *mc) { - struct uml_pt_regs regs; + struct uml_pt_regs *regs; + + regs = malloc(sizeof(struct uml_pt_regs)); + if (!regs) + panic("out of memory"); if (mc != NULL) - get_regs_from_mc(®s, mc); - timer_handler(SIGALRM, NULL, ®s); + get_regs_from_mc(regs, mc); + timer_handler(SIGALRM, NULL, regs); + + free(regs); } void timer_alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc) diff --git a/arch/x86/um/signal.c b/arch/x86/um/signal.c index 14fcd01..a350535 100644 --- a/arch/x86/um/signal.c +++ b/arch/x86/um/signal.c @@ -8,6 +8,7 @@ #include <linux/personality.h> #include <linux/ptrace.h> #include <linux/kernel.h> +#include <linux/slab.h> #include <asm/unistd.h> #include <asm/uaccess.h> #include <asm/ucontext.h> @@ -155,6 +156,7 @@ static int copy_sc_from_user(struct pt_regs *regs, { struct sigcontext sc; int err, pid; + struct _xstate *fp; /* Always make any pending restarted system calls return -EINTR */ current->restart_block.fn = do_no_restart_syscall; @@ -225,30 +227,39 @@ static int copy_sc_from_user(struct pt_regs *regs, } else #endif { - struct user_i387_struct fp; + fp = kmalloc(sizeof(struct _xstate), GFP_ATOMIC); + if (!fp) + return 1; - err = copy_from_user(&fp, (void *)sc.fpstate, - sizeof(struct user_i387_struct)); + err = copy_from_user(fp, (void *)sc.fpstate, + sizeof(struct _xstate)); if (err) - return 1; + goto err; - err = restore_fp_registers(pid, (unsigned long *) &fp); + err = restore_fp_registers(pid, (unsigned long *) fp); if (err < 0) { printk(KERN_ERR "copy_sc_from_user - " "restore_fp_registers failed, errno = %d\n", -err); - return 1; + goto err; } + + kfree(fp); } return 0; + +err: + kfree(fp); + return 1; } static int copy_sc_to_user(struct sigcontext __user *to, - struct _fpstate __user *to_fp, struct pt_regs *regs, + struct _xstate __user *to_fp, struct pt_regs *regs, unsigned long mask) { struct sigcontext sc; struct faultinfo * fi = ¤t->thread.arch.faultinfo; + struct _xstate *fp; int err, pid; memset(&sc, 0, sizeof(struct sigcontext)); @@ -310,34 +321,42 @@ static int copy_sc_to_user(struct sigcontext __user *to, return 1; } - err = convert_fxsr_to_user(to_fp, &fpx); + err = convert_fxsr_to_user(&to_fp->fpstate, &fpx); if (err) return 1; - err |= __put_user(fpx.swd, &to_fp->status); - err |= __put_user(X86_FXSR_MAGIC, &to_fp->magic); + err |= __put_user(fpx.swd, &to_fp->fpstate.status); + err |= __put_user(X86_FXSR_MAGIC, &to_fp->fpstate.magic); if (err) return 1; - if (copy_to_user(&to_fp->_fxsr_env[0], &fpx, + if (copy_to_user(&to_fp->fpstate._fxsr_env[0], &fpx, sizeof(struct user_fxsr_struct))) return 1; } else #endif { - struct user_i387_struct fp; - - err = save_fp_registers(pid, (unsigned long *) &fp); - if (copy_to_user(to_fp, &fp, sizeof(struct user_i387_struct))) + fp = kmalloc(sizeof(struct _xstate), GFP_ATOMIC); + if (!fp) return 1; + + err = save_fp_registers(pid, (unsigned long *) fp); + if (copy_to_user(to_fp, fp, sizeof(struct _xstate))) + goto err; + + kfree(fp); } return 0; + +err: + kfree(fp); + return 1; } #ifdef CONFIG_X86_32 static int copy_ucontext_to_user(struct ucontext __user *uc, - struct _fpstate __user *fp, sigset_t *set, + struct _xstate __user *fp, sigset_t *set, unsigned long sp) { int err = 0; @@ -353,7 +372,7 @@ struct sigframe char __user *pretcode; int sig; struct sigcontext sc; - struct _fpstate fpstate; + struct _xstate fpstate; unsigned long extramask[_NSIG_WORDS-1]; char retcode[8]; }; @@ -366,7 +385,7 @@ struct rt_sigframe void __user *puc; struct siginfo info; struct ucontext uc; - struct _fpstate fpstate; + struct _xstate fpstate; char retcode[8]; }; @@ -495,7 +514,7 @@ struct rt_sigframe char __user *pretcode; struct ucontext uc; struct siginfo info; - struct _fpstate fpstate; + struct _xstate fpstate; }; int setup_signal_stack_si(unsigned long stack_top, struct ksignal *ksig, diff --git a/arch/x86/um/user-offsets.c b/arch/x86/um/user-offsets.c index 470564b..cb3c223 100644 --- a/arch/x86/um/user-offsets.c +++ b/arch/x86/um/user-offsets.c @@ -50,7 +50,7 @@ void foo(void) DEFINE(HOST_GS, GS); DEFINE(HOST_ORIG_AX, ORIG_EAX); #else - DEFINE(HOST_FP_SIZE, sizeof(struct _fpstate) / sizeof(unsigned long)); + DEFINE(HOST_FP_SIZE, sizeof(struct _xstate) / sizeof(unsigned long)); DEFINE_LONGS(HOST_BX, RBX); DEFINE_LONGS(HOST_CX, RCX); DEFINE_LONGS(HOST_DI, RDI); -- 2.7.2 |
From: Eli C. <eli...@gm...> - 2016-03-16 08:48:52
|
This patch makes ptrace in UML responde to PTRACE_GETFPREGS/_SETFPREG requests with a user_i387_struct (thus independent from HOST_FP_SIZE), and by calling save_i387_registers() and restore_i387_registers() instead of the extended save_fp_registers() and restore_fp_registers() functions. Signed-off-by: Eli Cooper <eli...@gm...> --- arch/x86/um/ptrace_32.c | 5 +++-- arch/x86/um/ptrace_64.c | 16 ++++++++-------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/arch/x86/um/ptrace_32.c b/arch/x86/um/ptrace_32.c index 47c78d5..ebd4dd6 100644 --- a/arch/x86/um/ptrace_32.c +++ b/arch/x86/um/ptrace_32.c @@ -194,7 +194,8 @@ static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *c int err, n, cpu = ((struct thread_info *) child->stack)->cpu; struct user_i387_struct fpregs; - err = save_fp_registers(userspace_pid[cpu], (unsigned long *) &fpregs); + err = save_i387_registers(userspace_pid[cpu], + (unsigned long *) &fpregs); if (err) return err; @@ -214,7 +215,7 @@ static int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *c if (n > 0) return -EFAULT; - return restore_fp_registers(userspace_pid[cpu], + return restore_i387_registers(userspace_pid[cpu], (unsigned long *) &fpregs); } diff --git a/arch/x86/um/ptrace_64.c b/arch/x86/um/ptrace_64.c index a629694..faab418 100644 --- a/arch/x86/um/ptrace_64.c +++ b/arch/x86/um/ptrace_64.c @@ -222,14 +222,14 @@ int is_syscall(unsigned long addr) static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) { int err, n, cpu = ((struct thread_info *) child->stack)->cpu; - long fpregs[HOST_FP_SIZE]; + struct user_i387_struct fpregs; - BUG_ON(sizeof(*buf) != sizeof(fpregs)); - err = save_fp_registers(userspace_pid[cpu], fpregs); + err = save_i387_registers(userspace_pid[cpu], + (unsigned long *) &fpregs); if (err) return err; - n = copy_to_user(buf, fpregs, sizeof(fpregs)); + n = copy_to_user(buf, &fpregs, sizeof(fpregs)); if (n > 0) return -EFAULT; @@ -239,14 +239,14 @@ static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *c static int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) { int n, cpu = ((struct thread_info *) child->stack)->cpu; - long fpregs[HOST_FP_SIZE]; + struct user_i387_struct fpregs; - BUG_ON(sizeof(*buf) != sizeof(fpregs)); - n = copy_from_user(fpregs, buf, sizeof(fpregs)); + n = copy_from_user(&fpregs, buf, sizeof(fpregs)); if (n > 0) return -EFAULT; - return restore_fp_registers(userspace_pid[cpu], fpregs); + return restore_i387_registers(userspace_pid[cpu], + (unsigned long *) &fpregs); } long subarch_ptrace(struct task_struct *child, long request, -- 2.7.2 |
From: Eli C. <eli...@gm...> - 2016-03-16 08:48:47
|
This series adds support for the extended processor state (XSTATE) for x86_64 UML, especially the YMM registers used by AVX/AVX2 instructions. Modern userspace programs built with AVX can now run inside x86_64 UML without YMM registers getting corrupted. Tested with a tiny selftest program below, which of course requires the following patch I sent earlier today to run correctly. um: fix FPU register double-restore after sigreturn Also tested with a latest Arch Linux image on a CPU with AVX2 support. Without YMM support in UML, a lot of programs crash unexpectedly, or result in bad results (e.g., calculating SHA256 in OpenSSL). Changes since v1: - Refactor functions with oversized stack frame - Add a tiny selftest program to the cover letter Eli Cooper (3): um: extend _fpstate to _xstate um: add extended processor state save/restore support um: fix ptrace PTRACE_GETFPREGS and PTRACE_SETFPREG support arch/um/include/shared/registers.h | 2 ++ arch/um/kernel/process.c | 2 +- arch/um/os-Linux/signal.c | 28 ++++++++++++----- arch/x86/um/os-Linux/registers.c | 49 ++++++++++++++++++++++++++++-- arch/x86/um/ptrace_32.c | 5 +-- arch/x86/um/ptrace_64.c | 16 +++++----- arch/x86/um/shared/sysdep/ptrace_64.h | 4 +-- arch/x86/um/signal.c | 57 +++++++++++++++++++++++------------ arch/x86/um/user-offsets.c | 2 +- 9 files changed, 121 insertions(+), 44 deletions(-) --- /* test if context switches preserve YMM registers, should exit with code 0 */ #include <stdint.h> #include <unistd.h> #include <signal.h> #include <immintrin.h> int flag; void sighandler(int signum) { if (flag) exit(0); alarm(1); flag = 1; __m256i m0 = _mm256_set_epi64x(0, 0, 0, 0); } int main() { register uint32_t a asm("eax") = 0; signal(SIGALRM, sighandler); alarm(1); __m256i m0 = _mm256_set_epi64x(1L << 32, 0, 0, 0); do { asm("vextracti128 $1,%ymm0,%xmm1"); asm("vpextrd $3,%xmm1,%eax"); } while (a == 1); return 1; } |
From: Eli C. <eli...@gm...> - 2016-03-16 01:25:24
|
This patch prevents userspace() from incorrectly restoring FPU registers after a sigreturn or rt_sigreturn system call, which has already restored FPU registers to the state prior to the signal handler was invoked. Fixes FPU state corruption after invoking the signal handler. Signed-off-by: Eli Cooper <eli...@gm...> --- arch/um/os-Linux/skas/process.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c index 23025d6..664f184 100644 --- a/arch/um/os-Linux/skas/process.c +++ b/arch/um/os-Linux/skas/process.c @@ -310,6 +310,8 @@ 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; + /* To prevent FPU register restore after sigreturn syscalls. */ + int skip_fp_restore = 0; siginfo_t si; /* Handle any immediate reschedules or signals */ @@ -328,8 +330,9 @@ void userspace(struct uml_pt_regs *regs) if (ptrace(PTRACE_SETREGS, pid, 0, regs->gp)) fatal_sigsegv(); - if (put_fp_registers(pid, regs->fp)) - fatal_sigsegv(); + if (!skip_fp_restore) + if (put_fp_registers(pid, regs->fp)) + fatal_sigsegv(); /* Now we set local_using_sysemu to be used for one loop */ local_using_sysemu = get_using_sysemu(); @@ -351,6 +354,7 @@ void userspace(struct uml_pt_regs *regs) } regs->is_user = 1; + skip_fp_restore = 0; if (ptrace(PTRACE_GETREGS, pid, 0, regs->gp)) { printk(UM_KERN_ERR "userspace - PTRACE_GETREGS failed, " "errno = %d\n", errno); @@ -381,6 +385,12 @@ void userspace(struct uml_pt_regs *regs) else handle_segv(pid, regs); break; case SIGTRAP + 0x80: +#ifdef __i386__ + if (PT_SYSCALL_NR(regs->gp) == __NR_sigreturn) + skip_fp_restore = 1; +#endif + if (PT_SYSCALL_NR(regs->gp) == __NR_rt_sigreturn) + skip_fp_restore = 1; handle_trap(pid, regs, local_using_sysemu); break; case SIGTRAP: -- 2.7.2 |
From: <st...@ni...> - 2016-03-14 08:22:54
|
> /* test if signal handling preserves XMM registers */ > #include <stdio.h> > #include <unistd.h> > #include <signal.h> > > int count; > > void sighandler(int signum) > { > count++; > > /* alarm(1) without calling libc */ > asm("mov $0x1,%rdi"); > asm("mov $0x25,%rax"); > asm("syscall"); > > asm("movq $0xdeadbeef,%r11"); > /* the following two instructions > * modify xmm0 and xmm1 registers */ > asm("vmovq %r11,%xmm0"); > asm("vmovq %r11,%xmm1"); > } > > int main() > { > struct sigaction act; > double a = 3.14159, b = 2.71828; > > act.sa_handler = sighandler; > act.sa_flags = 0; > sigemptyset(&act.sa_mask); > sigaction(SIGALRM, &act, NULL); > > alarm(1); > > /* this loop should run indefinitely */ > while (a + b == a + b) ; > > printf("count = %d\n", count); if you put a break here in gdb, and dump the FPU regs, what does it say? Can be that either we a lacking or missplaced a fwait (to flush FPU) > return 1; > } |
From: Eli C. <eli...@gm...> - 2016-03-13 13:55:12
|
Hi Richard, On 2016/3/13 15:58, Richard Weinberger wrote: > Eli, > > Am 12.03.2016 um 08:08 schrieb Eli Cooper: >> > Hi Richard, >> > >> > On 2016/3/10 4:44, Richard Weinberger wrote: >>> >> Hmm, this needs rework. Having everything on the stack is not good. >> > >> > Okay, I'll rework the functions whose stack size is greater than the >> > warning threshold by using kmalloc. > I fear it is not that easy. Having a kmalloc() per context switch would > be every expensive. Even for UML. Actually only two functions' stack frame size exceed kernel's default warning threshold (1024 bytes) after the _xstate extension, i.e., copy_sc_from_user and copy_sc_to_user. That's because they have an _xstate on stack as well as a sigcontext, which contains another _xstate. Context switches due to signal handling are rare; thus I think having a kmalloc() for signal handling is acceptable. >>> >> Can you also create a selftest such that this bug cannot happen again? >> > >> > It seems that instead of writing a self-test showing this problem cannot >> > happen again, I wrote a test that manifested another bug that is not >> > directly related to my patch. >> > >> > Without applying my patch, the current UML should support XMM registers >> > because those are covered by _fpstate and PTRACE_GETFPREGS. But it >> > seemed that XMM registers are not restored after the signal handler returns. >> > >> > In the following quick test, the main loop should run indefinitely >> > despite XMM registers are modified by the signal handler. But in UML, >> > the loop breaks randomly within a minute or two, showing that the >> > registers are corrupted. So far I haven't found the cause. Any hints? > Meh. :( > Can you figure out whether the issue depends on the host kernel? i.e. try something older > and Linus' tree. > UML is a heavy user of ptrace(), maybe the recent FPU cleanup on x86 broke something. No, it seems that this issue does not depend on the host kernel, UML kernel, or CPU. I can reproduce this bug on a variety of combinations of them, with the host kernel ranging from 2.6.32 to 3.19 to 4.5. Thanks, Eli > > Thanks, > //richard > |
From: Richard W. <ri...@no...> - 2016-03-13 07:58:26
|
Eli, Am 12.03.2016 um 08:08 schrieb Eli Cooper: > Hi Richard, > > On 2016/3/10 4:44, Richard Weinberger wrote: >> Hmm, this needs rework. Having everything on the stack is not good. > > Okay, I'll rework the functions whose stack size is greater than the > warning threshold by using kmalloc. I fear it is not that easy. Having a kmalloc() per context switch would be every expensive. Even for UML. >> Can you also create a selftest such that this bug cannot happen again? > > It seems that instead of writing a self-test showing this problem cannot > happen again, I wrote a test that manifested another bug that is not > directly related to my patch. > > Without applying my patch, the current UML should support XMM registers > because those are covered by _fpstate and PTRACE_GETFPREGS. But it > seemed that XMM registers are not restored after the signal handler returns. > > In the following quick test, the main loop should run indefinitely > despite XMM registers are modified by the signal handler. But in UML, > the loop breaks randomly within a minute or two, showing that the > registers are corrupted. So far I haven't found the cause. Any hints? Meh. :( Can you figure out whether the issue depends on the host kernel? i.e. try something older and Linus' tree. UML is a heavy user of ptrace(), maybe the recent FPU cleanup on x86 broke something. Thanks, //richard > Thanks, > Eli > > --- > /* test if signal handling preserves XMM registers */ > #include <stdio.h> > #include <unistd.h> > #include <signal.h> > > int count; > > void sighandler(int signum) > { > count++; > > /* alarm(1) without calling libc */ > asm("mov $0x1,%rdi"); > asm("mov $0x25,%rax"); > asm("syscall"); > > asm("movq $0xdeadbeef,%r11"); > /* the following two instructions > * modify xmm0 and xmm1 registers */ > asm("vmovq %r11,%xmm0"); > asm("vmovq %r11,%xmm1"); > } > > int main() > { > struct sigaction act; > double a = 3.14159, b = 2.71828; > > act.sa_handler = sighandler; > act.sa_flags = 0; > sigemptyset(&act.sa_mask); > sigaction(SIGALRM, &act, NULL); > > alarm(1); > > /* this loop should run indefinitely */ > while (a + b == a + b) ; > > printf("count = %d\n", count); > return 1; > } > |
From: Eli C. <eli...@gm...> - 2016-03-12 07:06:27
|
Hi Richard, On 2016/3/10 4:44, Richard Weinberger wrote: > Hmm, this needs rework. Having everything on the stack is not good. Okay, I'll rework the functions whose stack size is greater than the warning threshold by using kmalloc. > Can you also create a selftest such that this bug cannot happen again? It seems that instead of writing a self-test showing this problem cannot happen again, I wrote a test that manifested another bug that is not directly related to my patch. Without applying my patch, the current UML should support XMM registers because those are covered by _fpstate and PTRACE_GETFPREGS. But it seemed that XMM registers are not restored after the signal handler returns. In the following quick test, the main loop should run indefinitely despite XMM registers are modified by the signal handler. But in UML, the loop breaks randomly within a minute or two, showing that the registers are corrupted. So far I haven't found the cause. Any hints? Thanks, Eli --- /* test if signal handling preserves XMM registers */ #include <stdio.h> #include <unistd.h> #include <signal.h> int count; void sighandler(int signum) { count++; /* alarm(1) without calling libc */ asm("mov $0x1,%rdi"); asm("mov $0x25,%rax"); asm("syscall"); asm("movq $0xdeadbeef,%r11"); /* the following two instructions * modify xmm0 and xmm1 registers */ asm("vmovq %r11,%xmm0"); asm("vmovq %r11,%xmm1"); } int main() { struct sigaction act; double a = 3.14159, b = 2.71828; act.sa_handler = sighandler; act.sa_flags = 0; sigemptyset(&act.sa_mask); sigaction(SIGALRM, &act, NULL); alarm(1); /* this loop should run indefinitely */ while (a + b == a + b) ; printf("count = %d\n", count); return 1; } |
From: Richard W. <ri...@no...> - 2016-03-09 20:44:21
|
Hi! Am 06.03.2016 um 15:36 schrieb Eli Cooper: > Extends _fpstate to _xstate, in order to hold AVX/YMM registers. > Due to increased frame size, compilers might emit some warnings. Hmm, this needs rework. Having everything on the stack is not good. Can you also create a selftest such that this bug cannot happen again? Thanks, //richard |
From: Eli C. <eli...@gm...> - 2016-03-06 14:36:57
|
This patch makes ptrace in UML responde to PTRACE_GETFPREGS/_SETFPREG requests with a user_i387_struct (thus independent from HOST_FP_SIZE), and by calling save_i387_registers() and restore_i387_registers() instead of the extended save_fp_registers() and restore_fp_registers() functions. Signed-off-by: Eli Cooper <eli...@gm...> --- arch/x86/um/ptrace_32.c | 4 ++-- arch/x86/um/ptrace_64.c | 14 ++++++-------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/arch/x86/um/ptrace_32.c b/arch/x86/um/ptrace_32.c index 47c78d5..2eeaf2c 100644 --- a/arch/x86/um/ptrace_32.c +++ b/arch/x86/um/ptrace_32.c @@ -194,7 +194,7 @@ static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *c int err, n, cpu = ((struct thread_info *) child->stack)->cpu; struct user_i387_struct fpregs; - err = save_fp_registers(userspace_pid[cpu], (unsigned long *) &fpregs); + err = save_i387_registers(userspace_pid[cpu], + (unsigned long *) &fpregs); if (err) return err; @@ -214,7 +214,7 @@ static int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *c if (n > 0) return -EFAULT; - return restore_fp_registers(userspace_pid[cpu], + return restore_i387_registers(userspace_pid[cpu], (unsigned long *) &fpregs); } diff --git a/arch/x86/um/ptrace_64.c b/arch/x86/um/ptrace_64.c index a629694..14c9ab1 100644 --- a/arch/x86/um/ptrace_64.c +++ b/arch/x86/um/ptrace_64.c @@ -222,14 +222,13 @@ int is_syscall(unsigned long addr) static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) { int err, n, cpu = ((struct thread_info *) child->stack)->cpu; - long fpregs[HOST_FP_SIZE]; + struct user_i387_struct fpregs; - BUG_ON(sizeof(*buf) != sizeof(fpregs)); - err = save_fp_registers(userspace_pid[cpu], fpregs); + err = save_i387_registers(userspace_pid[cpu], &fpregs); if (err) return err; - n = copy_to_user(buf, fpregs, sizeof(fpregs)); + n = copy_to_user(buf, &fpregs, sizeof(fpregs)); if (n > 0) return -EFAULT; @@ -239,14 +238,13 @@ static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *c static int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) { int n, cpu = ((struct thread_info *) child->stack)->cpu; - long fpregs[HOST_FP_SIZE]; + struct user_i387_struct fpregs; - BUG_ON(sizeof(*buf) != sizeof(fpregs)); - n = copy_from_user(fpregs, buf, sizeof(fpregs)); + n = copy_from_user(&fpregs, buf, sizeof(fpregs)); if (n > 0) return -EFAULT; - return restore_fp_registers(userspace_pid[cpu], fpregs); + return restore_i387_registers(userspace_pid[cpu], &fpregs); } long subarch_ptrace(struct task_struct *child, long request, -- 2.7.2 |
From: Eli C. <eli...@gm...> - 2016-03-06 14:36:54
|
This patch extends save_fp_registers() and restore_fp_registers() to use PTRACE_GETREGSET and PTRACE_SETREGSET with the XSTATE note type, adding support for new processor state extensions. Now these functions expect *fp_regs to have the space of an _xstate struct. When the new ptrace requests are unavailable, it falls back to the old PTRACE_GETFPREGS and PTRACE_SETFPREGS methods, which have been renamed to save_i387_registers() and restore_i387_registers(). Signed-off-by: Eli Cooper <eli...@gm...> --- arch/um/include/shared/registers.h | 2 ++ arch/um/kernel/process.c | 2 +- arch/x86/um/os-Linux/registers.c | 49 +++++++++++++++++++++++++++++++++-- arch/x86/um/shared/sysdep/ptrace_64.h | 4 +-- 4 files changed, 51 insertions(+), 6 deletions(-) diff --git a/arch/um/include/shared/registers.h b/arch/um/include/shared/registers.h index f5b7635..a74449b 100644 --- a/arch/um/include/shared/registers.h +++ b/arch/um/include/shared/registers.h @@ -9,6 +9,8 @@ #include <sysdep/ptrace.h> #include <sysdep/archsetjmp.h> +extern int save_i387_registers(int pid, unsigned long *fp_regs); +extern int restore_i387_registers(int pid, unsigned long *fp_regs); 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); diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index 48af59a..d55a473 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -402,6 +402,6 @@ int elf_core_copy_fpregs(struct task_struct *t, elf_fpregset_t *fpu) { int cpu = current_thread_info()->cpu; - return save_fp_registers(userspace_pid[cpu], (unsigned long *) fpu); + return save_i387_registers(userspace_pid[cpu], (unsigned long *) fpu); } diff --git a/arch/x86/um/os-Linux/registers.c b/arch/x86/um/os-Linux/registers.c index 41bfe84..c7f12c9 100644 --- a/arch/x86/um/os-Linux/registers.c +++ b/arch/x86/um/os-Linux/registers.c @@ -11,21 +11,56 @@ #endif #include <longjmp.h> #include <sysdep/ptrace_user.h> +#include <sys/uio.h> +#include <asm/sigcontext.h> +#include <linux/elf.h> -int save_fp_registers(int pid, unsigned long *fp_regs) +int have_xstate_support; + +int save_i387_registers(int pid, unsigned long *fp_regs) { if (ptrace(PTRACE_GETFPREGS, pid, 0, fp_regs) < 0) return -errno; return 0; } -int restore_fp_registers(int pid, unsigned long *fp_regs) +int save_fp_registers(int pid, unsigned long *fp_regs) +{ + struct iovec iov; + + if (have_xstate_support) { + iov.iov_base = fp_regs; + iov.iov_len = sizeof(struct _xstate); + if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) < 0) + return -errno; + return 0; + } else { + return save_i387_registers(pid, fp_regs); + } +} + +int restore_i387_registers(int pid, unsigned long *fp_regs) { if (ptrace(PTRACE_SETFPREGS, pid, 0, fp_regs) < 0) return -errno; return 0; } +int restore_fp_registers(int pid, unsigned long *fp_regs) +{ + struct iovec iov; + + if (have_xstate_support) { + iov.iov_base = fp_regs; + iov.iov_len = sizeof(struct _xstate); + if (ptrace(PTRACE_SETREGSET, pid, NT_X86_XSTATE, &iov) < 0) + return -errno; + return 0; + } else { + return restore_i387_registers(pid, fp_regs); + } +} + #ifdef __i386__ int have_fpx_regs = 1; int save_fpx_registers(int pid, unsigned long *fp_regs) @@ -85,6 +120,16 @@ int put_fp_registers(int pid, unsigned long *regs) return restore_fp_registers(pid, regs); } +void arch_init_registers(int pid) +{ + struct _xstate fp_regs; + struct iovec iov; + + iov.iov_base = &fp_regs; + iov.iov_len = sizeof(struct _xstate); + if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) == 0) + have_xstate_support = 1; +} #endif unsigned long get_thread_reg(int reg, jmp_buf *buf) diff --git a/arch/x86/um/shared/sysdep/ptrace_64.h b/arch/x86/um/shared/sysdep/ptrace_64.h index 919789f..0dc223a 100644 --- a/arch/x86/um/shared/sysdep/ptrace_64.h +++ b/arch/x86/um/shared/sysdep/ptrace_64.h @@ -57,8 +57,6 @@ #define UPT_SYSCALL_ARG5(r) UPT_R8(r) #define UPT_SYSCALL_ARG6(r) UPT_R9(r) -static inline void arch_init_registers(int pid) -{ -} +extern void arch_init_registers(int pid); #endif -- 2.7.2 |
From: Eli C. <eli...@gm...> - 2016-03-06 14:36:52
|
Extends _fpstate to _xstate, in order to hold AVX/YMM registers. Due to increased frame size, compilers might emit some warnings. Signed-off-by: Eli Cooper <eli...@gm...> --- arch/x86/um/signal.c | 26 +++++++++++++------------- arch/x86/um/user-offsets.c | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/arch/x86/um/signal.c b/arch/x86/um/signal.c index 14fcd01..e66bb06 100644 --- a/arch/x86/um/signal.c +++ b/arch/x86/um/signal.c @@ -225,10 +225,10 @@ static int copy_sc_from_user(struct pt_regs *regs, } else #endif { - struct user_i387_struct fp; + struct _xstate fp; err = copy_from_user(&fp, (void *)sc.fpstate, - sizeof(struct user_i387_struct)); + sizeof(struct _xstate)); if (err) return 1; @@ -244,7 +244,7 @@ static int copy_sc_from_user(struct pt_regs *regs, } static int copy_sc_to_user(struct sigcontext __user *to, - struct _fpstate __user *to_fp, struct pt_regs *regs, + struct _xstate __user *to_fp, struct pt_regs *regs, unsigned long mask) { struct sigcontext sc; @@ -310,25 +310,25 @@ static int copy_sc_to_user(struct sigcontext __user *to, return 1; } - err = convert_fxsr_to_user(to_fp, &fpx); + err = convert_fxsr_to_user(&to_fp->fpstate, &fpx); if (err) return 1; - err |= __put_user(fpx.swd, &to_fp->status); - err |= __put_user(X86_FXSR_MAGIC, &to_fp->magic); + err |= __put_user(fpx.swd, &to_fp->fpstate.status); + err |= __put_user(X86_FXSR_MAGIC, &to_fp->fpstate.magic); if (err) return 1; - if (copy_to_user(&to_fp->_fxsr_env[0], &fpx, + if (copy_to_user(&to_fp->fpstate._fxsr_env[0], &fpx, sizeof(struct user_fxsr_struct))) return 1; } else #endif { - struct user_i387_struct fp; + struct _xstate fp; err = save_fp_registers(pid, (unsigned long *) &fp); - if (copy_to_user(to_fp, &fp, sizeof(struct user_i387_struct))) + if (copy_to_user(to_fp, &fp, sizeof(struct _xstate))) return 1; } @@ -337,7 +337,7 @@ static int copy_sc_to_user(struct sigcontext __user *to, #ifdef CONFIG_X86_32 static int copy_ucontext_to_user(struct ucontext __user *uc, - struct _fpstate __user *fp, sigset_t *set, + struct _xstate __user *fp, sigset_t *set, unsigned long sp) { int err = 0; @@ -353,7 +353,7 @@ struct sigframe char __user *pretcode; int sig; struct sigcontext sc; - struct _fpstate fpstate; + struct _xstate fpstate; unsigned long extramask[_NSIG_WORDS-1]; char retcode[8]; }; @@ -366,7 +366,7 @@ struct rt_sigframe void __user *puc; struct siginfo info; struct ucontext uc; - struct _fpstate fpstate; + struct _xstate fpstate; char retcode[8]; }; @@ -495,7 +495,7 @@ struct rt_sigframe char __user *pretcode; struct ucontext uc; struct siginfo info; - struct _fpstate fpstate; + struct _xstate fpstate; }; int setup_signal_stack_si(unsigned long stack_top, struct ksignal *ksig, diff --git a/arch/x86/um/user-offsets.c b/arch/x86/um/user-offsets.c index ce7e360..bab4362 100644 --- a/arch/x86/um/user-offsets.c +++ b/arch/x86/um/user-offsets.c @@ -52,7 +52,7 @@ void foo(void) DEFINE(HOST_GS, GS); DEFINE(HOST_ORIG_AX, ORIG_EAX); #else - DEFINE(HOST_FP_SIZE, sizeof(struct _fpstate) / sizeof(unsigned long)); + DEFINE(HOST_FP_SIZE, sizeof(struct _xstate) / sizeof(unsigned long)); DEFINE_LONGS(HOST_BX, RBX); DEFINE_LONGS(HOST_CX, RCX); DEFINE_LONGS(HOST_DI, RDI); -- 2.7.2 |
From: Eli C. <eli...@gm...> - 2016-03-06 14:36:52
|
This series adds support for the extended processor state (XSTATE) for x86_64 UML, especially the YMM registers used by AVX/AVX2 instructions. Modern userspace programs built with AVX can now run inside x86_64 UML without YMM registers getting corrupted. Eli Cooper (3): um: extend _fpstate to _xstate um: add extended processor state save/restore support um: fix ptrace PTRACE_GETFPREGS and PTRACE_SETFPREG support arch/um/include/shared/registers.h | 2 ++ arch/um/kernel/process.c | 2 +- arch/x86/um/os-Linux/registers.c | 49 +++++++++++++++++++++++++++++++++-- arch/x86/um/ptrace_32.c | 4 +-- arch/x86/um/ptrace_64.c | 14 +++++----- arch/x86/um/shared/sysdep/ptrace_64.h | 4 +-- arch/x86/um/signal.c | 26 +++++++++---------- arch/x86/um/user-offsets.c | 2 +- 8 files changed, 73 insertions(+), 30 deletions(-) -- 2.7.2 |