mirror of
https://github.com/torvalds/linux.git
synced 2024-12-25 12:21:37 +00:00
a5e090acbf
Provide a software-based implementation of the priviledged no access support found in ARMv8.1. Userspace pages are mapped using a different domain number from the kernel and IO mappings. If we switch the user domain to "no access" when we enter the kernel, we can prevent the kernel from touching userspace. However, the kernel needs to be able to access userspace via the various user accessor functions. With the wrapping in the previous patch, we can temporarily enable access when the kernel needs user access, and re-disable it afterwards. This allows us to trap non-intended accesses to userspace, eg, caused by an inadvertent dereference of the LIST_POISON* values, which, with appropriate user mappings setup, can be made to succeed. This in turn can allow use-after-free bugs to be further exploited than would otherwise be possible. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
143 lines
3.4 KiB
C
143 lines
3.4 KiB
C
/*
|
|
* arch/arm/include/asm/domain.h
|
|
*
|
|
* Copyright (C) 1999 Russell King.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*/
|
|
#ifndef __ASM_PROC_DOMAIN_H
|
|
#define __ASM_PROC_DOMAIN_H
|
|
|
|
#ifndef __ASSEMBLY__
|
|
#include <asm/barrier.h>
|
|
#endif
|
|
|
|
/*
|
|
* Domain numbers
|
|
*
|
|
* DOMAIN_IO - domain 2 includes all IO only
|
|
* DOMAIN_USER - domain 1 includes all user memory only
|
|
* DOMAIN_KERNEL - domain 0 includes all kernel memory only
|
|
*
|
|
* The domain numbering depends on whether we support 36 physical
|
|
* address for I/O or not. Addresses above the 32 bit boundary can
|
|
* only be mapped using supersections and supersections can only
|
|
* be set for domain 0. We could just default to DOMAIN_IO as zero,
|
|
* but there may be systems with supersection support and no 36-bit
|
|
* addressing. In such cases, we want to map system memory with
|
|
* supersections to reduce TLB misses and footprint.
|
|
*
|
|
* 36-bit addressing and supersections are only available on
|
|
* CPUs based on ARMv6+ or the Intel XSC3 core.
|
|
*/
|
|
#ifndef CONFIG_IO_36
|
|
#define DOMAIN_KERNEL 0
|
|
#define DOMAIN_USER 1
|
|
#define DOMAIN_IO 2
|
|
#else
|
|
#define DOMAIN_KERNEL 2
|
|
#define DOMAIN_USER 1
|
|
#define DOMAIN_IO 0
|
|
#endif
|
|
#define DOMAIN_VECTORS 3
|
|
|
|
/*
|
|
* Domain types
|
|
*/
|
|
#define DOMAIN_NOACCESS 0
|
|
#define DOMAIN_CLIENT 1
|
|
#ifdef CONFIG_CPU_USE_DOMAINS
|
|
#define DOMAIN_MANAGER 3
|
|
#else
|
|
#define DOMAIN_MANAGER 1
|
|
#endif
|
|
|
|
#define domain_mask(dom) ((3) << (2 * (dom)))
|
|
#define domain_val(dom,type) ((type) << (2 * (dom)))
|
|
|
|
#ifdef CONFIG_CPU_SW_DOMAIN_PAN
|
|
#define DACR_INIT \
|
|
(domain_val(DOMAIN_USER, DOMAIN_NOACCESS) | \
|
|
domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \
|
|
domain_val(DOMAIN_IO, DOMAIN_CLIENT) | \
|
|
domain_val(DOMAIN_VECTORS, DOMAIN_CLIENT))
|
|
#else
|
|
#define DACR_INIT \
|
|
(domain_val(DOMAIN_USER, DOMAIN_CLIENT) | \
|
|
domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \
|
|
domain_val(DOMAIN_IO, DOMAIN_CLIENT) | \
|
|
domain_val(DOMAIN_VECTORS, DOMAIN_CLIENT))
|
|
#endif
|
|
|
|
#define __DACR_DEFAULT \
|
|
domain_val(DOMAIN_KERNEL, DOMAIN_CLIENT) | \
|
|
domain_val(DOMAIN_IO, DOMAIN_CLIENT) | \
|
|
domain_val(DOMAIN_VECTORS, DOMAIN_CLIENT)
|
|
|
|
#define DACR_UACCESS_DISABLE \
|
|
(__DACR_DEFAULT | domain_val(DOMAIN_USER, DOMAIN_NOACCESS))
|
|
#define DACR_UACCESS_ENABLE \
|
|
(__DACR_DEFAULT | domain_val(DOMAIN_USER, DOMAIN_CLIENT))
|
|
|
|
#ifndef __ASSEMBLY__
|
|
|
|
static inline unsigned int get_domain(void)
|
|
{
|
|
unsigned int domain;
|
|
|
|
asm(
|
|
"mrc p15, 0, %0, c3, c0 @ get domain"
|
|
: "=r" (domain));
|
|
|
|
return domain;
|
|
}
|
|
|
|
static inline void set_domain(unsigned val)
|
|
{
|
|
asm volatile(
|
|
"mcr p15, 0, %0, c3, c0 @ set domain"
|
|
: : "r" (val));
|
|
isb();
|
|
}
|
|
|
|
#ifdef CONFIG_CPU_USE_DOMAINS
|
|
#define modify_domain(dom,type) \
|
|
do { \
|
|
unsigned int domain = get_domain(); \
|
|
domain &= ~domain_mask(dom); \
|
|
domain = domain | domain_val(dom, type); \
|
|
set_domain(domain); \
|
|
} while (0)
|
|
|
|
#else
|
|
static inline void modify_domain(unsigned dom, unsigned type) { }
|
|
#endif
|
|
|
|
/*
|
|
* Generate the T (user) versions of the LDR/STR and related
|
|
* instructions (inline assembly)
|
|
*/
|
|
#ifdef CONFIG_CPU_USE_DOMAINS
|
|
#define TUSER(instr) #instr "t"
|
|
#else
|
|
#define TUSER(instr) #instr
|
|
#endif
|
|
|
|
#else /* __ASSEMBLY__ */
|
|
|
|
/*
|
|
* Generate the T (user) versions of the LDR/STR and related
|
|
* instructions
|
|
*/
|
|
#ifdef CONFIG_CPU_USE_DOMAINS
|
|
#define TUSER(instr) instr ## t
|
|
#else
|
|
#define TUSER(instr) instr
|
|
#endif
|
|
|
|
#endif /* __ASSEMBLY__ */
|
|
|
|
#endif /* !__ASM_PROC_DOMAIN_H */
|