| From foo@baz Fri Mar 29 15:53:50 CET 2019 |
| From: Michael Ellerman <mpe@ellerman.id.au> |
| Date: Fri, 29 Mar 2019 22:25:50 +1100 |
| Subject: powerpc/64s: Patch barrier_nospec in modules |
| To: stable@vger.kernel.org, gregkh@linuxfoundation.org |
| Cc: linuxppc-dev@ozlabs.org, diana.craciun@nxp.com, msuchanek@suse.de, christophe.leroy@c-s.fr |
| Message-ID: <20190329112620.14489-3-mpe@ellerman.id.au> |
| |
| From: Michal Suchanek <msuchanek@suse.de> |
| |
| commit 815069ca57c142eb71d27439bc27f41a433a67b3 upstream. |
| |
| Note that unlike RFI which is patched only in kernel the nospec state |
| reflects settings at the time the module was loaded. |
| |
| Iterating all modules and re-patching every time the settings change |
| is not implemented. |
| |
| Based on lwsync patching. |
| |
| Signed-off-by: Michal Suchanek <msuchanek@suse.de> |
| Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| arch/powerpc/include/asm/setup.h | 7 +++++++ |
| arch/powerpc/kernel/module.c | 6 ++++++ |
| arch/powerpc/kernel/security.c | 2 +- |
| arch/powerpc/lib/feature-fixups.c | 16 +++++++++++++--- |
| 4 files changed, 27 insertions(+), 4 deletions(-) |
| |
| --- a/arch/powerpc/include/asm/setup.h |
| +++ b/arch/powerpc/include/asm/setup.h |
| @@ -53,6 +53,13 @@ enum l1d_flush_type { |
| void setup_rfi_flush(enum l1d_flush_type, bool enable); |
| void do_rfi_flush_fixups(enum l1d_flush_type types); |
| void do_barrier_nospec_fixups(bool enable); |
| +extern bool barrier_nospec_enabled; |
| + |
| +#ifdef CONFIG_PPC_BOOK3S_64 |
| +void do_barrier_nospec_fixups_range(bool enable, void *start, void *end); |
| +#else |
| +static inline void do_barrier_nospec_fixups_range(bool enable, void *start, void *end) { }; |
| +#endif |
| |
| #endif /* !__ASSEMBLY__ */ |
| |
| --- a/arch/powerpc/kernel/module.c |
| +++ b/arch/powerpc/kernel/module.c |
| @@ -72,6 +72,12 @@ int module_finalize(const Elf_Ehdr *hdr, |
| do_feature_fixups(powerpc_firmware_features, |
| (void *)sect->sh_addr, |
| (void *)sect->sh_addr + sect->sh_size); |
| + |
| + sect = find_section(hdr, sechdrs, "__spec_barrier_fixup"); |
| + if (sect != NULL) |
| + do_barrier_nospec_fixups_range(barrier_nospec_enabled, |
| + (void *)sect->sh_addr, |
| + (void *)sect->sh_addr + sect->sh_size); |
| #endif |
| |
| sect = find_section(hdr, sechdrs, "__lwsync_fixup"); |
| --- a/arch/powerpc/kernel/security.c |
| +++ b/arch/powerpc/kernel/security.c |
| @@ -15,7 +15,7 @@ |
| |
| unsigned long powerpc_security_features __read_mostly = SEC_FTR_DEFAULT; |
| |
| -static bool barrier_nospec_enabled; |
| +bool barrier_nospec_enabled; |
| |
| static void enable_barrier_nospec(bool enable) |
| { |
| --- a/arch/powerpc/lib/feature-fixups.c |
| +++ b/arch/powerpc/lib/feature-fixups.c |
| @@ -278,14 +278,14 @@ void do_rfi_flush_fixups(enum l1d_flush_ |
| : "unknown"); |
| } |
| |
| -void do_barrier_nospec_fixups(bool enable) |
| +void do_barrier_nospec_fixups_range(bool enable, void *fixup_start, void *fixup_end) |
| { |
| unsigned int instr, *dest; |
| long *start, *end; |
| int i; |
| |
| - start = PTRRELOC(&__start___barrier_nospec_fixup), |
| - end = PTRRELOC(&__stop___barrier_nospec_fixup); |
| + start = fixup_start; |
| + end = fixup_end; |
| |
| instr = 0x60000000; /* nop */ |
| |
| @@ -304,6 +304,16 @@ void do_barrier_nospec_fixups(bool enabl |
| printk(KERN_DEBUG "barrier-nospec: patched %d locations\n", i); |
| } |
| |
| +void do_barrier_nospec_fixups(bool enable) |
| +{ |
| + void *start, *end; |
| + |
| + start = PTRRELOC(&__start___barrier_nospec_fixup), |
| + end = PTRRELOC(&__stop___barrier_nospec_fixup); |
| + |
| + do_barrier_nospec_fixups_range(enable, start, end); |
| +} |
| + |
| #endif /* CONFIG_PPC_BOOK3S_64 */ |
| |
| void do_lwsync_fixups(unsigned long value, void *fixup_start, void *fixup_end) |