1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2018 ARM Ltd, All Rights Reserved.
4  */
5 
6 #include <linux/errno.h>
7 #include <linux/sched.h>
8 #include <linux/thread_info.h>
9 
10 #include <asm/cpufeature.h>
11 
12 /*
13  * prctl interface for SSBD
14  * FIXME: Drop the below ifdefery once merged in 4.18.
15  */
16 #ifdef PR_SPEC_STORE_BYPASS
ssbd_prctl_set(struct task_struct * task,unsigned long ctrl)17 static int ssbd_prctl_set(struct task_struct *task, unsigned long ctrl)
18 {
19 	int state = arm64_get_ssbd_state();
20 
21 	/* Unsupported */
22 	if (state == ARM64_SSBD_UNKNOWN)
23 		return -EINVAL;
24 
25 	/* Treat the unaffected/mitigated state separately */
26 	if (state == ARM64_SSBD_MITIGATED) {
27 		switch (ctrl) {
28 		case PR_SPEC_ENABLE:
29 			return -EPERM;
30 		case PR_SPEC_DISABLE:
31 		case PR_SPEC_FORCE_DISABLE:
32 			return 0;
33 		}
34 	}
35 
36 	/*
37 	 * Things are a bit backward here: the arm64 internal API
38 	 * *enables the mitigation* when the userspace API *disables
39 	 * speculation*. So much fun.
40 	 */
41 	switch (ctrl) {
42 	case PR_SPEC_ENABLE:
43 		/* If speculation is force disabled, enable is not allowed */
44 		if (state == ARM64_SSBD_FORCE_ENABLE ||
45 		    task_spec_ssb_force_disable(task))
46 			return -EPERM;
47 		task_clear_spec_ssb_disable(task);
48 		clear_tsk_thread_flag(task, TIF_SSBD);
49 		break;
50 	case PR_SPEC_DISABLE:
51 		if (state == ARM64_SSBD_FORCE_DISABLE)
52 			return -EPERM;
53 		task_set_spec_ssb_disable(task);
54 		set_tsk_thread_flag(task, TIF_SSBD);
55 		break;
56 	case PR_SPEC_FORCE_DISABLE:
57 		if (state == ARM64_SSBD_FORCE_DISABLE)
58 			return -EPERM;
59 		task_set_spec_ssb_disable(task);
60 		task_set_spec_ssb_force_disable(task);
61 		set_tsk_thread_flag(task, TIF_SSBD);
62 		break;
63 	default:
64 		return -ERANGE;
65 	}
66 
67 	return 0;
68 }
69 
arch_prctl_spec_ctrl_set(struct task_struct * task,unsigned long which,unsigned long ctrl)70 int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which,
71 			     unsigned long ctrl)
72 {
73 	switch (which) {
74 	case PR_SPEC_STORE_BYPASS:
75 		return ssbd_prctl_set(task, ctrl);
76 	default:
77 		return -ENODEV;
78 	}
79 }
80 
ssbd_prctl_get(struct task_struct * task)81 static int ssbd_prctl_get(struct task_struct *task)
82 {
83 	switch (arm64_get_ssbd_state()) {
84 	case ARM64_SSBD_UNKNOWN:
85 		return -EINVAL;
86 	case ARM64_SSBD_FORCE_ENABLE:
87 		return PR_SPEC_DISABLE;
88 	case ARM64_SSBD_KERNEL:
89 		if (task_spec_ssb_force_disable(task))
90 			return PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE;
91 		if (task_spec_ssb_disable(task))
92 			return PR_SPEC_PRCTL | PR_SPEC_DISABLE;
93 		return PR_SPEC_PRCTL | PR_SPEC_ENABLE;
94 	case ARM64_SSBD_FORCE_DISABLE:
95 		return PR_SPEC_ENABLE;
96 	default:
97 		return PR_SPEC_NOT_AFFECTED;
98 	}
99 }
100 
arch_prctl_spec_ctrl_get(struct task_struct * task,unsigned long which)101 int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which)
102 {
103 	switch (which) {
104 	case PR_SPEC_STORE_BYPASS:
105 		return ssbd_prctl_get(task);
106 	default:
107 		return -ENODEV;
108 	}
109 }
110 #endif	/* PR_SPEC_STORE_BYPASS */
111