https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120008

            Bug ID: 120008
           Summary: RFE: x86: explicit compiler support for SMAP stac/clac
                    (possibly via __attribute__((user))) or similar
           Product: gcc
           Version: unknown
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
          Assignee: unassigned at gcc dot gnu.org
          Reporter: hpa at zytor dot com
  Target Milestone: ---

When doing user space memory references from kernel space, x86 needs to use the
stac and clac instructions to protect those memory references.

Currently, as far as I can tell, there is no support for stac and clac in gcc,
which means the kernel needs to perform them using explicit assembly
statements.

This has several problems:

1. stac/clac, though fairly expensive on existing hardware (estimated 3% of all
kernel time is stac/clac), cannot be CSE'd by the compiler.

2. The compiler not being aware of them means that it cannot move kernel memory
references out of the stac/clac region.

3. The stac/clac asm statements end up having to use a memory clobber or be
marked volatile together which each user space reference. This greatly limits
the flexibility of gcc to optimize around these; furthermore, it makes it far
likely that kernel memory references will remain in the stac/clac region.

The kernel will likely need to continue to use assembly wrappers for the actual
user space reference due to the need for exception fixups, but it would be a
great improvement to have the compiler understand stac and clac, and optionally
the ((user)) attribute which is already used to decorate such pointers in the
kernel via the __user macro (which definition is used depends on the compiler
used [or sparse]):

[include/linux/compiler_types.h]

#define __user          __attribute__((noderef, address_space(__user)))
#define __user __attribute__((user))
#define __user BTF_TYPE_TAG(user)

... where BTF_TYPE_TAG() is defined as:

/*
 * Skipped when running bindgen due to a libclang issue;
 * see https://github.com/rust-lang/rust-bindgen/issues/2244.
 */
#if defined(CONFIG_DEBUG_INFO_BTF) && defined(CONFIG_PAHOLE_HAS_BTF_TAG) && \
        __has_attribute(btf_type_tag) && !defined(__BINDGEN__)
# define BTF_TYPE_TAG(value) __attribute__((btf_type_tag(#value)))
#else
# define BTF_TYPE_TAG(value) /* nothing */
#endif


A user attribute, and letting the compiler generate stac/clac if enabled via
compiler options would be a rather neat solution. Although the kernel needs to
patch out stac and clac at runtime if not supported on the CPU in question,
these instructions could be located by the objtool postprocessor that the
kernel uses.

That being said, we also have a try ... catch ... like mechanism in the kernel
for when a large number of user space references need to be performed in
sequence. It MAY be necessary to add some compiler understanding of those
constructs; if nothing else it would be nice to be able to not have to add
memory clobbers as those affects kernel memory, too. Perhaps the simplest
solution to *that* is to declare __user to be something like "volatile
__attribute__((user))"; user space really is volatile as far as the kernel is
concerned (since other threads can be running in the same address space at the
same time.)

Reply via email to