/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Supervisor Mode Access Prevention support
*
* Copyright (C) 2012 Intel Corporation
* Author: H. Peter Anvin <[email protected]>
*/
#ifndef _ASM_X86_SMAP_H
#define _ASM_X86_SMAP_H
#include <asm/nops.h>
#include <asm/cpufeatures.h>
#include <asm/nospec-branch.h>
#if defined(CONFIG_X86_64) && defined(CONFIG_PAX_MEMORY_UDEREF)
#define ASM_PAX_OPEN_USERLAND "pax_direct_call __pax_open_userland"
#define ASM_PAX_CLOSE_USERLAND "pax_direct_call __pax_close_userland"
#else
#define ASM_PAX_OPEN_USERLAND ""
#define ASM_PAX_CLOSE_USERLAND ""
#endif
/* "Raw" instruction opcodes */
#define __ASM_CLAC ".byte 0x0f,0x01,0xca"
#define __ASM_STAC ".byte 0x0f,0x01,0xcb"
#ifdef __ASSEMBLY__
#define ASM_CLAC \
ALTERNATIVE "", __ASM_CLAC, X86_FEATURE_SMAP
#define ASM_PAX_CLAC __ASM_CLAC
#define ASM_STAC \
ALTERNATIVE "", __ASM_STAC, X86_FEATURE_SMAP
#define ASM_PAX_STAC __ASM_STAC
#define ASM_USER_ACCESS_BEGIN ALTERNATIVE_2 \
ANNOTATE_IGNORE_ALTERNATIVE, \
ASM_PAX_OPEN_USERLAND, \
X86_FEATURE_UDEREF, \
ASM_PAX_STAC, \
X86_FEATURE_SMAP
#define ASM_USER_ACCESS_END ALTERNATIVE_2 \
ANNOTATE_IGNORE_ALTERNATIVE, \
ASM_PAX_CLOSE_USERLAND, \
X86_FEATURE_UDEREF, \
ASM_PAX_CLAC, \
X86_FEATURE_SMAP
#else /* __ASSEMBLY__ */
#define __HAVE_ARCH_PAX_OPEN_USERLAND
#define __HAVE_ARCH_PAX_CLOSE_USERLAND
#if defined(CONFIG_X86_64) && defined(CONFIG_PAX_MEMORY_UDEREF)
noinstr __used __leaf_only __no_caller_saved_registers noinline
void __pax_open_userland(void);
noinstr __used __leaf_only __no_caller_saved_registers noinline
void __pax_close_userland(void);
noinstr noinline
void __pax_save_userland(unsigned long *);
noinstr noinline
void __pax_restore_userland(unsigned long);
#define PAX_OPEN_USERLAND PAX_DIRECT_CALL("%P[open]")
#define PAX_OPEN_USERLAND_CONSTRAINTS : ASM_CALL_CONSTRAINT : [open] "i" (__pax_open_userland) : "memory"
#define PAX_CLOSE_USERLAND PAX_DIRECT_CALL("%P[close]")
#define PAX_CLOSE_USERLAND_CONSTRAINTS : ASM_CALL_CONSTRAINT : [close] "i" (__pax_close_userland) : "memory"
#define PAX_SAVE_USERLAND PAX_DIRECT_CALL("%P[save]")
#define PAX_SAVE_USERLAND_CONSTRAINTS : ASM_CALL_CONSTRAINT, [flags] "=m" (flags) : "D" (&flags), [save] "i" (__pax_save_userland) : "memory", "cc"
#define PAX_RESTORE_USERLAND PAX_DIRECT_CALL("%P[restore]")
#define PAX_RESTORE_USERLAND_CONSTRAINTS : ASM_CALL_CONSTRAINT : [flags] "D" (flags), [restore] "i" (__pax_restore_userland) : "memory", "cc"
#else
#define PAX_OPEN_USERLAND ""
#define PAX_OPEN_USERLAND_CONSTRAINTS : : : "memory"
#define PAX_CLOSE_USERLAND ""
#define PAX_CLOSE_USERLAND_CONSTRAINTS : : : "memory"
#define PAX_SAVE_USERLAND ""
#define PAX_SAVE_USERLAND_CONSTRAINTS : [flags] "=rm" (flags) : : "memory", "cc"
#define PAX_RESTORE_USERLAND ""
#define PAX_RESTORE_USERLAND_CONSTRAINTS :: [flags] "g" (flags) : "memory", "cc"
#endif
#define CLAC __ASM_CLAC
#define STAC __ASM_STAC
static __always_inline unsigned long __user_access_save(void)
{
unsigned long flags;
asm volatile (ALTERNATIVE_2(RAP_SAFE_ASM,
PAX_SAVE_USERLAND,
X86_FEATURE_UDEREF,
"pushf; pop %[flags]; " __ASM_CLAC,
X86_FEATURE_SMAP)
PAX_SAVE_USERLAND_CONSTRAINTS);
return flags;
}
static __always_inline void __user_access_restore(unsigned long flags)
{
asm volatile (ALTERNATIVE_2(RAP_SAFE_ASM,
PAX_RESTORE_USERLAND,
X86_FEATURE_UDEREF,
"push %[flags]; popf",
X86_FEATURE_SMAP)
PAX_RESTORE_USERLAND_CONSTRAINTS);
}
/* These macros can be used in asm() statements */
#define ASM_CLAC \
ALTERNATIVE("", __ASM_CLAC, X86_FEATURE_SMAP)
#define ASM_STAC \
ALTERNATIVE("", __ASM_STAC, X86_FEATURE_SMAP)
#endif /* __ASSEMBLY__ */
#endif /* _ASM_X86_SMAP_H */