]>
Commit | Line | Data |
---|---|---|
4fa5b95e GKH |
1 | From foo@baz Mon 29 Apr 2019 11:38:37 AM CEST |
2 | From: Michael Ellerman <mpe@ellerman.id.au> | |
3 | Date: Mon, 22 Apr 2019 00:20:13 +1000 | |
4 | Subject: powerpc/64s: Enable barrier_nospec based on firmware settings | |
5 | To: stable@vger.kernel.org, gregkh@linuxfoundation.org | |
6 | Cc: linuxppc-dev@ozlabs.org, diana.craciun@nxp.com, msuchanek@suse.de, npiggin@gmail.com, christophe.leroy@c-s.fr | |
7 | Message-ID: <20190421142037.21881-29-mpe@ellerman.id.au> | |
8 | ||
9 | From: Michal Suchanek <msuchanek@suse.de> | |
10 | ||
11 | commit cb3d6759a93c6d0aea1c10deb6d00e111c29c19c upstream. | |
12 | ||
13 | Check what firmware told us and enable/disable the barrier_nospec as | |
14 | appropriate. | |
15 | ||
16 | We err on the side of enabling the barrier, as it's no-op on older | |
17 | systems, see the comment for more detail. | |
18 | ||
19 | Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> | |
20 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
21 | --- | |
22 | arch/powerpc/include/asm/setup.h | 1 | |
23 | arch/powerpc/kernel/security.c | 59 +++++++++++++++++++++++++++++++++ | |
24 | arch/powerpc/platforms/powernv/setup.c | 1 | |
25 | arch/powerpc/platforms/pseries/setup.c | 1 | |
26 | 4 files changed, 62 insertions(+) | |
27 | ||
28 | --- a/arch/powerpc/include/asm/setup.h | |
29 | +++ b/arch/powerpc/include/asm/setup.h | |
30 | @@ -38,6 +38,7 @@ enum l1d_flush_type { | |
31 | ||
32 | void setup_rfi_flush(enum l1d_flush_type, bool enable); | |
33 | void do_rfi_flush_fixups(enum l1d_flush_type types); | |
34 | +void setup_barrier_nospec(void); | |
35 | void do_barrier_nospec_fixups(bool enable); | |
36 | extern bool barrier_nospec_enabled; | |
37 | ||
38 | --- a/arch/powerpc/kernel/security.c | |
39 | +++ b/arch/powerpc/kernel/security.c | |
40 | @@ -24,6 +24,65 @@ static void enable_barrier_nospec(bool e | |
41 | do_barrier_nospec_fixups(enable); | |
42 | } | |
43 | ||
44 | +void setup_barrier_nospec(void) | |
45 | +{ | |
46 | + bool enable; | |
47 | + | |
48 | + /* | |
49 | + * It would make sense to check SEC_FTR_SPEC_BAR_ORI31 below as well. | |
50 | + * But there's a good reason not to. The two flags we check below are | |
51 | + * both are enabled by default in the kernel, so if the hcall is not | |
52 | + * functional they will be enabled. | |
53 | + * On a system where the host firmware has been updated (so the ori | |
54 | + * functions as a barrier), but on which the hypervisor (KVM/Qemu) has | |
55 | + * not been updated, we would like to enable the barrier. Dropping the | |
56 | + * check for SEC_FTR_SPEC_BAR_ORI31 achieves that. The only downside is | |
57 | + * we potentially enable the barrier on systems where the host firmware | |
58 | + * is not updated, but that's harmless as it's a no-op. | |
59 | + */ | |
60 | + enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) && | |
61 | + security_ftr_enabled(SEC_FTR_BNDS_CHK_SPEC_BAR); | |
62 | + | |
63 | + enable_barrier_nospec(enable); | |
64 | +} | |
65 | + | |
66 | +#ifdef CONFIG_DEBUG_FS | |
67 | +static int barrier_nospec_set(void *data, u64 val) | |
68 | +{ | |
69 | + switch (val) { | |
70 | + case 0: | |
71 | + case 1: | |
72 | + break; | |
73 | + default: | |
74 | + return -EINVAL; | |
75 | + } | |
76 | + | |
77 | + if (!!val == !!barrier_nospec_enabled) | |
78 | + return 0; | |
79 | + | |
80 | + enable_barrier_nospec(!!val); | |
81 | + | |
82 | + return 0; | |
83 | +} | |
84 | + | |
85 | +static int barrier_nospec_get(void *data, u64 *val) | |
86 | +{ | |
87 | + *val = barrier_nospec_enabled ? 1 : 0; | |
88 | + return 0; | |
89 | +} | |
90 | + | |
91 | +DEFINE_SIMPLE_ATTRIBUTE(fops_barrier_nospec, | |
92 | + barrier_nospec_get, barrier_nospec_set, "%llu\n"); | |
93 | + | |
94 | +static __init int barrier_nospec_debugfs_init(void) | |
95 | +{ | |
96 | + debugfs_create_file("barrier_nospec", 0600, powerpc_debugfs_root, NULL, | |
97 | + &fops_barrier_nospec); | |
98 | + return 0; | |
99 | +} | |
100 | +device_initcall(barrier_nospec_debugfs_init); | |
101 | +#endif /* CONFIG_DEBUG_FS */ | |
102 | + | |
103 | ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf) | |
104 | { | |
105 | bool thread_priv; | |
106 | --- a/arch/powerpc/platforms/powernv/setup.c | |
107 | +++ b/arch/powerpc/platforms/powernv/setup.c | |
108 | @@ -123,6 +123,7 @@ static void pnv_setup_rfi_flush(void) | |
109 | security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV)); | |
110 | ||
111 | setup_rfi_flush(type, enable); | |
112 | + setup_barrier_nospec(); | |
113 | } | |
114 | ||
115 | static void __init pnv_setup_arch(void) | |
116 | --- a/arch/powerpc/platforms/pseries/setup.c | |
117 | +++ b/arch/powerpc/platforms/pseries/setup.c | |
118 | @@ -574,6 +574,7 @@ void pseries_setup_rfi_flush(void) | |
119 | security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR); | |
120 | ||
121 | setup_rfi_flush(types, enable); | |
122 | + setup_barrier_nospec(); | |
123 | } | |
124 | ||
125 | static void __init pSeries_setup_arch(void) |