diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c index 4956014a9937..6bbc16f98d5e 100644 --- a/arch/microblaze/kernel/signal.c +++ b/arch/microblaze/kernel/signal.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -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);