mirror of
https://git.hardenedbsd.org/hardenedbsd/HardenedBSD.git
synced 2024-11-26 10:53:39 +01:00
Stop single stepping in signal handers on arm64
We should clear the single step flag when entering a signal hander and set it when returning. This fixes the ptrace__PT_STEP_with_signal test. While here add support for userspace to set the single step bit as on x86. This can be used by userspace for self tracing. Reviewed by: kib Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D34170
This commit is contained in:
parent
4073917408
commit
31cf95cec7
@ -97,7 +97,6 @@ set_regs(struct thread *td, struct reg *regs)
|
||||
frame = td->td_frame;
|
||||
frame->tf_sp = regs->sp;
|
||||
frame->tf_lr = regs->lr;
|
||||
frame->tf_spsr &= ~PSR_FLAGS;
|
||||
|
||||
memcpy(frame->tf_x, regs->x, sizeof(frame->tf_x));
|
||||
|
||||
@ -109,12 +108,27 @@ set_regs(struct thread *td, struct reg *regs)
|
||||
* it put it.
|
||||
*/
|
||||
frame->tf_elr = regs->x[15];
|
||||
frame->tf_spsr |= regs->x[16] & PSR_FLAGS;
|
||||
frame->tf_spsr &= ~PSR_SETTABLE_32;
|
||||
frame->tf_spsr |= regs->x[16] & PSR_SETTABLE_32;
|
||||
/* Don't allow userspace to ask to continue single stepping.
|
||||
* The SPSR.SS field doesn't exist when the EL1 is AArch32.
|
||||
* As the SPSR.DIT field has moved in its place don't
|
||||
* allow userspace to set the SPSR.SS field.
|
||||
*/
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
frame->tf_elr = regs->elr;
|
||||
frame->tf_spsr |= regs->spsr & PSR_FLAGS;
|
||||
frame->tf_spsr &= ~PSR_SETTABLE_64;
|
||||
frame->tf_spsr |= regs->spsr & PSR_SETTABLE_64;
|
||||
/* Enable single stepping if userspace asked fot it */
|
||||
if ((frame->tf_spsr & PSR_SS) != 0) {
|
||||
td->td_pcb->pcb_flags |= PCB_SINGLE_STEP;
|
||||
|
||||
WRITE_SPECIALREG(mdscr_el1,
|
||||
READ_SPECIALREG(mdscr_el1) | MDSCR_SS);
|
||||
isb();
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
@ -333,8 +347,8 @@ set_regs32(struct thread *td, struct reg32 *regs)
|
||||
tf->tf_x[13] = regs->r_sp;
|
||||
tf->tf_x[14] = regs->r_lr;
|
||||
tf->tf_elr = regs->r_pc;
|
||||
tf->tf_spsr &= ~PSR_FLAGS;
|
||||
tf->tf_spsr |= regs->r_cpsr & PSR_FLAGS;
|
||||
tf->tf_spsr &= ~PSR_SETTABLE_32;
|
||||
tf->tf_spsr |= regs->r_cpsr & PSR_SETTABLE_32;
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -450,6 +464,13 @@ set_mcontext(struct thread *td, mcontext_t *mcp)
|
||||
tf->tf_lr = mcp->mc_gpregs.gp_lr;
|
||||
tf->tf_elr = mcp->mc_gpregs.gp_elr;
|
||||
tf->tf_spsr = mcp->mc_gpregs.gp_spsr;
|
||||
if ((tf->tf_spsr & PSR_SS) != 0) {
|
||||
td->td_pcb->pcb_flags |= PCB_SINGLE_STEP;
|
||||
|
||||
WRITE_SPECIALREG(mdscr_el1,
|
||||
READ_SPECIALREG(mdscr_el1) | MDSCR_SS);
|
||||
isb();
|
||||
}
|
||||
set_fpcontext(td, mcp);
|
||||
|
||||
return (0);
|
||||
@ -604,6 +625,14 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
|
||||
tf->tf_sp = (register_t)fp;
|
||||
tf->tf_lr = (register_t)p->p_sysent->sv_sigcode_base;
|
||||
|
||||
/* Clear the single step flag while in the signal handler */
|
||||
if ((td->td_pcb->pcb_flags & PCB_SINGLE_STEP) != 0) {
|
||||
td->td_pcb->pcb_flags &= ~PCB_SINGLE_STEP;
|
||||
WRITE_SPECIALREG(mdscr_el1,
|
||||
READ_SPECIALREG(mdscr_el1) & ~MDSCR_SS);
|
||||
isb();
|
||||
}
|
||||
|
||||
CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_elr,
|
||||
tf->tf_sp);
|
||||
|
||||
|
@ -198,14 +198,34 @@ set_mcontext32(struct thread *td, mcontext32_t *mcp)
|
||||
{
|
||||
struct trapframe *tf;
|
||||
mcontext32_vfp_t mc_vfp;
|
||||
uint32_t spsr;
|
||||
int i;
|
||||
|
||||
tf = td->td_frame;
|
||||
|
||||
spsr = mcp->mc_gregset[16];
|
||||
/*
|
||||
* There is no PSR_SS in the 32-bit kernel so ignore it if it's set
|
||||
* as we will set it later if needed.
|
||||
*/
|
||||
if ((spsr & ~(PSR_SETTABLE_32 | PSR_SS)) !=
|
||||
(tf->tf_spsr & ~(PSR_SETTABLE_32 | PSR_SS)))
|
||||
return (EINVAL);
|
||||
|
||||
spsr &= PSR_SETTABLE_32;
|
||||
spsr |= tf->tf_spsr & ~PSR_SETTABLE_32;
|
||||
|
||||
if ((td->td_dbgflags & TDB_STEP) != 0) {
|
||||
spsr |= PSR_SS;
|
||||
td->td_pcb->pcb_flags |= PCB_SINGLE_STEP;
|
||||
WRITE_SPECIALREG(mdscr_el1,
|
||||
READ_SPECIALREG(mdscr_el1) | MDSCR_SS);
|
||||
}
|
||||
|
||||
for (i = 0; i < 15; i++)
|
||||
tf->tf_x[i] = mcp->mc_gregset[i];
|
||||
tf->tf_elr = mcp->mc_gregset[15];
|
||||
tf->tf_spsr = mcp->mc_gregset[16];
|
||||
tf->tf_spsr = spsr;
|
||||
#ifdef VFP
|
||||
if (mcp->mc_vfp_size == sizeof(mc_vfp) && mcp->mc_vfp_ptr != 0) {
|
||||
if (copyin((void *)(uintptr_t)mcp->mc_vfp_ptr, &mc_vfp,
|
||||
@ -404,6 +424,14 @@ freebsd32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
|
||||
else
|
||||
tf->tf_spsr &= ~PSR_T;
|
||||
|
||||
/* Clear the single step flag while in the signal handler */
|
||||
if ((td->td_pcb->pcb_flags & PCB_SINGLE_STEP) != 0) {
|
||||
td->td_pcb->pcb_flags &= ~PCB_SINGLE_STEP;
|
||||
WRITE_SPECIALREG(mdscr_el1,
|
||||
READ_SPECIALREG(mdscr_el1) & ~MDSCR_SS);
|
||||
isb();
|
||||
}
|
||||
|
||||
CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_x[14],
|
||||
tf->tf_x[13]);
|
||||
|
||||
|
@ -59,18 +59,22 @@ ptrace_set_pc(struct thread *td, u_long addr)
|
||||
int
|
||||
ptrace_single_step(struct thread *td)
|
||||
{
|
||||
|
||||
PROC_LOCK_ASSERT(td->td_proc, MA_OWNED);
|
||||
if ((td->td_frame->tf_spsr & PSR_SS) == 0) {
|
||||
td->td_frame->tf_spsr |= PSR_SS;
|
||||
td->td_pcb->pcb_flags |= PCB_SINGLE_STEP;
|
||||
td->td_dbgflags |= TDB_STEP;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
ptrace_clear_single_step(struct thread *td)
|
||||
{
|
||||
|
||||
PROC_LOCK_ASSERT(td->td_proc, MA_OWNED);
|
||||
td->td_frame->tf_spsr &= ~PSR_SS;
|
||||
td->td_pcb->pcb_flags &= ~PCB_SINGLE_STEP;
|
||||
td->td_dbgflags &= ~TDB_STEP;
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -620,10 +620,14 @@ do_el0_sync(struct thread *td, struct trapframe *frame)
|
||||
userret(td, frame);
|
||||
break;
|
||||
case EXCP_SOFTSTP_EL0:
|
||||
PROC_LOCK(td->td_proc);
|
||||
if ((td->td_dbgflags & TDB_STEP) != 0) {
|
||||
td->td_frame->tf_spsr &= ~PSR_SS;
|
||||
td->td_pcb->pcb_flags &= ~PCB_SINGLE_STEP;
|
||||
WRITE_SPECIALREG(mdscr_el1,
|
||||
READ_SPECIALREG(mdscr_el1) & ~MDSCR_SS);
|
||||
}
|
||||
PROC_UNLOCK(td->td_proc);
|
||||
call_trapsignal(td, SIGTRAP, TRAP_TRACE,
|
||||
(void *)frame->tf_elr, exception);
|
||||
userret(td, frame);
|
||||
|
@ -1315,6 +1315,9 @@
|
||||
#define PSR_Z 0x40000000
|
||||
#define PSR_N 0x80000000
|
||||
#define PSR_FLAGS 0xf0000000
|
||||
/* PSR fields that can be set from 32-bit and 64-bit processes */
|
||||
#define PSR_SETTABLE_32 PSR_FLAGS
|
||||
#define PSR_SETTABLE_64 (PSR_FLAGS | PSR_SS)
|
||||
|
||||
/* TCR_EL1 - Translation Control Register */
|
||||
/* Bits 63:59 are reserved */
|
||||
|
@ -10,6 +10,20 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(__aarch64__)
|
||||
#include <machine/armreg.h>
|
||||
#define SET_TRACE_FLAG(ucp) (ucp)->uc_mcontext.mc_gpregs.gp_spsr |= PSR_SS
|
||||
#define CLR_TRACE_FLAG(ucp) (ucp)->uc_mcontext.mc_gpregs.gp_spsr &= ~PSR_SS
|
||||
#elif defined(__amd64__)
|
||||
#include <machine/psl.h>
|
||||
#define SET_TRACE_FLAG(ucp) (ucp)->uc_mcontext.mc_rflags |= PSL_T
|
||||
#define CLR_TRACE_FLAG(ucp) (ucp)->uc_mcontext.mc_rflags &= ~PSL_T
|
||||
#elif defined(__i386__)
|
||||
#include <machine/psl.h>
|
||||
#define SET_TRACE_FLAG(ucp) (ucp)->uc_mcontext.mc_eflags |= PSL_T
|
||||
#define CLR_TRACE_FLAG(ucp) (ucp)->uc_mcontext.mc_eflags &= ~PSL_T
|
||||
#endif
|
||||
|
||||
static volatile sig_atomic_t signal_fired = 0;
|
||||
|
||||
static void
|
||||
@ -62,6 +76,55 @@ ATF_TC_BODY(signal_test, tc)
|
||||
ATF_CHECK(signal_fired == 3);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check setting the machine dependent single step flag works when supported.
|
||||
*/
|
||||
#ifdef SET_TRACE_FLAG
|
||||
static volatile sig_atomic_t trap_signal_fired = 0;
|
||||
|
||||
static void
|
||||
trap_sig_handler(int signo, siginfo_t *info __unused, void *_ucp)
|
||||
{
|
||||
ucontext_t *ucp = _ucp;
|
||||
|
||||
if (trap_signal_fired < 9) {
|
||||
SET_TRACE_FLAG(ucp);
|
||||
} else {
|
||||
CLR_TRACE_FLAG(ucp);
|
||||
}
|
||||
trap_signal_fired++;
|
||||
}
|
||||
|
||||
ATF_TC(trap_signal_test);
|
||||
|
||||
ATF_TC_HEAD(trap_signal_test, tc)
|
||||
{
|
||||
|
||||
atf_tc_set_md_var(tc, "descr",
|
||||
"Testing signal handler setting the MD single step flag");
|
||||
}
|
||||
|
||||
ATF_TC_BODY(trap_signal_test, tc)
|
||||
{
|
||||
/*
|
||||
* Setup the signal handlers
|
||||
*/
|
||||
struct sigaction sa = {
|
||||
.sa_sigaction = trap_sig_handler,
|
||||
.sa_flags = SA_SIGINFO,
|
||||
};
|
||||
ATF_REQUIRE(sigemptyset(&sa.sa_mask) == 0);
|
||||
ATF_REQUIRE(sigaction(SIGTRAP, &sa, NULL) == 0);
|
||||
|
||||
/*
|
||||
* Fire SIGTRAP
|
||||
*/
|
||||
ATF_CHECK(trap_signal_fired == 0);
|
||||
ATF_REQUIRE(raise(SIGTRAP) == 0);
|
||||
ATF_CHECK(trap_signal_fired == 10);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Special tests for 32-bit arm. We can call thumb code (really just t32) from
|
||||
* normal (a32) mode and vice versa. Likewise, signals can interrupt a T32
|
||||
@ -150,6 +213,9 @@ ATF_TP_ADD_TCS(tp)
|
||||
{
|
||||
|
||||
ATF_TP_ADD_TC(tp, signal_test);
|
||||
#ifdef SET_TRACE_FLAG
|
||||
ATF_TP_ADD_TC(tp, trap_signal_test);
|
||||
#endif
|
||||
#ifdef __arm__
|
||||
ATF_TP_ADD_TC(tp, signal_test_T32_to_A32);
|
||||
ATF_TP_ADD_TC(tp, signal_test_A32_to_T32);
|
||||
|
Loading…
Reference in New Issue
Block a user