Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

arm64: signal: Preserve POR_EL0 if poe_context is missing

Commit 2e8a1acea859 ("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: 2e8a1acea859 ("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>

authored by

Kevin Brodsky and committed by
Catalin Marinas
030e8a40 4d8e74ad

+43 -11
+43 -11
arch/arm64/kernel/signal.c
··· 67 67 unsigned long end_offset; 68 68 }; 69 69 70 + #define TERMINATOR_SIZE round_up(sizeof(struct _aarch64_ctx), 16) 71 + #define EXTRA_CONTEXT_SIZE round_up(sizeof(struct extra_context), 16) 72 + 70 73 /* 71 74 * Holds any EL0-controlled state that influences unprivileged memory accesses. 72 75 * This includes both accesses done in userspace and uaccess done in the kernel. ··· 77 74 * This state needs to be carefully managed to ensure that it doesn't cause 78 75 * uaccess to fail when setting up the signal frame, and the signal handler 79 76 * itself also expects a well-defined state when entered. 77 + * 78 + * The struct should be zero-initialised. Its members should only be accessed 79 + * via the accessors below. __valid_fields tracks which of the fields are valid 80 + * (have been set to some value). 80 81 */ 81 82 struct user_access_state { 82 - u64 por_el0; 83 + unsigned int __valid_fields; 84 + u64 __por_el0; 83 85 }; 84 86 85 - #define TERMINATOR_SIZE round_up(sizeof(struct _aarch64_ctx), 16) 86 - #define EXTRA_CONTEXT_SIZE round_up(sizeof(struct extra_context), 16) 87 + #define UA_STATE_HAS_POR_EL0 BIT(0) 88 + 89 + static void set_ua_state_por_el0(struct user_access_state *ua_state, 90 + u64 por_el0) 91 + { 92 + ua_state->__por_el0 = por_el0; 93 + ua_state->__valid_fields |= UA_STATE_HAS_POR_EL0; 94 + } 95 + 96 + static int get_ua_state_por_el0(const struct user_access_state *ua_state, 97 + u64 *por_el0) 98 + { 99 + if (ua_state->__valid_fields & UA_STATE_HAS_POR_EL0) { 100 + *por_el0 = ua_state->__por_el0; 101 + return 0; 102 + } 103 + 104 + return -ENOENT; 105 + } 87 106 88 107 /* 89 108 * Save the user access state into ua_state and reset it to disable any ··· 119 94 for (int pkey = 0; pkey < arch_max_pkey(); pkey++) 120 95 por_enable_all |= POR_ELx_PERM_PREP(pkey, POE_RWX); 121 96 122 - ua_state->por_el0 = read_sysreg_s(SYS_POR_EL0); 97 + set_ua_state_por_el0(ua_state, read_sysreg_s(SYS_POR_EL0)); 123 98 write_sysreg_s(por_enable_all, SYS_POR_EL0); 124 99 /* 125 100 * No ISB required as we can tolerate spurious Overlay faults - ··· 147 122 */ 148 123 static void restore_user_access_state(const struct user_access_state *ua_state) 149 124 { 150 - if (system_supports_poe()) 151 - write_sysreg_s(ua_state->por_el0, SYS_POR_EL0); 125 + u64 por_el0; 126 + 127 + if (get_ua_state_por_el0(ua_state, &por_el0) == 0) 128 + write_sysreg_s(por_el0, SYS_POR_EL0); 152 129 } 153 130 154 131 static void init_user_layout(struct rt_sigframe_user_layout *user) ··· 360 333 static int preserve_poe_context(struct poe_context __user *ctx, 361 334 const struct user_access_state *ua_state) 362 335 { 363 - int err = 0; 336 + int err; 337 + u64 por_el0; 338 + 339 + err = get_ua_state_por_el0(ua_state, &por_el0); 340 + if (WARN_ON_ONCE(err)) 341 + return err; 364 342 365 343 __put_user_error(POE_MAGIC, &ctx->head.magic, err); 366 344 __put_user_error(sizeof(*ctx), &ctx->head.size, err); 367 - __put_user_error(ua_state->por_el0, &ctx->por_el0, err); 345 + __put_user_error(por_el0, &ctx->por_el0, err); 368 346 369 347 return err; 370 348 } ··· 385 353 386 354 __get_user_error(por_el0, &(user->poe->por_el0), err); 387 355 if (!err) 388 - ua_state->por_el0 = por_el0; 356 + set_ua_state_por_el0(ua_state, por_el0); 389 357 390 358 return err; 391 359 } ··· 1127 1095 { 1128 1096 struct pt_regs *regs = current_pt_regs(); 1129 1097 struct rt_sigframe __user *frame; 1130 - struct user_access_state ua_state; 1098 + struct user_access_state ua_state = {}; 1131 1099 1132 1100 /* Always make any pending restarted system calls return -EINTR */ 1133 1101 current->restart_block.fn = do_no_restart_syscall; ··· 1539 1507 { 1540 1508 struct rt_sigframe_user_layout user; 1541 1509 struct rt_sigframe __user *frame; 1542 - struct user_access_state ua_state; 1510 + struct user_access_state ua_state = {}; 1543 1511 int err = 0; 1544 1512 1545 1513 fpsimd_save_and_flush_current_state();