Skip to content

Commit 9e78b65

Browse files
committed
arm64: Move SSBD prctl() handler alongside other spectre mitigation code
As part of the spectre consolidation effort to shift all of the ghosts into their own proton pack, move all of the horrible SSBD prctl() code out of its own 'ssbd.c' file. Signed-off-by: Will Deacon <will@kernel.org>
1 parent 9b0955b commit 9e78b65

3 files changed

Lines changed: 119 additions & 130 deletions

File tree

arch/arm64/kernel/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ obj-y := debug-monitors.o entry.o irq.o fpsimd.o \
1919
return_address.o cpuinfo.o cpu_errata.o \
2020
cpufeature.o alternative.o cacheinfo.o \
2121
smp.o smp_spin_table.o topology.o smccc-call.o \
22-
ssbd.o syscall.o proton-pack.o
22+
syscall.o proton-pack.o
2323

2424
targets += efi-entry.o
2525

arch/arm64/kernel/proton-pack.c

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <linux/arm-smccc.h>
2121
#include <linux/cpu.h>
2222
#include <linux/device.h>
23+
#include <linux/nospec.h>
2324
#include <linux/prctl.h>
2425

2526
#include <asm/spectre.h>
@@ -318,3 +319,120 @@ void spectre_v2_enable_mitigation(const struct arm64_cpu_capabilities *__unused)
318319

319320
update_mitigation_state(&spectre_v2_state, state);
320321
}
322+
323+
/* Spectre v4 prctl */
324+
static void ssbd_ssbs_enable(struct task_struct *task)
325+
{
326+
u64 val = is_compat_thread(task_thread_info(task)) ?
327+
PSR_AA32_SSBS_BIT : PSR_SSBS_BIT;
328+
329+
task_pt_regs(task)->pstate |= val;
330+
}
331+
332+
static void ssbd_ssbs_disable(struct task_struct *task)
333+
{
334+
u64 val = is_compat_thread(task_thread_info(task)) ?
335+
PSR_AA32_SSBS_BIT : PSR_SSBS_BIT;
336+
337+
task_pt_regs(task)->pstate &= ~val;
338+
}
339+
340+
/*
341+
* prctl interface for SSBD
342+
*/
343+
static int ssbd_prctl_set(struct task_struct *task, unsigned long ctrl)
344+
{
345+
int state = arm64_get_ssbd_state();
346+
347+
/* Unsupported */
348+
if (state == ARM64_SSBD_UNKNOWN)
349+
return -ENODEV;
350+
351+
/* Treat the unaffected/mitigated state separately */
352+
if (state == ARM64_SSBD_MITIGATED) {
353+
switch (ctrl) {
354+
case PR_SPEC_ENABLE:
355+
return -EPERM;
356+
case PR_SPEC_DISABLE:
357+
case PR_SPEC_FORCE_DISABLE:
358+
return 0;
359+
}
360+
}
361+
362+
/*
363+
* Things are a bit backward here: the arm64 internal API
364+
* *enables the mitigation* when the userspace API *disables
365+
* speculation*. So much fun.
366+
*/
367+
switch (ctrl) {
368+
case PR_SPEC_ENABLE:
369+
/* If speculation is force disabled, enable is not allowed */
370+
if (state == ARM64_SSBD_FORCE_ENABLE ||
371+
task_spec_ssb_force_disable(task))
372+
return -EPERM;
373+
task_clear_spec_ssb_disable(task);
374+
clear_tsk_thread_flag(task, TIF_SSBD);
375+
ssbd_ssbs_enable(task);
376+
break;
377+
case PR_SPEC_DISABLE:
378+
if (state == ARM64_SSBD_FORCE_DISABLE)
379+
return -EPERM;
380+
task_set_spec_ssb_disable(task);
381+
set_tsk_thread_flag(task, TIF_SSBD);
382+
ssbd_ssbs_disable(task);
383+
break;
384+
case PR_SPEC_FORCE_DISABLE:
385+
if (state == ARM64_SSBD_FORCE_DISABLE)
386+
return -EPERM;
387+
task_set_spec_ssb_disable(task);
388+
task_set_spec_ssb_force_disable(task);
389+
set_tsk_thread_flag(task, TIF_SSBD);
390+
ssbd_ssbs_disable(task);
391+
break;
392+
default:
393+
return -ERANGE;
394+
}
395+
396+
return 0;
397+
}
398+
399+
int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which,
400+
unsigned long ctrl)
401+
{
402+
switch (which) {
403+
case PR_SPEC_STORE_BYPASS:
404+
return ssbd_prctl_set(task, ctrl);
405+
default:
406+
return -ENODEV;
407+
}
408+
}
409+
410+
static int ssbd_prctl_get(struct task_struct *task)
411+
{
412+
switch (arm64_get_ssbd_state()) {
413+
case ARM64_SSBD_UNKNOWN:
414+
return -ENODEV;
415+
case ARM64_SSBD_FORCE_ENABLE:
416+
return PR_SPEC_DISABLE;
417+
case ARM64_SSBD_KERNEL:
418+
if (task_spec_ssb_force_disable(task))
419+
return PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE;
420+
if (task_spec_ssb_disable(task))
421+
return PR_SPEC_PRCTL | PR_SPEC_DISABLE;
422+
return PR_SPEC_PRCTL | PR_SPEC_ENABLE;
423+
case ARM64_SSBD_FORCE_DISABLE:
424+
return PR_SPEC_ENABLE;
425+
default:
426+
return PR_SPEC_NOT_AFFECTED;
427+
}
428+
}
429+
430+
int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which)
431+
{
432+
switch (which) {
433+
case PR_SPEC_STORE_BYPASS:
434+
return ssbd_prctl_get(task);
435+
default:
436+
return -ENODEV;
437+
}
438+
}

arch/arm64/kernel/ssbd.c

Lines changed: 0 additions & 129 deletions
This file was deleted.

0 commit comments

Comments
 (0)