svn commit: r332454 - in head/sys: amd64/amd64 amd64/ia32 amd64/linux amd64/linux32 i386/i386
Konstantin Belousov
kib at FreeBSD.org
Thu Apr 12 20:43:40 UTC 2018
Author: kib
Date: Thu Apr 12 20:43:39 2018
New Revision: 332454
URL: https://svnweb.freebsd.org/changeset/base/332454
Log:
Fix PSL_T inheritance on exec for x86.
The miscellaneous x86 sysent->sv_setregs() implementations tried to
migrate PSL_T from the previous program to the new executed one, but
they evaluated regs->tf_eflags after the whole regs structure was
bzeroed. Make this functional by saving PSL_T value before zeroing.
Note that if the debugger is not attached, executing the first
instruction in the new program with PSL_T set results in SIGTRAP, and
since all intercepted signals are reset to default dispostion on
exec(2), this means that non-debugged process gets killed immediately
if PSL_T is inherited. In particular, since suid images drop
P_TRACED, attempt to set PSL_T for execution of such program would
kill the process.
Another issue with userspace PSL_T handling is that it is reset by
trap(). It is reasonable to clear PSL_T when entering SIGTRAP
handler, to allow the signal to be handled without recursion or
delivery of blocked fault. But it is not reasonable to return back to
the normal flow with PSL_T cleared. This is too late to change, I
think.
Discussed with: bde, Ali Mashtizadeh
Sponsored by: The FreeBSD Foundation
MFC after: 3 weeks
Differential revision: https://reviews.freebsd.org/D14995
Modified:
head/sys/amd64/amd64/machdep.c
head/sys/amd64/ia32/ia32_signal.c
head/sys/amd64/linux/linux_sysvec.c
head/sys/amd64/linux32/linux32_sysvec.c
head/sys/i386/i386/machdep.c
Modified: head/sys/amd64/amd64/machdep.c
==============================================================================
--- head/sys/amd64/amd64/machdep.c Thu Apr 12 20:27:57 2018 (r332453)
+++ head/sys/amd64/amd64/machdep.c Thu Apr 12 20:43:39 2018 (r332454)
@@ -581,9 +581,13 @@ freebsd4_sigreturn(struct thread *td, struct freebsd4_
void
exec_setregs(struct thread *td, struct image_params *imgp, u_long stack)
{
- struct trapframe *regs = td->td_frame;
- struct pcb *pcb = td->td_pcb;
+ struct trapframe *regs;
+ struct pcb *pcb;
+ register_t saved_rflags;
+ regs = td->td_frame;
+ pcb = td->td_pcb;
+
if (td->td_proc->p_md.md_ldt != NULL)
user_ldt_free(td);
@@ -593,11 +597,12 @@ exec_setregs(struct thread *td, struct image_params *i
clear_pcb_flags(pcb, PCB_32BIT);
pcb->pcb_initial_fpucw = __INITIAL_FPUCW__;
+ saved_rflags = regs->tf_rflags & PSL_T;
bzero((char *)regs, sizeof(struct trapframe));
regs->tf_rip = imgp->entry_addr;
regs->tf_rsp = ((stack - 8) & ~0xFul) + 8;
regs->tf_rdi = stack; /* argv */
- regs->tf_rflags = PSL_USER | (regs->tf_rflags & PSL_T);
+ regs->tf_rflags = PSL_USER | saved_rflags;
regs->tf_ss = _udatasel;
regs->tf_cs = _ucodesel;
regs->tf_ds = _udatasel;
Modified: head/sys/amd64/ia32/ia32_signal.c
==============================================================================
--- head/sys/amd64/ia32/ia32_signal.c Thu Apr 12 20:27:57 2018 (r332453)
+++ head/sys/amd64/ia32/ia32_signal.c Thu Apr 12 20:43:39 2018 (r332454)
@@ -936,9 +936,13 @@ freebsd32_sigreturn(td, uap)
void
ia32_setregs(struct thread *td, struct image_params *imgp, u_long stack)
{
- struct trapframe *regs = td->td_frame;
- struct pcb *pcb = td->td_pcb;
+ struct trapframe *regs;
+ struct pcb *pcb;
+ register_t saved_rflags;
+ regs = td->td_frame;
+ pcb = td->td_pcb;
+
if (td->td_proc->p_md.md_ldt != NULL)
user_ldt_free(td);
#ifdef COMPAT_43
@@ -949,10 +953,11 @@ ia32_setregs(struct thread *td, struct image_params *i
pcb->pcb_gsbase = 0;
pcb->pcb_initial_fpucw = __INITIAL_FPUCW_I386__;
+ saved_rflags = regs->tf_rflags & PSL_T;
bzero((char *)regs, sizeof(struct trapframe));
regs->tf_rip = imgp->entry_addr;
regs->tf_rsp = stack;
- regs->tf_rflags = PSL_USER | (regs->tf_rflags & PSL_T);
+ regs->tf_rflags = PSL_USER | saved_rflags;
regs->tf_ss = _udatasel;
regs->tf_cs = _ucode32sel;
regs->tf_rbx = imgp->ps_strings;
Modified: head/sys/amd64/linux/linux_sysvec.c
==============================================================================
--- head/sys/amd64/linux/linux_sysvec.c Thu Apr 12 20:27:57 2018 (r332453)
+++ head/sys/amd64/linux/linux_sysvec.c Thu Apr 12 20:43:39 2018 (r332454)
@@ -404,9 +404,13 @@ linux_copyout_strings(struct image_params *imgp)
static void
linux_exec_setregs(struct thread *td, struct image_params *imgp, u_long stack)
{
- struct trapframe *regs = td->td_frame;
- struct pcb *pcb = td->td_pcb;
+ struct trapframe *regs;
+ struct pcb *pcb;
+ register_t saved_rflags;
+ regs = td->td_frame;
+ pcb = td->td_pcb;
+
if (td->td_proc->p_md.md_ldt != NULL)
user_ldt_free(td);
@@ -416,10 +420,11 @@ linux_exec_setregs(struct thread *td, struct image_par
pcb->pcb_initial_fpucw = __LINUX_NPXCW__;
set_pcb_flags(pcb, PCB_FULL_IRET);
+ saved_rflags = regs->tf_rflags & PSL_T;
bzero((char *)regs, sizeof(struct trapframe));
regs->tf_rip = imgp->entry_addr;
regs->tf_rsp = stack;
- regs->tf_rflags = PSL_USER | (regs->tf_rflags & PSL_T);
+ regs->tf_rflags = PSL_USER | saved_rflags;
regs->tf_ss = _udatasel;
regs->tf_cs = _ucodesel;
regs->tf_ds = _udatasel;
Modified: head/sys/amd64/linux32/linux32_sysvec.c
==============================================================================
--- head/sys/amd64/linux32/linux32_sysvec.c Thu Apr 12 20:27:57 2018 (r332453)
+++ head/sys/amd64/linux32/linux32_sysvec.c Thu Apr 12 20:43:39 2018 (r332454)
@@ -719,7 +719,11 @@ linux_exec_setregs(struct thread *td, struct image_par
{
struct trapframe *regs = td->td_frame;
struct pcb *pcb = td->td_pcb;
+ register_t saved_rflags;
+ regs = td->td_frame;
+ pcb = td->td_pcb;
+
if (td->td_proc->p_md.md_ldt != NULL)
user_ldt_free(td);
@@ -731,10 +735,11 @@ linux_exec_setregs(struct thread *td, struct image_par
critical_exit();
pcb->pcb_initial_fpucw = __LINUX_NPXCW__;
+ saved_rflags = regs->tf_rflags & PSL_T;
bzero((char *)regs, sizeof(struct trapframe));
regs->tf_rip = imgp->entry_addr;
regs->tf_rsp = stack;
- regs->tf_rflags = PSL_USER | (regs->tf_rflags & PSL_T);
+ regs->tf_rflags = PSL_USER | saved_rflags;
regs->tf_gs = _ugssel;
regs->tf_fs = _ufssel;
regs->tf_es = _udatasel;
Modified: head/sys/i386/i386/machdep.c
==============================================================================
--- head/sys/i386/i386/machdep.c Thu Apr 12 20:27:57 2018 (r332453)
+++ head/sys/i386/i386/machdep.c Thu Apr 12 20:43:39 2018 (r332454)
@@ -1104,9 +1104,13 @@ sys_sigreturn(td, uap)
void
exec_setregs(struct thread *td, struct image_params *imgp, u_long stack)
{
- struct trapframe *regs = td->td_frame;
- struct pcb *pcb = td->td_pcb;
+ struct trapframe *regs;
+ struct pcb *pcb;
+ register_t saved_eflags;
+ regs = td->td_frame;
+ pcb = td->td_pcb;
+
/* Reset pc->pcb_gs and %gs before possibly invalidating it. */
pcb->pcb_gs = _udatasel;
load_gs(_udatasel);
@@ -1127,10 +1131,11 @@ exec_setregs(struct thread *td, struct image_params *i
set_gsbase(td, 0);
/* Make sure edx is 0x0 on entry. Linux binaries depend on it. */
+ saved_eflags = regs->tf_eflags & PSL_T;
bzero((char *)regs, sizeof(struct trapframe));
regs->tf_eip = imgp->entry_addr;
regs->tf_esp = stack;
- regs->tf_eflags = PSL_USER | (regs->tf_eflags & PSL_T);
+ regs->tf_eflags = PSL_USER | saved_eflags;
regs->tf_ss = _udatasel;
regs->tf_ds = _udatasel;
regs->tf_es = _udatasel;
More information about the svn-src-all
mailing list