|
8 | 8 | #include <asm/fpu/api.h>
|
9 | 9 | #include <asm/fpu/signal.h>
|
10 | 10 | #include <asm/fpu/regset.h>
|
| 11 | +#include <asm/prctl.h> |
11 | 12 |
|
12 | 13 | #include "context.h"
|
13 | 14 | #include "internal.h"
|
@@ -174,6 +175,86 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset,
|
174 | 175 | return ret;
|
175 | 176 | }
|
176 | 177 |
|
| 178 | +#ifdef CONFIG_X86_USER_SHADOW_STACK |
| 179 | +int ssp_active(struct task_struct *target, const struct user_regset *regset) |
| 180 | +{ |
| 181 | + if (target->thread.features & ARCH_SHSTK_SHSTK) |
| 182 | + return regset->n; |
| 183 | + |
| 184 | + return 0; |
| 185 | +} |
| 186 | + |
| 187 | +int ssp_get(struct task_struct *target, const struct user_regset *regset, |
| 188 | + struct membuf to) |
| 189 | +{ |
| 190 | + struct fpu *fpu = &target->thread.fpu; |
| 191 | + struct cet_user_state *cetregs; |
| 192 | + |
| 193 | + if (!cpu_feature_enabled(X86_FEATURE_USER_SHSTK)) |
| 194 | + return -ENODEV; |
| 195 | + |
| 196 | + sync_fpstate(fpu); |
| 197 | + cetregs = get_xsave_addr(&fpu->fpstate->regs.xsave, XFEATURE_CET_USER); |
| 198 | + if (WARN_ON(!cetregs)) { |
| 199 | + /* |
| 200 | + * This shouldn't ever be NULL because shadow stack was |
| 201 | + * verified to be enabled above. This means |
| 202 | + * MSR_IA32_U_CET.CET_SHSTK_EN should be 1 and so |
| 203 | + * XFEATURE_CET_USER should not be in the init state. |
| 204 | + */ |
| 205 | + return -ENODEV; |
| 206 | + } |
| 207 | + |
| 208 | + return membuf_write(&to, (unsigned long *)&cetregs->user_ssp, |
| 209 | + sizeof(cetregs->user_ssp)); |
| 210 | +} |
| 211 | + |
| 212 | +int ssp_set(struct task_struct *target, const struct user_regset *regset, |
| 213 | + unsigned int pos, unsigned int count, |
| 214 | + const void *kbuf, const void __user *ubuf) |
| 215 | +{ |
| 216 | + struct fpu *fpu = &target->thread.fpu; |
| 217 | + struct xregs_state *xsave = &fpu->fpstate->regs.xsave; |
| 218 | + struct cet_user_state *cetregs; |
| 219 | + unsigned long user_ssp; |
| 220 | + int r; |
| 221 | + |
| 222 | + if (!cpu_feature_enabled(X86_FEATURE_USER_SHSTK) || |
| 223 | + !ssp_active(target, regset)) |
| 224 | + return -ENODEV; |
| 225 | + |
| 226 | + if (pos != 0 || count != sizeof(user_ssp)) |
| 227 | + return -EINVAL; |
| 228 | + |
| 229 | + r = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &user_ssp, 0, -1); |
| 230 | + if (r) |
| 231 | + return r; |
| 232 | + |
| 233 | + /* |
| 234 | + * Some kernel instructions (IRET, etc) can cause exceptions in the case |
| 235 | + * of disallowed CET register values. Just prevent invalid values. |
| 236 | + */ |
| 237 | + if (user_ssp >= TASK_SIZE_MAX || !IS_ALIGNED(user_ssp, 8)) |
| 238 | + return -EINVAL; |
| 239 | + |
| 240 | + fpu_force_restore(fpu); |
| 241 | + |
| 242 | + cetregs = get_xsave_addr(xsave, XFEATURE_CET_USER); |
| 243 | + if (WARN_ON(!cetregs)) { |
| 244 | + /* |
| 245 | + * This shouldn't ever be NULL because shadow stack was |
| 246 | + * verified to be enabled above. This means |
| 247 | + * MSR_IA32_U_CET.CET_SHSTK_EN should be 1 and so |
| 248 | + * XFEATURE_CET_USER should not be in the init state. |
| 249 | + */ |
| 250 | + return -ENODEV; |
| 251 | + } |
| 252 | + |
| 253 | + cetregs->user_ssp = user_ssp; |
| 254 | + return 0; |
| 255 | +} |
| 256 | +#endif /* CONFIG_X86_USER_SHADOW_STACK */ |
| 257 | + |
177 | 258 | #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
|
178 | 259 |
|
179 | 260 | /*
|
|
0 commit comments