mirror of
git://git.yoctoproject.org/linux-yocto.git
synced 2025-08-21 16:31:14 +02:00

- Make LAM enablement safe vs. kernel threads using a process mm temporarily as switching back to the process would not update CR3 and therefore not enable LAM causing faults in user space when using tagged pointers. Cure it by synchronizing LAM enablement via IPIs to all CPUs which use the related mm. - Cure a LAM harmless inconsistency between CR3 and the state during context switch. It's both confusing and prone to lead to real bugs - Handle alt stack handling for threads which run with a non-zero protection key. The non-zero key prevents the kernel to access the alternate stack. Cure it by temporarily enabling all protection keys for the alternate stack setup/restore operations. - Provide a EFI config table identity mapping for kexec kernel to prevent kexec fails because the new kernel cannot access the config table array - Use GB pages only when a full GB is mapped in the identity map as otherwise the CPU can speculate into reserved areas after the end of memory which causes malfunction on UV systems. - Remove the noisy and pointless SRAT table dump during boot - Use is_ioremap_addr() for iounmap() address range checks instead of high_memory. is_ioremap_addr() is more precise. -----BEGIN PGP SIGNATURE----- iQJHBAABCgAxFiEEQp8+kY+LLUocC4bMphj1TA10mKEFAmbpPpYTHHRnbHhAbGlu dXRyb25peC5kZQAKCRCmGPVMDXSYoYddD/9HeH5/rpWS3JU4ZVC+huY28uJuwAFW ER48zniRbmuz8y+dZZ6K8uvqoWB+ro+yNjA9Jhm9nHUzhs7kE5O8+bmkUi6HXViW 6zS6PW95+u80dmSGy1Gna0SU3158OyBf2X61SySJABLLek7WwrR7jakkgrDBVtL5 ILKS/dUwIrUPoVlszCh9uE0Kj6gdFquooE06sif5EIibnhSgSXfr2EbGj0Qq/YYf FYfpggSSVpTXFSkZSB2VCEqK66jaGUfKzZ6v1DkSioChUCsky2OO6zD9pk0dMixO a/0XvRUo3OhiXZbj1tPUtxaEBgJdigpsxke7xQSVxSl+DNNuapiybpgAzFM5Xh+m yFcP66nIpJcHE10vjVR3jSUlTSb2zk+v9d1Ujj10G1h8RHLTfsTCRHgzs7P0/nkE NJleWstYVRV5rFpPLoY0ryQmjW/PzYokkaqWKI12Lhxg4ojijZso3pS8WfOsk1/B 081tOZERWeGnJEOOJwwYE1wt0Qq8th4S9b2/fz3vk2fsEHIf42s4fKQwy1CxKopb PyIrgnZyWx6ueX9QaIGIzGV1GsY4FKMgFJVOyVb0D0stMnr1ty2m3993eNs/nCXy +rHPMwFteLcwiWp/C3hq5IQd7uEvmRt/mYJ5hdvCj5wCIkXI3JtgsXfLSVs3Ln4f R6HvZehYmbJoNQ== =VZcR -----END PGP SIGNATURE----- Merge tag 'x86-mm-2024-09-17' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip Pull x86 memory management updates from Thomas Gleixner: - Make LAM enablement safe vs. kernel threads using a process mm temporarily as switching back to the process would not update CR3 and therefore not enable LAM causing faults in user space when using tagged pointers. Cure it by synchronizing LAM enablement via IPIs to all CPUs which use the related mm. - Cure a LAM harmless inconsistency between CR3 and the state during context switch. It's both confusing and prone to lead to real bugs - Handle alt stack handling for threads which run with a non-zero protection key. The non-zero key prevents the kernel to access the alternate stack. Cure it by temporarily enabling all protection keys for the alternate stack setup/restore operations. - Provide a EFI config table identity mapping for kexec kernel to prevent kexec fails because the new kernel cannot access the config table array - Use GB pages only when a full GB is mapped in the identity map as otherwise the CPU can speculate into reserved areas after the end of memory which causes malfunction on UV systems. - Remove the noisy and pointless SRAT table dump during boot - Use is_ioremap_addr() for iounmap() address range checks instead of high_memory. is_ioremap_addr() is more precise. * tag 'x86-mm-2024-09-17' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/ioremap: Improve iounmap() address range checks x86/mm: Remove duplicate check from build_cr3() x86/mm: Remove unused NX related declarations x86/mm: Remove unused CR3_HW_ASID_BITS x86/mm: Don't print out SRAT table information x86/mm/ident_map: Use gbpages only where full GB page should be mapped. x86/kexec: Add EFI config table identity mapping for kexec kernel selftests/mm: Add new testcases for pkeys x86/pkeys: Restore altstack access in sigreturn() x86/pkeys: Update PKRU to enable all pkeys before XSAVE x86/pkeys: Add helper functions to update PKRU on the sigframe x86/pkeys: Add PKRU as a parameter in signal handling functions x86/mm: Cleanup prctl_enable_tagged_addr() nr_bits error checking x86/mm: Fix LAM inconsistency during context switch x86/mm: Use IPIs to synchronize LAM enablement
246 lines
5.7 KiB
C
246 lines
5.7 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
#ifndef _PKEYS_HELPER_H
|
|
#define _PKEYS_HELPER_H
|
|
#define _GNU_SOURCE
|
|
#include <string.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <signal.h>
|
|
#include <assert.h>
|
|
#include <stdlib.h>
|
|
#include <ucontext.h>
|
|
#include <sys/mman.h>
|
|
|
|
#include "../kselftest.h"
|
|
|
|
/* Define some kernel-like types */
|
|
#define u8 __u8
|
|
#define u16 __u16
|
|
#define u32 __u32
|
|
#define u64 __u64
|
|
|
|
#define PTR_ERR_ENOTSUP ((void *)-ENOTSUP)
|
|
|
|
#ifndef DEBUG_LEVEL
|
|
#define DEBUG_LEVEL 0
|
|
#endif
|
|
#define DPRINT_IN_SIGNAL_BUF_SIZE 4096
|
|
extern int dprint_in_signal;
|
|
extern char dprint_in_signal_buffer[DPRINT_IN_SIGNAL_BUF_SIZE];
|
|
|
|
extern int test_nr;
|
|
extern int iteration_nr;
|
|
|
|
#ifdef __GNUC__
|
|
__printf(1, 2)
|
|
#endif
|
|
static inline void sigsafe_printf(const char *format, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
if (!dprint_in_signal) {
|
|
va_start(ap, format);
|
|
vprintf(format, ap);
|
|
va_end(ap);
|
|
} else {
|
|
int ret;
|
|
/*
|
|
* No printf() functions are signal-safe.
|
|
* They deadlock easily. Write the format
|
|
* string to get some output, even if
|
|
* incomplete.
|
|
*/
|
|
ret = write(1, format, strlen(format));
|
|
if (ret < 0)
|
|
exit(1);
|
|
}
|
|
}
|
|
#define dprintf_level(level, args...) do { \
|
|
if (level <= DEBUG_LEVEL) \
|
|
sigsafe_printf(args); \
|
|
} while (0)
|
|
#define dprintf0(args...) dprintf_level(0, args)
|
|
#define dprintf1(args...) dprintf_level(1, args)
|
|
#define dprintf2(args...) dprintf_level(2, args)
|
|
#define dprintf3(args...) dprintf_level(3, args)
|
|
#define dprintf4(args...) dprintf_level(4, args)
|
|
|
|
extern void abort_hooks(void);
|
|
#define pkey_assert(condition) do { \
|
|
if (!(condition)) { \
|
|
dprintf0("assert() at %s::%d test_nr: %d iteration: %d\n", \
|
|
__FILE__, __LINE__, \
|
|
test_nr, iteration_nr); \
|
|
dprintf0("errno at assert: %d", errno); \
|
|
abort_hooks(); \
|
|
exit(__LINE__); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define barrier() __asm__ __volatile__("": : :"memory")
|
|
#ifndef noinline
|
|
# define noinline __attribute__((noinline))
|
|
#endif
|
|
|
|
noinline int read_ptr(int *ptr)
|
|
{
|
|
/* Keep GCC from optimizing this away somehow */
|
|
barrier();
|
|
return *ptr;
|
|
}
|
|
|
|
void expected_pkey_fault(int pkey);
|
|
int sys_pkey_alloc(unsigned long flags, unsigned long init_val);
|
|
int sys_pkey_free(unsigned long pkey);
|
|
int mprotect_pkey(void *ptr, size_t size, unsigned long orig_prot,
|
|
unsigned long pkey);
|
|
void record_pkey_malloc(void *ptr, long size, int prot);
|
|
|
|
#if defined(__i386__) || defined(__x86_64__) /* arch */
|
|
#include "pkey-x86.h"
|
|
#elif defined(__powerpc64__) /* arch */
|
|
#include "pkey-powerpc.h"
|
|
#elif defined(__aarch64__) /* arch */
|
|
#include "pkey-arm64.h"
|
|
#else /* arch */
|
|
#error Architecture not supported
|
|
#endif /* arch */
|
|
|
|
#ifndef PKEY_MASK
|
|
#define PKEY_MASK (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE)
|
|
#endif
|
|
|
|
#ifndef set_pkey_bits
|
|
static inline u64 set_pkey_bits(u64 reg, int pkey, u64 flags)
|
|
{
|
|
u32 shift = pkey_bit_position(pkey);
|
|
/* mask out bits from pkey in old value */
|
|
reg &= ~((u64)PKEY_MASK << shift);
|
|
/* OR in new bits for pkey */
|
|
reg |= (flags & PKEY_MASK) << shift;
|
|
return reg;
|
|
}
|
|
#endif
|
|
|
|
#ifndef get_pkey_bits
|
|
static inline u64 get_pkey_bits(u64 reg, int pkey)
|
|
{
|
|
u32 shift = pkey_bit_position(pkey);
|
|
/*
|
|
* shift down the relevant bits to the lowest two, then
|
|
* mask off all the other higher bits
|
|
*/
|
|
return ((reg >> shift) & PKEY_MASK);
|
|
}
|
|
#endif
|
|
|
|
extern u64 shadow_pkey_reg;
|
|
|
|
static inline u64 _read_pkey_reg(int line)
|
|
{
|
|
u64 pkey_reg = __read_pkey_reg();
|
|
|
|
dprintf4("read_pkey_reg(line=%d) pkey_reg: %016llx"
|
|
" shadow: %016llx\n",
|
|
line, pkey_reg, shadow_pkey_reg);
|
|
assert(pkey_reg == shadow_pkey_reg);
|
|
|
|
return pkey_reg;
|
|
}
|
|
|
|
#define read_pkey_reg() _read_pkey_reg(__LINE__)
|
|
|
|
static inline void write_pkey_reg(u64 pkey_reg)
|
|
{
|
|
dprintf4("%s() changing %016llx to %016llx\n", __func__,
|
|
__read_pkey_reg(), pkey_reg);
|
|
/* will do the shadow check for us: */
|
|
read_pkey_reg();
|
|
__write_pkey_reg(pkey_reg);
|
|
shadow_pkey_reg = pkey_reg;
|
|
dprintf4("%s(%016llx) pkey_reg: %016llx\n", __func__,
|
|
pkey_reg, __read_pkey_reg());
|
|
}
|
|
|
|
/*
|
|
* These are technically racy. since something could
|
|
* change PKEY register between the read and the write.
|
|
*/
|
|
static inline void __pkey_access_allow(int pkey, int do_allow)
|
|
{
|
|
u64 pkey_reg = read_pkey_reg();
|
|
int bit = pkey * 2;
|
|
|
|
if (do_allow)
|
|
pkey_reg &= (1<<bit);
|
|
else
|
|
pkey_reg |= (1<<bit);
|
|
|
|
dprintf4("pkey_reg now: %016llx\n", read_pkey_reg());
|
|
write_pkey_reg(pkey_reg);
|
|
}
|
|
|
|
static inline void __pkey_write_allow(int pkey, int do_allow_write)
|
|
{
|
|
u64 pkey_reg = read_pkey_reg();
|
|
int bit = pkey * 2 + 1;
|
|
|
|
if (do_allow_write)
|
|
pkey_reg &= (1<<bit);
|
|
else
|
|
pkey_reg |= (1<<bit);
|
|
|
|
write_pkey_reg(pkey_reg);
|
|
dprintf4("pkey_reg now: %016llx\n", read_pkey_reg());
|
|
}
|
|
|
|
#define ALIGN_UP(x, align_to) (((x) + ((align_to)-1)) & ~((align_to)-1))
|
|
#define ALIGN_DOWN(x, align_to) ((x) & ~((align_to)-1))
|
|
#define ALIGN_PTR_UP(p, ptr_align_to) \
|
|
((typeof(p))ALIGN_UP((unsigned long)(p), ptr_align_to))
|
|
#define ALIGN_PTR_DOWN(p, ptr_align_to) \
|
|
((typeof(p))ALIGN_DOWN((unsigned long)(p), ptr_align_to))
|
|
#define __stringify_1(x...) #x
|
|
#define __stringify(x...) __stringify_1(x)
|
|
|
|
static inline u32 *siginfo_get_pkey_ptr(siginfo_t *si)
|
|
{
|
|
#ifdef si_pkey
|
|
return &si->si_pkey;
|
|
#else
|
|
return (u32 *)(((u8 *)si) + si_pkey_offset);
|
|
#endif
|
|
}
|
|
|
|
static inline int kernel_has_pkeys(void)
|
|
{
|
|
/* try allocating a key and see if it succeeds */
|
|
int ret = sys_pkey_alloc(0, 0);
|
|
if (ret <= 0) {
|
|
return 0;
|
|
}
|
|
sys_pkey_free(ret);
|
|
return 1;
|
|
}
|
|
|
|
static inline int is_pkeys_supported(void)
|
|
{
|
|
/* check if the cpu supports pkeys */
|
|
if (!cpu_has_pkeys()) {
|
|
dprintf1("SKIP: %s: no CPU support\n", __func__);
|
|
return 0;
|
|
}
|
|
|
|
/* check if the kernel supports pkeys */
|
|
if (!kernel_has_pkeys()) {
|
|
dprintf1("SKIP: %s: no kernel support\n", __func__);
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
#endif /* _PKEYS_HELPER_H */
|