mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
microblaze: preserve the MSR carry flags across signals
setup_sigcontext() and restore_sigcontext() copy r0-r31, pc, ear, esr and
fsr to and from the signal frame but never touch MSR. The interrupted
MSR is therefore dropped from the signal context entirely: the handler's
ucontext does not expose it, a handler cannot adjust the resumed
arithmetic flags through uc_mcontext.regs.msr, and -- because
restore_sigcontext() leaves regs->msr as whatever the rt_sigreturn trap
left in it -- the interrupted context resumes with the carry produced by
the syscall entry path (_user_exception does "addi r14, r14, 4", which
writes carry), not with its own.
Other architectures round-trip the user-visible flags through the signal
frame (arm's cpsr, csky's carry, x86's eflags), so a handler can both read
and adjust the resumed flags; purely privileged status registers such as
riscv's sstatus are left out. MicroBlaze should do the same for the
user-writable bits.
Concretely, MSR[C] (carry) is lost across signal delivery. Code that
keeps a live carry across a point where a signal can be delivered -- for
example an lwx/swx compare-and-swap retry loop, between the swx and the
carry test -- resumes with the handler's carry and mis-evaluates the
result; the same failure class as the rt_sigreturn r3/r4 clobber, reached
through a different register. Demonstrated under qemu-system-microblazeel
(machine petalogix-s3adsp1800): a handler that sets MSR_C in
uc_mcontext.regs.msr has no effect before this change (0 of 132 in-window
signals propagated) and takes effect after (130 of 132).
Save MSR in setup_sigcontext() so the handler's ucontext exposes it. The
signal frame is user-writable, so restore_sigcontext() must not restore it
verbatim: MicroBlaze packs the user-writable carry (MSR_C, MSR_CC) and the
privileged control bits (MSR_UM, MSR_VM, MSR_IE, MSR_EE, ...) into the one
register, and a verbatim restore would let userspace alter privileged
return state -- rtbd derives the resumed mode from MSR_UMS/MSR_VMS.
Restore only MSR_C | MSR_CC from the frame and keep the rest from the
current regs->msr. This mirrors x86's
restore_sigcontext(), which masks the restored EFLAGS to FIX_EFLAGS for
the same reason; arches whose status register is purely privileged (e.g.
riscv sstatus) simply do not restore it at all.
Comment on the exposed MSR reworded: it is not read-only,
restore_sigcontext() applies MSR_C|MSR_CC from the frame. Author's
Signed-off-by kept; he agreed to comment and changelog cleanups.
Fixes: 2148daa9c4 ("microblaze_v8: Signal support")
Cc: stable@vger.kernel.org
Signed-off-by: Sam Price <thesamprice@gmail.com>
Signed-off-by: Ramin Moussavi <ramin.moussavi@yacoub.de>
Tested-by: Waldemar Brodkorb <wbx@openadk.org>
Link: https://patch.msgid.link/20260821151809.1233057-6-ramin.moussavi@yacoub.de
Signed-off-by: Michal Simek <michal.simek@amd.com>
This commit is contained in:
parent
c35d40a3ef
commit
ca35dd21a5
|
|
@ -33,6 +33,7 @@
|
|||
#include <linux/linkage.h>
|
||||
#include <linux/resume_user_mode.h>
|
||||
#include <asm/entry.h>
|
||||
#include <asm/registers.h>
|
||||
#include <asm/ucontext.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/syscalls.h>
|
||||
|
|
@ -81,6 +82,22 @@ static int restore_sigcontext(struct pt_regs *regs,
|
|||
COPY(pc); COPY(ear); COPY(esr); COPY(fsr);
|
||||
#undef COPY
|
||||
|
||||
/*
|
||||
* The frame is user-writable, so restore only the user-writable
|
||||
* status flags (carry) and keep the kernel-controlled MSR bits
|
||||
* (UMS/VMS/IE/EE/...) from regs->msr: rtbd derives the resumed mode
|
||||
* from UMS/VMS, so a verbatim restore would hand userspace the
|
||||
* privileged return state. Same idea as x86 masking the restored
|
||||
* EFLAGS to FIX_EFLAGS.
|
||||
*/
|
||||
{
|
||||
unsigned long msr;
|
||||
|
||||
err |= __get_user(msr, &sc->regs.msr);
|
||||
regs->msr = (regs->msr & ~(MSR_C | MSR_CC)) |
|
||||
(msr & (MSR_C | MSR_CC));
|
||||
}
|
||||
|
||||
*rval_p = regs->r3;
|
||||
|
||||
return err;
|
||||
|
|
@ -140,6 +157,7 @@ setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
|
|||
COPY(r26); COPY(r27); COPY(r28); COPY(r29);
|
||||
COPY(r30); COPY(r31);
|
||||
COPY(pc); COPY(ear); COPY(esr); COPY(fsr);
|
||||
COPY(msr); /* restore_sigcontext() accepts only carry state */
|
||||
#undef COPY
|
||||
|
||||
err |= __put_user(mask, &sc->oldmask);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user