4cdb7ba9b6
This patch extends the protection domain framework with an additional plugin to use Task-State Segment (TSS) structures to offload much of the work of switching protection domains to the CPU. This can save space compared to paging, since paging requires two 4KiB page tables and one 32-byte page table plus one whole-system TSS and an additional 32-byte data structure for each protection domain, whereas the approach implemented by this patch just requires a 128-byte data structure for each protection domain. Only a small number of protection domains will typically be used, so n * 128 < 8328 + (n * 32). For additional information, please refer to cpu/x86/mm/README.md. GCC 6 is introducing named address spaces for the FS and GS segments [1]. LLVM Clang also provides address spaces for the FS and GS segments [2]. This patch also adds support to the multi-segment X86 memory management subsystem for using these features instead of inline assembly blocks, which enables type checking to detect some address space mismatches. [1] https://gcc.gnu.org/onlinedocs/gcc/Named-Address-Spaces.html [2] http://llvm.org/releases/3.3/tools/clang/docs/LanguageExtensions.html#target-specific-extensions
143 lines
7 KiB
C
143 lines
7 KiB
C
/*
|
|
* Copyright (C) 2015-2016, Intel Corporation. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* 3. Neither the name of the copyright holder nor the names of its
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#ifndef CPU_X86_MM_SYSCALLS_H_
|
|
#define CPU_X86_MM_SYSCALLS_H_
|
|
|
|
#include "helpers.h"
|
|
#include "prot-domains.h"
|
|
#include <stdbool.h>
|
|
|
|
typedef uint32_t dom_id_bitmap_t;
|
|
|
|
typedef struct syscalls_entrypoint {
|
|
uintptr_t entrypoint;
|
|
dom_id_bitmap_t doms;
|
|
} syscalls_entrypoint_t;
|
|
extern syscalls_entrypoint_t ATTR_KERN_ADDR_SPACE syscalls_entrypoints[];
|
|
extern syscalls_entrypoint_t ATTR_KERN_ADDR_SPACE syscalls_entrypoints_end[];
|
|
|
|
#define SYSCALLS_ACTUAL_CNT (syscalls_entrypoints_end - syscalls_entrypoints)
|
|
|
|
#if X86_CONF_PROT_DOMAINS != X86_CONF_PROT_DOMAINS__NONE
|
|
|
|
#define SYSCALLS_ALLOC_ENTRYPOINT(nm) \
|
|
syscalls_entrypoint_t __attribute__((section(".syscall_bss"))) \
|
|
ATTR_KERN_ADDR_SPACE _syscall_ent_##nm
|
|
|
|
#define SYSCALLS_INIT(nm) \
|
|
KERN_WRITEL(_syscall_ent_##nm.entrypoint, (uintptr_t)_syscall_##nm); \
|
|
KERN_WRITEL(_syscall_ent_##nm.doms, 0)
|
|
|
|
#define SYSCALLS_DEFINE(nm, ...) \
|
|
void _syscall_##nm(__VA_ARGS__); \
|
|
SYSCALLS_STUB(nm); \
|
|
void _syscall_##nm(__VA_ARGS__)
|
|
|
|
#define SYSCALLS_DEFINE_SINGLETON(nm, dcd, ...) \
|
|
void _syscall_##nm(__VA_ARGS__); \
|
|
SYSCALLS_STUB_SINGLETON(nm, dcd); \
|
|
void _syscall_##nm(__VA_ARGS__)
|
|
|
|
#define SYSCALLS_AUTHZ_UPD(nm, drv, set) \
|
|
{ \
|
|
dom_id_t _sc_tmp_id; \
|
|
dom_id_bitmap_t _sc_tmp_bm; \
|
|
KERN_READL(_sc_tmp_id, (drv).dom_id); \
|
|
KERN_READL(_sc_tmp_bm, _syscall_ent_##nm.doms); \
|
|
if(set) { \
|
|
_sc_tmp_bm |= BIT(_sc_tmp_id); \
|
|
} else { \
|
|
_sc_tmp_bm &= ~BIT(_sc_tmp_id); \
|
|
} \
|
|
KERN_WRITEL(_syscall_ent_##nm.doms, _sc_tmp_bm); \
|
|
}
|
|
|
|
/**
|
|
* Check that any untrusted pointer that could have been influenced by a caller
|
|
* (i.e. a stack parameter or global variable) refers to a location at or above
|
|
* a certain stack boundary and halt otherwise. This is used to prevent a
|
|
* protection domain from calling a different protection domain and passing a
|
|
* pointer that references a location in the callee's stack other than its
|
|
* parameters.
|
|
*
|
|
* This also checks that the pointer is either within the stack region or the
|
|
* shared data region, which is important for preventing redirection of data
|
|
* accesses to MMIO or metadata regions. This check is omitted for multi-
|
|
* segment protection domain implementations, since the segment settings
|
|
* already enforce this property for pointers dereferenced in DS. Pointers
|
|
* that can be influenced by a caller should not be dereferenced in any other
|
|
* segment.
|
|
*
|
|
* The pointer is both validated and copied to a new storage location, which
|
|
* must be within the callee's local stack region (excluding the parameter
|
|
* region). This is to mitigate scenarios such as two pointers being validated
|
|
* and an adversary later inducing a write through one of the pointers to the
|
|
* other pointer to corrupt the latter pointer before it is used.
|
|
*
|
|
* The frame address is adjusted to account for the first word pushed on the
|
|
* local frame and the return address, since neither of those should ever be
|
|
* referenced by an incoming pointer. In particular, if an incoming pointer
|
|
* references the return address, it could potentially redirect execution with
|
|
* the privileges of the callee protection domain.
|
|
*/
|
|
#if X86_CONF_PROT_DOMAINS_MULTI_SEG
|
|
#define PROT_DOMAINS_VALIDATE_PTR(validated, untrusted, sz) \
|
|
validated = untrusted; \
|
|
if(((uintptr_t)(validated)) < \
|
|
((2 * sizeof(uintptr_t)) + (uintptr_t)__builtin_frame_address(0))) { \
|
|
halt(); \
|
|
}
|
|
#else
|
|
#define PROT_DOMAINS_VALIDATE_PTR(validated, untrusted, sz) \
|
|
validated = untrusted; \
|
|
if((((uintptr_t)(validated)) < \
|
|
((2 * sizeof(uintptr_t)) + (uintptr_t)__builtin_frame_address(0))) || \
|
|
(((uintptr_t)&_edata_addr) <= (((uintptr_t)(validated)) + (sz)))) { \
|
|
halt(); \
|
|
}
|
|
#endif
|
|
|
|
#else
|
|
|
|
#define SYSCALLS_ALLOC_ENTRYPOINT(nm)
|
|
#define SYSCALLS_INIT(nm)
|
|
#define SYSCALLS_DEFINE(nm, ...) void nm(__VA_ARGS__)
|
|
#define SYSCALLS_DEFINE_SINGLETON(nm, dcd, ...) void nm(__VA_ARGS__)
|
|
#define SYSCALLS_AUTHZ_UPD(nm, drv, set)
|
|
#define PROT_DOMAINS_VALIDATE_PTR(validated, untrusted, sz) validated = untrusted
|
|
|
|
#endif
|
|
|
|
#define SYSCALLS_AUTHZ(nm, drv) SYSCALLS_AUTHZ_UPD(nm, drv, true)
|
|
#define SYSCALLS_DEAUTHZ(nm, drv) SYSCALLS_AUTHZ_UPD(nm, drv, false)
|
|
|
|
#endif /* CPU_X86_MM_SYSCALLS_H_ */
|