Ensure we check the program state set in the trap frame on arm and arm64.
This value may be set by userspace so we need to check it before using it. If this is not done correctly on exception return the kernel may continue in kernel mode with all registers set to a userspace controlled value. Fix this by moving the check into set_mcontext, and also add the missing sanitisation from the arm64 set_regs. Discussed with: security-officer@ MFC after: 3 days Sponsored by: DARPA, AFRL
This commit is contained in:
parent
b452493a3d
commit
521018d379
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=326137
@ -518,6 +518,16 @@ set_mcontext(struct thread *td, mcontext_t *mcp)
|
||||
mcontext_vfp_t mc_vfp, *vfp;
|
||||
struct trapframe *tf = td->td_frame;
|
||||
const __greg_t *gr = mcp->__gregs;
|
||||
int spsr;
|
||||
|
||||
/*
|
||||
* Make sure the processor mode has not been tampered with and
|
||||
* interrupts have not been disabled.
|
||||
*/
|
||||
spsr = gr[_REG_CPSR];
|
||||
if ((spsr & PSR_MODE) != PSR_USR32_MODE ||
|
||||
(spsr & (PSR_I | PSR_F)) != 0)
|
||||
return (EINVAL);
|
||||
|
||||
#ifdef WITNESS
|
||||
if (mcp->mc_vfp_size != 0 && mcp->mc_vfp_size != sizeof(mc_vfp)) {
|
||||
@ -677,22 +687,16 @@ sys_sigreturn(td, uap)
|
||||
} */ *uap;
|
||||
{
|
||||
ucontext_t uc;
|
||||
int spsr;
|
||||
int error;
|
||||
|
||||
if (uap == NULL)
|
||||
return (EFAULT);
|
||||
if (copyin(uap->sigcntxp, &uc, sizeof(uc)))
|
||||
return (EFAULT);
|
||||
/*
|
||||
* Make sure the processor mode has not been tampered with and
|
||||
* interrupts have not been disabled.
|
||||
*/
|
||||
spsr = uc.uc_mcontext.__gregs[_REG_CPSR];
|
||||
if ((spsr & PSR_MODE) != PSR_USR32_MODE ||
|
||||
(spsr & (PSR_I | PSR_F)) != 0)
|
||||
return (EINVAL);
|
||||
/* Restore register context. */
|
||||
set_mcontext(td, &uc.uc_mcontext);
|
||||
error = set_mcontext(td, &uc.uc_mcontext);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
/* Restore signal mask. */
|
||||
kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0);
|
||||
|
@ -211,7 +211,8 @@ set_regs(struct thread *td, struct reg *regs)
|
||||
frame->tf_sp = regs->sp;
|
||||
frame->tf_lr = regs->lr;
|
||||
frame->tf_elr = regs->elr;
|
||||
frame->tf_spsr = regs->spsr;
|
||||
frame->tf_spsr &= ~PSR_FLAGS;
|
||||
frame->tf_spsr |= regs->spsr & PSR_FLAGS;
|
||||
|
||||
memcpy(frame->tf_x, regs->x, sizeof(frame->tf_x));
|
||||
|
||||
@ -354,6 +355,12 @@ int
|
||||
set_mcontext(struct thread *td, mcontext_t *mcp)
|
||||
{
|
||||
struct trapframe *tf = td->td_frame;
|
||||
uint32_t spsr;
|
||||
|
||||
spsr = mcp->mc_gpregs.gp_spsr;
|
||||
if ((spsr & PSR_M_MASK) != PSR_M_EL0t ||
|
||||
(spsr & (PSR_F | PSR_I | PSR_A | PSR_D)) != 0)
|
||||
return (EINVAL);
|
||||
|
||||
memcpy(tf->tf_x, mcp->mc_gpregs.gp_x, sizeof(tf->tf_x));
|
||||
|
||||
@ -530,19 +537,16 @@ int
|
||||
sys_sigreturn(struct thread *td, struct sigreturn_args *uap)
|
||||
{
|
||||
ucontext_t uc;
|
||||
uint32_t spsr;
|
||||
int error;
|
||||
|
||||
if (uap == NULL)
|
||||
return (EFAULT);
|
||||
if (copyin(uap->sigcntxp, &uc, sizeof(uc)))
|
||||
return (EFAULT);
|
||||
|
||||
spsr = uc.uc_mcontext.mc_gpregs.gp_spsr;
|
||||
if ((spsr & PSR_M_MASK) != PSR_M_EL0t ||
|
||||
(spsr & (PSR_F | PSR_I | PSR_A | PSR_D)) != 0)
|
||||
return (EINVAL);
|
||||
|
||||
set_mcontext(td, &uc.uc_mcontext);
|
||||
error = set_mcontext(td, &uc.uc_mcontext);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
set_fpcontext(td, &uc.uc_mcontext);
|
||||
|
||||
/* Restore signal mask. */
|
||||
|
@ -572,6 +572,7 @@
|
||||
#define PSR_C 0x20000000
|
||||
#define PSR_Z 0x40000000
|
||||
#define PSR_N 0x80000000
|
||||
#define PSR_FLAGS 0xf0000000
|
||||
|
||||
/* TCR_EL1 - Translation Control Register */
|
||||
#define TCR_ASID_16 (1 << 36)
|
||||
|
Loading…
Reference in New Issue
Block a user