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