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