mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-03 17:40:04 +00:00
![Michael Ellerman](/assets/img/avatar_default.png)
Commitb0b3b2c78e
("powerpc: Switch to relative jump labels") switched us to using relative jump labels. That involves changing the code, target and key members in struct jump_entry to be relative to the address of the jump_entry, rather than absolute addresses. We have two static inlines that create a struct jump_entry, arch_static_branch() and arch_static_branch_jump(), as well as an asm macro ARCH_STATIC_BRANCH, which is used by the pseries-only hypervisor tracing code. Unfortunately we missed updating the key to be a relative reference in ARCH_STATIC_BRANCH. That causes a pseries kernel to have a handful of jump_entry structs with bad key values. Instead of being a relative reference they instead hold the full address of the key. However the code doesn't expect that, it still adds the key value to the address of the jump_entry (see jump_entry_key()) expecting to get a pointer to a key somewhere in kernel data. The table of jump_entry structs sits in rodata, which comes after the kernel text. In a typical build this will be somewhere around 15MB. The address of the key will be somewhere in data, typically around 20MB. Adding the two values together gets us a pointer somewhere around 45MB. We then call static_key_set_entries() with that bad pointer and modify some members of the struct static_key we think we are pointing at. A pseries kernel is typically ~30MB in size, so writing to ~45MB won't corrupt the kernel itself. However if we're booting with an initrd, depending on the size and exact location of the initrd, we can corrupt the initrd. Depending on how exactly we corrupt the initrd it can either cause the system to not boot, or just corrupt one of the files in the initrd. The fix is simply to make the key value relative to the jump_entry struct in the ARCH_STATIC_BRANCH macro. Fixes:b0b3b2c78e
("powerpc: Switch to relative jump labels") Reported-by: Anastasia Kovaleva <a.kovaleva@yadro.com> Reported-by: Roman Bolshakov <r.bolshakov@yadro.com> Reported-by: Greg Kurz <groug@kaod.org> Reported-by: Daniel Axtens <dja@axtens.net> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Tested-by: Daniel Axtens <dja@axtens.net> Tested-by: Greg Kurz <groug@kaod.org> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://lore.kernel.org/r/20210614131440.312360-1-mpe@ellerman.id.au
57 lines
1.3 KiB
C
57 lines
1.3 KiB
C
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
#ifndef _ASM_POWERPC_JUMP_LABEL_H
|
|
#define _ASM_POWERPC_JUMP_LABEL_H
|
|
|
|
/*
|
|
* Copyright 2010 Michael Ellerman, IBM Corp.
|
|
*/
|
|
|
|
#ifndef __ASSEMBLY__
|
|
#include <linux/types.h>
|
|
|
|
#include <asm/feature-fixups.h>
|
|
#include <asm/asm-const.h>
|
|
|
|
#define JUMP_ENTRY_TYPE stringify_in_c(FTR_ENTRY_LONG)
|
|
#define JUMP_LABEL_NOP_SIZE 4
|
|
|
|
static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
|
|
{
|
|
asm_volatile_goto("1:\n\t"
|
|
"nop # arch_static_branch\n\t"
|
|
".pushsection __jump_table, \"aw\"\n\t"
|
|
".long 1b - ., %l[l_yes] - .\n\t"
|
|
JUMP_ENTRY_TYPE "%c0 - .\n\t"
|
|
".popsection \n\t"
|
|
: : "i" (&((char *)key)[branch]) : : l_yes);
|
|
|
|
return false;
|
|
l_yes:
|
|
return true;
|
|
}
|
|
|
|
static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch)
|
|
{
|
|
asm_volatile_goto("1:\n\t"
|
|
"b %l[l_yes] # arch_static_branch_jump\n\t"
|
|
".pushsection __jump_table, \"aw\"\n\t"
|
|
".long 1b - ., %l[l_yes] - .\n\t"
|
|
JUMP_ENTRY_TYPE "%c0 - .\n\t"
|
|
".popsection \n\t"
|
|
: : "i" (&((char *)key)[branch]) : : l_yes);
|
|
|
|
return false;
|
|
l_yes:
|
|
return true;
|
|
}
|
|
|
|
#else
|
|
#define ARCH_STATIC_BRANCH(LABEL, KEY) \
|
|
1098: nop; \
|
|
.pushsection __jump_table, "aw"; \
|
|
.long 1098b - ., LABEL - .; \
|
|
FTR_ENTRY_LONG KEY - .; \
|
|
.popsection
|
|
#endif
|
|
|
|
#endif /* _ASM_POWERPC_JUMP_LABEL_H */
|