Skip to content

Commit 4a37cca

Browse files
kevin-brodsky-armgregkh
authored andcommitted
arm64: signal: Preserve POR_EL0 if poe_context is missing
commit 030e8a4 upstream. Commit 2e8a1ac ("arm64: signal: Improve POR_EL0 handling to avoid uaccess failures") delayed the write to POR_EL0 in rt_sigreturn to avoid spurious uaccess failures. This change however relies on the poe_context frame record being present: on a system supporting POE, calling sigreturn without a poe_context record now results in writing arbitrary data from the kernel stack into POR_EL0. Fix this by adding a __valid_fields member to struct user_access_state, and zeroing the struct on allocation. restore_poe_context() then indicates that the por_el0 field is valid by setting the corresponding bit in __valid_fields, and restore_user_access_state() only touches POR_EL0 if there is a valid value to set it to. This is in line with how POR_EL0 was originally handled; all frame records are currently optional, except fpsimd_context. To ensure that __valid_fields is kept in sync, fields (currently just por_el0) are now accessed via accessors and prefixed with __ to discourage direct access. Fixes: 2e8a1ac ("arm64: signal: Improve POR_EL0 handling to avoid uaccess failures") Cc: <stable@vger.kernel.org> Reported-by: Will Deacon <will@kernel.org> Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent c0b654b commit 4a37cca

1 file changed

Lines changed: 43 additions & 11 deletions

File tree

arch/arm64/kernel/signal.c

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -67,20 +67,45 @@ struct rt_sigframe_user_layout {
6767
unsigned long end_offset;
6868
};
6969

70+
#define TERMINATOR_SIZE round_up(sizeof(struct _aarch64_ctx), 16)
71+
#define EXTRA_CONTEXT_SIZE round_up(sizeof(struct extra_context), 16)
72+
7073
/*
7174
* Holds any EL0-controlled state that influences unprivileged memory accesses.
7275
* This includes both accesses done in userspace and uaccess done in the kernel.
7376
*
7477
* This state needs to be carefully managed to ensure that it doesn't cause
7578
* uaccess to fail when setting up the signal frame, and the signal handler
7679
* itself also expects a well-defined state when entered.
80+
*
81+
* The struct should be zero-initialised. Its members should only be accessed
82+
* via the accessors below. __valid_fields tracks which of the fields are valid
83+
* (have been set to some value).
7784
*/
7885
struct user_access_state {
79-
u64 por_el0;
86+
unsigned int __valid_fields;
87+
u64 __por_el0;
8088
};
8189

82-
#define TERMINATOR_SIZE round_up(sizeof(struct _aarch64_ctx), 16)
83-
#define EXTRA_CONTEXT_SIZE round_up(sizeof(struct extra_context), 16)
90+
#define UA_STATE_HAS_POR_EL0 BIT(0)
91+
92+
static void set_ua_state_por_el0(struct user_access_state *ua_state,
93+
u64 por_el0)
94+
{
95+
ua_state->__por_el0 = por_el0;
96+
ua_state->__valid_fields |= UA_STATE_HAS_POR_EL0;
97+
}
98+
99+
static int get_ua_state_por_el0(const struct user_access_state *ua_state,
100+
u64 *por_el0)
101+
{
102+
if (ua_state->__valid_fields & UA_STATE_HAS_POR_EL0) {
103+
*por_el0 = ua_state->__por_el0;
104+
return 0;
105+
}
106+
107+
return -ENOENT;
108+
}
84109

85110
/*
86111
* Save the user access state into ua_state and reset it to disable any
@@ -94,7 +119,7 @@ static void save_reset_user_access_state(struct user_access_state *ua_state)
94119
for (int pkey = 0; pkey < arch_max_pkey(); pkey++)
95120
por_enable_all |= POR_ELx_PERM_PREP(pkey, POE_RWX);
96121

97-
ua_state->por_el0 = read_sysreg_s(SYS_POR_EL0);
122+
set_ua_state_por_el0(ua_state, read_sysreg_s(SYS_POR_EL0));
98123
write_sysreg_s(por_enable_all, SYS_POR_EL0);
99124
/*
100125
* No ISB required as we can tolerate spurious Overlay faults -
@@ -122,8 +147,10 @@ static void set_handler_user_access_state(void)
122147
*/
123148
static void restore_user_access_state(const struct user_access_state *ua_state)
124149
{
125-
if (system_supports_poe())
126-
write_sysreg_s(ua_state->por_el0, SYS_POR_EL0);
150+
u64 por_el0;
151+
152+
if (get_ua_state_por_el0(ua_state, &por_el0) == 0)
153+
write_sysreg_s(por_el0, SYS_POR_EL0);
127154
}
128155

129156
static void init_user_layout(struct rt_sigframe_user_layout *user)
@@ -333,11 +360,16 @@ static int restore_fpmr_context(struct user_ctxs *user)
333360
static int preserve_poe_context(struct poe_context __user *ctx,
334361
const struct user_access_state *ua_state)
335362
{
336-
int err = 0;
363+
int err;
364+
u64 por_el0;
365+
366+
err = get_ua_state_por_el0(ua_state, &por_el0);
367+
if (WARN_ON_ONCE(err))
368+
return err;
337369

338370
__put_user_error(POE_MAGIC, &ctx->head.magic, err);
339371
__put_user_error(sizeof(*ctx), &ctx->head.size, err);
340-
__put_user_error(ua_state->por_el0, &ctx->por_el0, err);
372+
__put_user_error(por_el0, &ctx->por_el0, err);
341373

342374
return err;
343375
}
@@ -353,7 +385,7 @@ static int restore_poe_context(struct user_ctxs *user,
353385

354386
__get_user_error(por_el0, &(user->poe->por_el0), err);
355387
if (!err)
356-
ua_state->por_el0 = por_el0;
388+
set_ua_state_por_el0(ua_state, por_el0);
357389

358390
return err;
359391
}
@@ -1095,7 +1127,7 @@ SYSCALL_DEFINE0(rt_sigreturn)
10951127
{
10961128
struct pt_regs *regs = current_pt_regs();
10971129
struct rt_sigframe __user *frame;
1098-
struct user_access_state ua_state;
1130+
struct user_access_state ua_state = {};
10991131

11001132
/* Always make any pending restarted system calls return -EINTR */
11011133
current->restart_block.fn = do_no_restart_syscall;
@@ -1507,7 +1539,7 @@ static int setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,
15071539
{
15081540
struct rt_sigframe_user_layout user;
15091541
struct rt_sigframe __user *frame;
1510-
struct user_access_state ua_state;
1542+
struct user_access_state ua_state = {};
15111543
int err = 0;
15121544

15131545
fpsimd_save_and_flush_current_state();

0 commit comments

Comments
 (0)