1/* SPDX-License-Identifier: GPL-2.0-only */
2/*
3 * Supervisor Mode Access Prevention support
4 *
5 * Copyright (C) 2012 Intel Corporation
6 * Author: H. Peter Anvin <hpa@linux.intel.com>
7 */
8
9#ifndef _ASM_X86_SMAP_H
10#define _ASM_X86_SMAP_H
11
12#include <asm/nops.h>
13#include <asm/cpufeatures.h>
14#include <asm/alternative.h>
15
16#ifdef __ASSEMBLER__
17
18#define ASM_CLAC \
19 ALTERNATIVE "", "clac", X86_FEATURE_SMAP
20
21#define ASM_STAC \
22 ALTERNATIVE "", "stac", X86_FEATURE_SMAP
23
24#else /* __ASSEMBLER__ */
25
26/*
27 * The CLAC/STAC instructions toggle the enforcement of
28 * X86_FEATURE_SMAP along with X86_FEATURE_LASS.
29 *
30 * SMAP enforcement is based on the _PAGE_BIT_USER bit in the page
31 * tables. The kernel is not allowed to touch pages with that bit set
32 * unless the AC bit is set.
33 *
34 * Use stac()/clac() when accessing userspace (_PAGE_USER) mappings,
35 * regardless of location.
36 *
37 * Note: a barrier is implicit in alternative().
38 */
39
40static __always_inline void clac(void)
41{
42 alternative("", "clac", X86_FEATURE_SMAP);
43}
44
45static __always_inline void stac(void)
46{
47 alternative("", "stac", X86_FEATURE_SMAP);
48}
49
50/*
51 * LASS enforcement is based on bit 63 of the virtual address. The
52 * kernel is not allowed to touch memory in the lower half of the
53 * virtual address space.
54 *
55 * Use lass_stac()/lass_clac() to toggle the AC bit for kernel data
56 * accesses (!_PAGE_USER) that are blocked by LASS, but not by SMAP.
57 *
58 * Even with the AC bit set, LASS will continue to block instruction
59 * fetches from the user half of the address space. To allow those,
60 * clear CR4.LASS to disable the LASS mechanism entirely.
61 *
62 * Note: a barrier is implicit in alternative().
63 */
64
65static __always_inline void lass_clac(void)
66{
67 alternative("", "clac", X86_FEATURE_LASS);
68}
69
70static __always_inline void lass_stac(void)
71{
72 alternative("", "stac", X86_FEATURE_LASS);
73}
74
75static __always_inline unsigned long smap_save(void)
76{
77 unsigned long flags;
78
79 asm volatile ("# smap_save\n\t"
80 ALTERNATIVE(ANNOTATE_IGNORE_ALTERNATIVE "\n\t"
81 "", "pushf; pop %0; clac",
82 X86_FEATURE_SMAP)
83 : "=rm" (flags) : : "memory", "cc");
84
85 return flags;
86}
87
88static __always_inline void smap_restore(unsigned long flags)
89{
90 asm volatile ("# smap_restore\n\t"
91 ALTERNATIVE(ANNOTATE_IGNORE_ALTERNATIVE "\n\t"
92 "", "push %0; popf",
93 X86_FEATURE_SMAP)
94 : : "g" (flags) : "memory", "cc");
95}
96
97/* These macros can be used in asm() statements */
98#define ASM_CLAC \
99 ALTERNATIVE("", "clac", X86_FEATURE_SMAP)
100#define ASM_STAC \
101 ALTERNATIVE("", "stac", X86_FEATURE_SMAP)
102
103#define ASM_CLAC_UNSAFE \
104 ALTERNATIVE("", ANNOTATE_IGNORE_ALTERNATIVE "\n\t" "clac", X86_FEATURE_SMAP)
105#define ASM_STAC_UNSAFE \
106 ALTERNATIVE("", ANNOTATE_IGNORE_ALTERNATIVE "\n\t" "stac", X86_FEATURE_SMAP)
107
108#endif /* __ASSEMBLER__ */
109
110#endif /* _ASM_X86_SMAP_H */
111

source code of linux/arch/x86/include/asm/smap.h