mirror of
https://sourceware.org/git/glibc.git
synced 2025-04-24 21:47:24 +03:00
This patch adds a field to ucontext_t to save shadow stack: 1. getcontext and swapcontext are updated to save the caller's shadow stack pointer and return addresses. 2. setcontext and swapcontext are updated to restore shadow stack and jump to new context directly. 3. makecontext is updated to allocate a new shadow stack and set the caller's return address to __start_context. Since makecontext allocates a new shadow stack when making a new context and kernel allocates a new shadow stack for clone/fork/vfork syscalls, we track the current shadow stack base. In setcontext and swapcontext, if the target shadow stack base is the same as the current shadow stack base, we unwind the shadow stack. Otherwise it is a stack switch and we look for a restore token. We enable shadow stack at run-time only if program and all used shared objects, including dlopened ones, are shadow stack enabled, which means that they must be compiled with GCC 8 or above and glibc 2.28 or above. We need to save and restore shadow stack only if shadow stack is enabled. When caller of getcontext, setcontext, swapcontext and makecontext is compiled with smaller ucontext_t, shadow stack won't be enabled at run-time. We check if shadow stack is enabled before accessing the extended field in ucontext_t. Reviewed-by: Carlos O'Donell <carlos@redhat.com> * sysdeps/unix/sysv/linux/x86/sys/ucontext.h (ucontext_t): Add __ssp. * sysdeps/unix/sysv/linux/x86_64/__start_context.S: Include <asm/prctl.h> and "ucontext_i.h" when shadow stack is enabled. (__push___start_context): New. * sysdeps/unix/sysv/linux/x86_64/getcontext.S: Include <asm/prctl.h>. (__getcontext): Record the current shadow stack base. Save the caller's shadow stack pointer and base. * sysdeps/unix/sysv/linux/x86_64/makecontext.c: Include <pthread.h>, <libc-pointer-arith.h> and <sys/prctl.h>. (__push___start_context): New prototype. (__makecontext): Call __push___start_context to allocate a new shadow stack, push __start_context onto the new stack as well as the new shadow stack. * sysdeps/unix/sysv/linux/x86_64/setcontext.S: Include <asm/prctl.h>. (__setcontext): Restore the target shadow stack. * sysdeps/unix/sysv/linux/x86_64/swapcontext.S: Include <asm/prctl.h>. (__swapcontext): Record the current shadow stack base. Save the caller's shadow stack pointer and base. Restore the target shadow stack. * sysdeps/unix/sysv/linux/x86_64/sysdep.h (STACK_SIZE_TO_SHADOW_STACK_SIZE_SHIFT): New. * sysdeps/unix/sysv/linux/x86_64/ucontext_i.sym (oSSP): New.
263 lines
5.7 KiB
C
263 lines
5.7 KiB
C
/* Copyright (C) 2001-2018 Free Software Foundation, Inc.
|
|
This file is part of the GNU C Library.
|
|
|
|
The GNU C Library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
The GNU C Library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with the GNU C Library; if not, see
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
#ifndef _SYS_UCONTEXT_H
|
|
#define _SYS_UCONTEXT_H 1
|
|
|
|
#include <features.h>
|
|
|
|
#include <bits/types.h>
|
|
#include <bits/types/sigset_t.h>
|
|
#include <bits/types/stack_t.h>
|
|
|
|
|
|
#ifdef __USE_MISC
|
|
# define __ctx(fld) fld
|
|
#else
|
|
# define __ctx(fld) __ ## fld
|
|
#endif
|
|
|
|
#ifdef __x86_64__
|
|
|
|
/* Type for general register. */
|
|
__extension__ typedef long long int greg_t;
|
|
|
|
/* Number of general registers. */
|
|
#define __NGREG 23
|
|
#ifdef __USE_MISC
|
|
# define NGREG __NGREG
|
|
#endif
|
|
|
|
/* Container for all general registers. */
|
|
typedef greg_t gregset_t[__NGREG];
|
|
|
|
#ifdef __USE_GNU
|
|
/* Number of each register in the `gregset_t' array. */
|
|
enum
|
|
{
|
|
REG_R8 = 0,
|
|
# define REG_R8 REG_R8
|
|
REG_R9,
|
|
# define REG_R9 REG_R9
|
|
REG_R10,
|
|
# define REG_R10 REG_R10
|
|
REG_R11,
|
|
# define REG_R11 REG_R11
|
|
REG_R12,
|
|
# define REG_R12 REG_R12
|
|
REG_R13,
|
|
# define REG_R13 REG_R13
|
|
REG_R14,
|
|
# define REG_R14 REG_R14
|
|
REG_R15,
|
|
# define REG_R15 REG_R15
|
|
REG_RDI,
|
|
# define REG_RDI REG_RDI
|
|
REG_RSI,
|
|
# define REG_RSI REG_RSI
|
|
REG_RBP,
|
|
# define REG_RBP REG_RBP
|
|
REG_RBX,
|
|
# define REG_RBX REG_RBX
|
|
REG_RDX,
|
|
# define REG_RDX REG_RDX
|
|
REG_RAX,
|
|
# define REG_RAX REG_RAX
|
|
REG_RCX,
|
|
# define REG_RCX REG_RCX
|
|
REG_RSP,
|
|
# define REG_RSP REG_RSP
|
|
REG_RIP,
|
|
# define REG_RIP REG_RIP
|
|
REG_EFL,
|
|
# define REG_EFL REG_EFL
|
|
REG_CSGSFS, /* Actually short cs, gs, fs, __pad0. */
|
|
# define REG_CSGSFS REG_CSGSFS
|
|
REG_ERR,
|
|
# define REG_ERR REG_ERR
|
|
REG_TRAPNO,
|
|
# define REG_TRAPNO REG_TRAPNO
|
|
REG_OLDMASK,
|
|
# define REG_OLDMASK REG_OLDMASK
|
|
REG_CR2
|
|
# define REG_CR2 REG_CR2
|
|
};
|
|
#endif
|
|
|
|
struct _libc_fpxreg
|
|
{
|
|
unsigned short int __ctx(significand)[4];
|
|
unsigned short int __ctx(exponent);
|
|
unsigned short int __glibc_reserved1[3];
|
|
};
|
|
|
|
struct _libc_xmmreg
|
|
{
|
|
__uint32_t __ctx(element)[4];
|
|
};
|
|
|
|
struct _libc_fpstate
|
|
{
|
|
/* 64-bit FXSAVE format. */
|
|
__uint16_t __ctx(cwd);
|
|
__uint16_t __ctx(swd);
|
|
__uint16_t __ctx(ftw);
|
|
__uint16_t __ctx(fop);
|
|
__uint64_t __ctx(rip);
|
|
__uint64_t __ctx(rdp);
|
|
__uint32_t __ctx(mxcsr);
|
|
__uint32_t __ctx(mxcr_mask);
|
|
struct _libc_fpxreg _st[8];
|
|
struct _libc_xmmreg _xmm[16];
|
|
__uint32_t __glibc_reserved1[24];
|
|
};
|
|
|
|
/* Structure to describe FPU registers. */
|
|
typedef struct _libc_fpstate *fpregset_t;
|
|
|
|
/* Context to describe whole processor state. */
|
|
typedef struct
|
|
{
|
|
gregset_t __ctx(gregs);
|
|
/* Note that fpregs is a pointer. */
|
|
fpregset_t __ctx(fpregs);
|
|
__extension__ unsigned long long __reserved1 [8];
|
|
} mcontext_t;
|
|
|
|
/* Userlevel context. */
|
|
typedef struct ucontext_t
|
|
{
|
|
unsigned long int __ctx(uc_flags);
|
|
struct ucontext_t *uc_link;
|
|
stack_t uc_stack;
|
|
mcontext_t uc_mcontext;
|
|
sigset_t uc_sigmask;
|
|
struct _libc_fpstate __fpregs_mem;
|
|
__extension__ unsigned long long int __ssp[4];
|
|
} ucontext_t;
|
|
|
|
#else /* !__x86_64__ */
|
|
|
|
/* Type for general register. */
|
|
typedef int greg_t;
|
|
|
|
/* Number of general registers. */
|
|
#define __NGREG 19
|
|
#ifdef __USE_MISC
|
|
# define NGREG __NGREG
|
|
#endif
|
|
|
|
/* Container for all general registers. */
|
|
typedef greg_t gregset_t[__NGREG];
|
|
|
|
#ifdef __USE_GNU
|
|
/* Number of each register is the `gregset_t' array. */
|
|
enum
|
|
{
|
|
REG_GS = 0,
|
|
# define REG_GS REG_GS
|
|
REG_FS,
|
|
# define REG_FS REG_FS
|
|
REG_ES,
|
|
# define REG_ES REG_ES
|
|
REG_DS,
|
|
# define REG_DS REG_DS
|
|
REG_EDI,
|
|
# define REG_EDI REG_EDI
|
|
REG_ESI,
|
|
# define REG_ESI REG_ESI
|
|
REG_EBP,
|
|
# define REG_EBP REG_EBP
|
|
REG_ESP,
|
|
# define REG_ESP REG_ESP
|
|
REG_EBX,
|
|
# define REG_EBX REG_EBX
|
|
REG_EDX,
|
|
# define REG_EDX REG_EDX
|
|
REG_ECX,
|
|
# define REG_ECX REG_ECX
|
|
REG_EAX,
|
|
# define REG_EAX REG_EAX
|
|
REG_TRAPNO,
|
|
# define REG_TRAPNO REG_TRAPNO
|
|
REG_ERR,
|
|
# define REG_ERR REG_ERR
|
|
REG_EIP,
|
|
# define REG_EIP REG_EIP
|
|
REG_CS,
|
|
# define REG_CS REG_CS
|
|
REG_EFL,
|
|
# define REG_EFL REG_EFL
|
|
REG_UESP,
|
|
# define REG_UESP REG_UESP
|
|
REG_SS
|
|
# define REG_SS REG_SS
|
|
};
|
|
#endif
|
|
|
|
/* Definitions taken from the kernel headers. */
|
|
struct _libc_fpreg
|
|
{
|
|
unsigned short int __ctx(significand)[4];
|
|
unsigned short int __ctx(exponent);
|
|
};
|
|
|
|
struct _libc_fpstate
|
|
{
|
|
unsigned long int __ctx(cw);
|
|
unsigned long int __ctx(sw);
|
|
unsigned long int __ctx(tag);
|
|
unsigned long int __ctx(ipoff);
|
|
unsigned long int __ctx(cssel);
|
|
unsigned long int __ctx(dataoff);
|
|
unsigned long int __ctx(datasel);
|
|
struct _libc_fpreg _st[8];
|
|
unsigned long int __ctx(status);
|
|
};
|
|
|
|
/* Structure to describe FPU registers. */
|
|
typedef struct _libc_fpstate *fpregset_t;
|
|
|
|
/* Context to describe whole processor state. */
|
|
typedef struct
|
|
{
|
|
gregset_t __ctx(gregs);
|
|
/* Due to Linux's history we have to use a pointer here. The SysV/i386
|
|
ABI requires a struct with the values. */
|
|
fpregset_t __ctx(fpregs);
|
|
unsigned long int __ctx(oldmask);
|
|
unsigned long int __ctx(cr2);
|
|
} mcontext_t;
|
|
|
|
/* Userlevel context. */
|
|
typedef struct ucontext_t
|
|
{
|
|
unsigned long int __ctx(uc_flags);
|
|
struct ucontext_t *uc_link;
|
|
stack_t uc_stack;
|
|
mcontext_t uc_mcontext;
|
|
sigset_t uc_sigmask;
|
|
struct _libc_fpstate __fpregs_mem;
|
|
unsigned long int __ssp[4];
|
|
} ucontext_t;
|
|
|
|
#endif /* !__x86_64__ */
|
|
|
|
#undef __ctx
|
|
|
|
#endif /* sys/ucontext.h */
|