On 24/10/2024 12:59, Catalin Marinas wrote: > On Wed, Oct 23, 2024 at 04:05:09PM +0100, Kevin Brodsky wrote: >> +/* >> + * Save the unpriv access state into ua_state and reset it to disable any >> + * restrictions. >> + */ >> +static void save_reset_user_access_state(struct user_access_state *ua_state) >> +{ >> + if (system_supports_poe()) { >> + /* >> + * Enable all permissions in all 8 keys >> + * (inspired by REPEAT_BYTE()) >> + */ >> + u64 por_enable_all = (~0u / POE_MASK) * POE_RXW; > I think this should be ~0ul. It is ~0u on purpose, because unlike in REPEAT_BYTE(), I only wanted the lower 32 bits to be filled with POE_RXW (we only have 8 keys, the top 32 bits are RES0). That said, given that D128 has 4-bit pkeys, we could anticipate and fill the top 32 bits too (should make no difference on D64). >> @@ -907,6 +964,7 @@ SYSCALL_DEFINE0(rt_sigreturn) >> { >> struct pt_regs *regs = current_pt_regs(); >> struct rt_sigframe __user *frame; >> + struct user_access_state ua_state; >> >> /* Always make any pending restarted system calls return -EINTR */ >> current->restart_block.fn = do_no_restart_syscall; >> @@ -923,12 +981,14 @@ SYSCALL_DEFINE0(rt_sigreturn) >> if (!access_ok(frame, sizeof (*frame))) >> goto badframe; >> >> - if (restore_sigframe(regs, frame)) >> + if (restore_sigframe(regs, frame, &ua_state)) >> goto badframe; >> >> if (restore_altstack(&frame->uc.uc_stack)) >> goto badframe; >> >> + restore_user_access_state(&ua_state); >> + >> return regs->regs[0]; >> >> badframe: > The saving part I'm fine with. For restoring, I was wondering whether we > can get a more privileged POR_EL0 if reading the frame somehow failed. > This is largely theoretical, there are other ways to attack like > writing POR_EL0 directly than unmapping/remapping the signal stack. > > What I'd change here is always restore_user_access_state() to > POR_EL0_INIT. Maybe just initialise ua_state above and add the function > call after the badframe label. I'm not sure I understand. When we enter this function, POR_EL0 is set to whatever the signal handler set it to (POR_EL0_INIT by default). There are then two cases: 1) Everything succeeds, including reading the saved POR_EL0 from the frame. We then call restore_user_access_state(), setting POR_EL0 to the value we've read, and return to userspace. 2) Any uaccess fails (for instance reading POR_EL0). In that case we leave POR_EL0 unchanged and deliver SIGSEGV. In case 2 POR_EL0 is most likely already set to POR_EL0_INIT, or whatever the signal handler set it to. It's not clear to me that forcing it to POR_EL0_INIT helps much. Either way it's doubtful that the SIGSEGV handler will be able to recover, since the new signal frame we will create for it may be a mix of interrupted state and signal handler state (depending on exactly where we fail). Kevin