arch/ARCH_KERNEL_STACK: Fix signal handling with kernel stack
There were two issues with signal handling: - With a kernel stack the "info" parameter was passed from kernel memory. This is fixed by making a stack frame to the user stack and copying it there. - If the signal handler uses a system call, the kernel stack was completely and unconditionally destroyed, resulting in a crash in the user application There is also no need to check ustkptr, it is always NULL. Why ? Because signal delivery is deferred when a system call is being executed.
This commit is contained in:
parent
37b8748f17
commit
686b990a85
@ -438,11 +438,31 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
|
||||
if (rtcb->xcp.kstack != NULL)
|
||||
{
|
||||
DEBUGASSERT(rtcb->xcp.kstkptr == NULL &&
|
||||
rtcb->xcp.ustkptr != NULL);
|
||||
uint32_t usp;
|
||||
|
||||
DEBUGASSERT(rtcb->xcp.kstkptr == NULL);
|
||||
|
||||
/* Copy "info" into user stack */
|
||||
|
||||
if (rtcb->xcp.sigdeliver)
|
||||
{
|
||||
usp = rtcb->xcp.saved_regs[REG_SP];
|
||||
}
|
||||
else
|
||||
{
|
||||
usp = rtcb->xcp.regs[REG_SP];
|
||||
}
|
||||
|
||||
/* Create a frame for info and copy the kernel info */
|
||||
|
||||
usp = usp - sizeof(siginfo_t);
|
||||
memcpy((void *)usp, (void *)regs[REG_R2], sizeof(siginfo_t));
|
||||
|
||||
/* Now set the updated SP and user copy of "info" to R2 */
|
||||
|
||||
rtcb->xcp.kstkptr = (uint32_t *)regs[REG_SP];
|
||||
regs[REG_SP] = (uint32_t)rtcb->xcp.ustkptr;
|
||||
regs[REG_SP] = usp;
|
||||
regs[REG_R2] = usp;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -480,8 +500,7 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
|
||||
if (rtcb->xcp.kstack != NULL)
|
||||
{
|
||||
DEBUGASSERT(rtcb->xcp.kstkptr != NULL &&
|
||||
(uint32_t)rtcb->xcp.ustkptr == regs[REG_SP]);
|
||||
DEBUGASSERT(rtcb->xcp.kstkptr != NULL);
|
||||
|
||||
regs[REG_SP] = (uint32_t)rtcb->xcp.kstkptr;
|
||||
rtcb->xcp.kstkptr = NULL;
|
||||
@ -540,8 +559,15 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
if (index == 0 && rtcb->xcp.kstack != NULL)
|
||||
{
|
||||
rtcb->xcp.ustkptr = (uint32_t *)regs[REG_SP];
|
||||
regs[REG_SP] = (uint32_t)rtcb->xcp.kstack +
|
||||
if (rtcb->xcp.kstkptr != NULL)
|
||||
{
|
||||
regs[REG_SP] = (uint32_t)rtcb->xcp.kstkptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
regs[REG_SP] = (uint32_t)rtcb->xcp.kstack +
|
||||
ARCH_KERNEL_STACKSIZE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -434,11 +434,31 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
|
||||
if (rtcb->xcp.kstack != NULL)
|
||||
{
|
||||
DEBUGASSERT(rtcb->xcp.kstkptr == NULL &&
|
||||
rtcb->xcp.ustkptr != NULL);
|
||||
uint32_t usp;
|
||||
|
||||
DEBUGASSERT(rtcb->xcp.kstkptr == NULL);
|
||||
|
||||
/* Copy "info" into user stack */
|
||||
|
||||
if (rtcb->xcp.sigdeliver)
|
||||
{
|
||||
usp = rtcb->xcp.saved_regs[REG_SP];
|
||||
}
|
||||
else
|
||||
{
|
||||
usp = rtcb->xcp.regs[REG_SP];
|
||||
}
|
||||
|
||||
/* Create a frame for info and copy the kernel info */
|
||||
|
||||
usp = usp - sizeof(siginfo_t);
|
||||
memcpy((void *)usp, (void *)regs[REG_R2], sizeof(siginfo_t));
|
||||
|
||||
/* Now set the updated SP and user copy of "info" to R2 */
|
||||
|
||||
rtcb->xcp.kstkptr = (uint32_t *)regs[REG_SP];
|
||||
regs[REG_SP] = (uint32_t)rtcb->xcp.ustkptr;
|
||||
regs[REG_SP] = usp;
|
||||
regs[REG_R2] = usp;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -476,8 +496,7 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
|
||||
if (rtcb->xcp.kstack != NULL)
|
||||
{
|
||||
DEBUGASSERT(rtcb->xcp.kstkptr != NULL &&
|
||||
(uint32_t)rtcb->xcp.ustkptr == regs[REG_SP]);
|
||||
DEBUGASSERT(rtcb->xcp.kstkptr != NULL);
|
||||
|
||||
regs[REG_SP] = (uint32_t)rtcb->xcp.kstkptr;
|
||||
rtcb->xcp.kstkptr = NULL;
|
||||
@ -536,8 +555,15 @@ uint32_t *arm_syscall(uint32_t *regs)
|
||||
if (index == 0 && rtcb->xcp.kstack != NULL)
|
||||
{
|
||||
rtcb->xcp.ustkptr = (uint32_t *)regs[REG_SP];
|
||||
regs[REG_SP] = (uint32_t)rtcb->xcp.kstack +
|
||||
ARCH_KERNEL_STACKSIZE;
|
||||
if (rtcb->xcp.kstkptr != NULL)
|
||||
{
|
||||
regs[REG_SP] = (uint32_t)rtcb->xcp.kstkptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
regs[REG_SP] = (uint32_t)rtcb->xcp.kstack +
|
||||
ARCH_KERNEL_STACKSIZE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -297,7 +297,7 @@ int arm64_syscall(uint64_t *regs)
|
||||
|
||||
if (index == 0 && rtcb->xcp.ustkptr != NULL)
|
||||
{
|
||||
regs[REG_SP] = (uint32_t)rtcb->xcp.ustkptr;
|
||||
regs[REG_SP] = (uint64_t)rtcb->xcp.ustkptr;
|
||||
rtcb->xcp.ustkptr = NULL;
|
||||
}
|
||||
#endif
|
||||
@ -413,7 +413,7 @@ int arm64_syscall(uint64_t *regs)
|
||||
* unprivileged mode.
|
||||
*/
|
||||
|
||||
regs[REG_PC] = (uint32_t)ARCH_DATA_RESERVE->ar_sigtramp;
|
||||
regs[REG_PC] = (uint64_t)ARCH_DATA_RESERVE->ar_sigtramp;
|
||||
cpsr = regs[REG_CPSR] & ~PSR_MODE_MASK;
|
||||
regs[REG_CPSR] = cpsr | PSR_MODE_USR;
|
||||
|
||||
@ -436,11 +436,31 @@ int arm64_syscall(uint64_t *regs)
|
||||
|
||||
if (rtcb->xcp.kstack != NULL)
|
||||
{
|
||||
DEBUGASSERT(rtcb->xcp.kstkptr == NULL &&
|
||||
rtcb->xcp.ustkptr != NULL);
|
||||
uint64_t usp;
|
||||
|
||||
rtcb->xcp.kstkptr = (uint32_t *)regs[REG_SP];
|
||||
regs[REG_SP] = (uint32_t)rtcb->xcp.ustkptr;
|
||||
DEBUGASSERT(rtcb->xcp.kstkptr == NULL);
|
||||
|
||||
/* Copy "info" into user stack */
|
||||
|
||||
if (rtcb->xcp.sigdeliver)
|
||||
{
|
||||
usp = rtcb->xcp.saved_regs[REG_SP];
|
||||
}
|
||||
else
|
||||
{
|
||||
usp = rtcb->xcp.regs[REG_SP];
|
||||
}
|
||||
|
||||
/* Create a frame for info and copy the kernel info */
|
||||
|
||||
usp = usp - sizeof(siginfo_t);
|
||||
memcpy((void *)usp, (void *)regs[REG_R2], sizeof(siginfo_t));
|
||||
|
||||
/* Now set the updated SP and user copy of "info" to R2 */
|
||||
|
||||
rtcb->xcp.kstkptr = (uint64_t *)regs[REG_SP];
|
||||
regs[REG_SP] = usp;
|
||||
regs[REG_R2] = usp;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -478,10 +498,9 @@ int arm64_syscall(uint64_t *regs)
|
||||
|
||||
if (rtcb->xcp.kstack != NULL)
|
||||
{
|
||||
DEBUGASSERT(rtcb->xcp.kstkptr != NULL &&
|
||||
(uint32_t)rtcb->xcp.ustkptr == regs[REG_SP]);
|
||||
DEBUGASSERT(rtcb->xcp.kstkptr != NULL);
|
||||
|
||||
regs[REG_SP] = (uint32_t)rtcb->xcp.kstkptr;
|
||||
regs[REG_SP] = (uint64_t)rtcb->xcp.kstkptr;
|
||||
rtcb->xcp.kstkptr = NULL;
|
||||
}
|
||||
#endif
|
||||
@ -517,7 +536,7 @@ int arm64_syscall(uint64_t *regs)
|
||||
rtcb->xcp.syscall[index].cpsr = regs[REG_CPSR];
|
||||
#endif
|
||||
|
||||
regs[REG_PC] = (uint32_t)dispatch_syscall;
|
||||
regs[REG_PC] = (uint64_t)dispatch_syscall;
|
||||
#ifdef CONFIG_BUILD_KERNEL
|
||||
cpsr = regs[REG_CPSR] & ~PSR_MODE_MASK;
|
||||
regs[REG_CPSR] = cpsr | PSR_MODE_SVC;
|
||||
@ -537,9 +556,16 @@ int arm64_syscall(uint64_t *regs)
|
||||
|
||||
if (index == 0 && rtcb->xcp.kstack != NULL)
|
||||
{
|
||||
rtcb->xcp.ustkptr = (uint32_t *)regs[REG_SP];
|
||||
regs[REG_SP] = (uint32_t)rtcb->xcp.kstack +
|
||||
rtcb->xcp.ustkptr = (uint64_t *)regs[REG_SP];
|
||||
if (rtcb->xcp.kstkptr != NULL)
|
||||
{
|
||||
regs[REG_SP] = (uint64_t)rtcb->xcp.kstkptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
regs[REG_SP] = (uint64_t)rtcb->xcp.kstack +
|
||||
ARCH_KERNEL_STACKSIZE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -366,8 +366,7 @@ int riscv_swint(int irq, void *context, void *arg)
|
||||
#if defined (CONFIG_BUILD_PROTECTED)
|
||||
regs[REG_EPC] = (uintptr_t)USERSPACE->signal_handler;
|
||||
#else
|
||||
regs[REG_EPC] =
|
||||
(uintptr_t)ARCH_DATA_RESERVE->ar_sigtramp;
|
||||
regs[REG_EPC] = (uintptr_t)ARCH_DATA_RESERVE->ar_sigtramp;
|
||||
#endif
|
||||
regs[REG_INT_CTX] &= ~STATUS_PPP; /* User mode */
|
||||
|
||||
@ -390,11 +389,31 @@ int riscv_swint(int irq, void *context, void *arg)
|
||||
|
||||
if (rtcb->xcp.kstack != NULL)
|
||||
{
|
||||
DEBUGASSERT(rtcb->xcp.kstkptr == NULL &&
|
||||
rtcb->xcp.ustkptr != NULL);
|
||||
uintptr_t usp;
|
||||
|
||||
DEBUGASSERT(rtcb->xcp.kstkptr == NULL);
|
||||
|
||||
/* Copy "info" into user stack */
|
||||
|
||||
if (rtcb->xcp.sigdeliver)
|
||||
{
|
||||
usp = rtcb->xcp.saved_regs[REG_SP];
|
||||
}
|
||||
else
|
||||
{
|
||||
usp = rtcb->xcp.regs[REG_SP];
|
||||
}
|
||||
|
||||
/* Create a frame for info and copy the kernel info */
|
||||
|
||||
usp = usp - sizeof(siginfo_t);
|
||||
memcpy((void *)usp, (void *)regs[REG_A2], sizeof(siginfo_t));
|
||||
|
||||
/* Now set the updated SP and user copy of "info" to A2 */
|
||||
|
||||
rtcb->xcp.kstkptr = (uintptr_t *)regs[REG_SP];
|
||||
regs[REG_SP] = (uintptr_t)rtcb->xcp.ustkptr;
|
||||
regs[REG_SP] = usp;
|
||||
regs[REG_A2] = usp;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -431,8 +450,7 @@ int riscv_swint(int irq, void *context, void *arg)
|
||||
|
||||
if (rtcb->xcp.kstack != NULL)
|
||||
{
|
||||
DEBUGASSERT(rtcb->xcp.kstkptr != NULL &&
|
||||
(uintptr_t)rtcb->xcp.ustkptr == regs[REG_SP]);
|
||||
DEBUGASSERT(rtcb->xcp.kstkptr != NULL);
|
||||
|
||||
regs[REG_SP] = (uintptr_t)rtcb->xcp.kstkptr;
|
||||
rtcb->xcp.kstkptr = NULL;
|
||||
@ -497,8 +515,15 @@ int riscv_swint(int irq, void *context, void *arg)
|
||||
if (index == 0 && rtcb->xcp.kstack != NULL)
|
||||
{
|
||||
rtcb->xcp.ustkptr = (uintptr_t *)regs[REG_SP];
|
||||
regs[REG_SP] = (uintptr_t)rtcb->xcp.kstack +
|
||||
if (rtcb->xcp.kstkptr != NULL)
|
||||
{
|
||||
regs[REG_SP] = (uintptr_t)rtcb->xcp.kstkptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
regs[REG_SP] = (uintptr_t)rtcb->xcp.kstack +
|
||||
ARCH_KERNEL_STACKSIZE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user