Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
*.lds
*.so
*.so.dbg
vdso*-image*.c
vdso2c
+12
View File
@@ -0,0 +1,12 @@
# SPDX-License-Identifier: GPL-2.0
#
# Building vDSO images for x86.
#
# Regular kernel objects
obj-y := vma.o extable.o
obj-$(CONFIG_COMPAT_32) += vdso32-setup.o
# vDSO directories
obj-$(CONFIG_X86_64) += vdso64/
obj-$(CONFIG_COMPAT_32) += vdso32/
@@ -0,0 +1,89 @@
# SPDX-License-Identifier: GPL-2.0
#
# Building vDSO images for x86.
#
# Include the generic Makefile to check the built vDSO:
include $(srctree)/lib/vdso/Makefile.include
obj-y += $(foreach x,$(vdsos-y),vdso$(x)-image.o)
targets += $(foreach x,$(vdsos-y),vdso$(x)-image.c vdso$(x).so vdso$(x).so.dbg vdso$(x).lds)
targets += $(vobjs-y)
# vobjs-y with $(obj)/ prepended
vobjs := $(addprefix $(obj)/,$(vobjs-y))
# Options for vdso*.lds
CPPFLAGS_VDSO_LDS := -P -C -I$(src)/..
$(obj)/%.lds : KBUILD_CPPFLAGS += $(CPPFLAGS_VDSO_LDS)
#
# Options from KBUILD_[AC]FLAGS that should *NOT* be kept
#
flags-remove-y += \
-D__KERNEL__ -mcmodel=kernel -mregparm=3 \
-fno-pic -fno-PIC -fno-pie -fno-PIE \
-mfentry -pg \
$(RANDSTRUCT_CFLAGS) $(GCC_PLUGINS_CFLAGS) $(KSTACK_ERASE_CFLAGS) \
$(RETPOLINE_CFLAGS) $(CC_FLAGS_LTO) $(CC_FLAGS_CFI) \
$(PADDING_CFLAGS)
#
# Don't omit frame pointers for ease of userspace debugging, but do
# optimize sibling calls.
#
flags-y += -D__DISABLE_EXPORTS
flags-y += -DDISABLE_BRANCH_PROFILING
flags-y += -DBUILD_VDSO
flags-y += -I$(src)/.. -I$(srctree)
flags-y += -O2 -fpic
flags-y += -fno-stack-protector
flags-y += -fno-omit-frame-pointer
flags-y += -foptimize-sibling-calls
flags-y += -fasynchronous-unwind-tables
# Reset cf protections enabled by compiler default
flags-y += $(call cc-option, -fcf-protection=none)
flags-$(X86_USER_SHADOW_STACK) += $(call cc-option, -fcf-protection=return)
# When user space IBT is supported, enable this.
# flags-$(CONFIG_USER_IBT) += $(call cc-option, -fcf-protection=branch)
flags-$(CONFIG_MITIGATION_RETPOLINE) += $(RETPOLINE_VDSO_CFLAGS)
# These need to be conditional on $(vobjs) as they do not apply to
# the output vdso*-image.o files which are standard kernel objects.
$(vobjs) : KBUILD_AFLAGS := \
$(filter-out $(flags-remove-y),$(KBUILD_AFLAGS)) $(flags-y)
$(vobjs) : KBUILD_CFLAGS := \
$(filter-out $(flags-remove-y),$(KBUILD_CFLAGS)) $(flags-y)
#
# The VDSO images are built using a special linker script.
#
VDSO_LDFLAGS := -shared --hash-style=both --build-id=sha1 --no-undefined \
$(call ld-option, --eh-frame-hdr) -Bsymbolic -z noexecstack
quiet_cmd_vdso = VDSO $@
cmd_vdso = $(LD) -o $@ \
$(VDSO_LDFLAGS) $(VDSO_LDFLAGS_$*) \
-T $(filter %.lds,$^) $(filter %.o,$^)
quiet_cmd_vdso_and_check = VDSO $@
cmd_vdso_and_check = $(cmd_vdso); $(cmd_vdso_check)
$(obj)/vdso%.so.dbg: $(obj)/vdso%.lds FORCE
$(call if_changed,vdso_and_check)
$(obj)/%.so: OBJCOPYFLAGS := -S --remove-section __ex_table
$(obj)/%.so: $(obj)/%.so.dbg FORCE
$(call if_changed,objcopy)
VDSO2C = $(objtree)/arch/x86/tools/vdso2c
quiet_cmd_vdso2c = VDSO2C $@
cmd_vdso2c = $(VDSO2C) $< $(<:%.dbg=%) $@
$(obj)/%-image.c: $(obj)/%.so.dbg $(obj)/%.so $(VDSO2C) FORCE
$(call if_changed,vdso2c)
$(obj)/%-image.o: $(obj)/%-image.c
@@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* This supplies .note.* sections to go into the PT_NOTE inside the vDSO text.
* Here we can supply some information useful to userland.
*/
#include <linux/build-salt.h>
#include <linux/version.h>
#include <linux/elfnote.h>
/* Ideally this would use UTS_NAME, but using a quoted string here
doesn't work. Remember to change this when changing the
kernel's name. */
ELFNOTE_START(Linux, 0, "a")
.long LINUX_VERSION_CODE
ELFNOTE_END
BUILD_SALT
@@ -0,0 +1,85 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Fast user context implementation of clock_gettime, gettimeofday, and time.
*
* Copyright 2006 Andi Kleen, SUSE Labs.
* Copyright 2019 ARM Limited
*
* 32 Bit compat layer by Stefani Seibold <stefani@seibold.net>
* sponsored by Rohde & Schwarz GmbH & Co. KG Munich/Germany
*/
#include <linux/time.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <vdso/gettime.h>
#include "lib/vdso/gettimeofday.c"
int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz)
{
return __cvdso_gettimeofday(tv, tz);
}
int gettimeofday(struct __kernel_old_timeval *, struct timezone *)
__attribute__((weak, alias("__vdso_gettimeofday")));
__kernel_old_time_t __vdso_time(__kernel_old_time_t *t)
{
return __cvdso_time(t);
}
__kernel_old_time_t time(__kernel_old_time_t *t) __attribute__((weak, alias("__vdso_time")));
#if defined(CONFIG_X86_64) && !defined(BUILD_VDSO32_64)
/* both 64-bit and x32 use these */
int __vdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts)
{
return __cvdso_clock_gettime(clock, ts);
}
int clock_gettime(clockid_t, struct __kernel_timespec *)
__attribute__((weak, alias("__vdso_clock_gettime")));
int __vdso_clock_getres(clockid_t clock,
struct __kernel_timespec *res)
{
return __cvdso_clock_getres(clock, res);
}
int clock_getres(clockid_t, struct __kernel_timespec *)
__attribute__((weak, alias("__vdso_clock_getres")));
#else
/* i386 only */
int __vdso_clock_gettime(clockid_t clock, struct old_timespec32 *ts)
{
return __cvdso_clock_gettime32(clock, ts);
}
int clock_gettime(clockid_t, struct old_timespec32 *)
__attribute__((weak, alias("__vdso_clock_gettime")));
int __vdso_clock_gettime64(clockid_t clock, struct __kernel_timespec *ts)
{
return __cvdso_clock_gettime(clock, ts);
}
int clock_gettime64(clockid_t, struct __kernel_timespec *)
__attribute__((weak, alias("__vdso_clock_gettime64")));
int __vdso_clock_getres(clockid_t clock, struct old_timespec32 *res)
{
return __cvdso_clock_getres_time32(clock, res);
}
int clock_getres(clockid_t, struct old_timespec32 *)
__attribute__((weak, alias("__vdso_clock_getres")));
int __vdso_clock_getres_time64(clockid_t clock, struct __kernel_timespec *ts)
{
return __cvdso_clock_getres(clock, ts);
}
int clock_getres_time64(clockid_t, struct __kernel_timespec *)
__attribute__((weak, alias("__vdso_clock_getres_time64")));
#endif
@@ -0,0 +1,109 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <asm/vdso.h>
#include <asm/vdso/vsyscall.h>
#include <vdso/datapage.h>
/*
* Linker script for vDSO. This is an ELF shared object prelinked to
* its virtual address, and with only one read-only segment.
* This script controls its layout.
*/
SECTIONS
{
/*
* User/kernel shared data is before the vDSO. This may be a little
* uglier than putting it after the vDSO, but it avoids issues with
* non-allocatable things that dangle past the end of the PT_LOAD
* segment.
*/
VDSO_VVAR_SYMS
vclock_pages = VDSO_VCLOCK_PAGES_START(vdso_u_data);
pvclock_page = vclock_pages + VDSO_PAGE_PVCLOCK_OFFSET * PAGE_SIZE;
hvclock_page = vclock_pages + VDSO_PAGE_HVCLOCK_OFFSET * PAGE_SIZE;
. = SIZEOF_HEADERS;
.hash : { *(.hash) } :text
.gnu.hash : { *(.gnu.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.dynamic : { *(.dynamic) } :text :dynamic
.rodata : {
*(.rodata*)
*(.data*)
*(.sdata*)
*(.got.plt) *(.got)
*(.gnu.linkonce.d.*)
*(.bss*)
*(.dynbss*)
*(.gnu.linkonce.b.*)
} :text
.note.gnu.property : {
*(.note.gnu.property)
} :text :note :gnu_property
.note : {
*(.note*)
} :text :note
.eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
.eh_frame : {
KEEP (*(.eh_frame))
*(.eh_frame.*)
} :text
/*
* Text is well-separated from actual data: there's plenty of
* stuff that isn't used at runtime in between.
*/
.text : {
*(.text*)
} :text =0x90909090,
.altinstructions : { *(.altinstructions) } :text
.altinstr_replacement : { *(.altinstr_replacement) } :text
__ex_table : { *(__ex_table) } :text
/DISCARD/ : {
*(.discard)
*(.discard.*)
*(__bug_table)
}
}
/*
* Very old versions of ld do not recognize this name token; use the constant.
*/
#define PT_GNU_EH_FRAME 0x6474e550
#define PT_GNU_STACK 0x6474e551
#define PT_GNU_PROPERTY 0x6474e553
/*
* We must supply the ELF program headers explicitly to get just one
* PT_LOAD segment, and set the flags explicitly to make segments read-only.
*/
#define PF_R FLAGS(4)
#define PF_RW FLAGS(6)
#define PF_RX FLAGS(5)
PHDRS
{
text PT_LOAD PF_RX FILEHDR PHDRS;
dynamic PT_DYNAMIC PF_R;
note PT_NOTE PF_R;
eh_frame_hdr PT_GNU_EH_FRAME PF_R;
gnu_stack PT_GNU_STACK PF_RW;
gnu_property PT_GNU_PROPERTY PF_R;
}
@@ -0,0 +1,71 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <vdso/futex.h>
/*
* Assembly template for the try unlock functions. The basic functionality is:
*
* mov esi, %eax Move the TID into EAX
* xor %ecx, %ecx Clear ECX
* lock_cmpxchgl %ecx, (%rdi) Attempt the TID -> 0 transition
* .Lcs_start: Start of the critical section
* jnz .Lcs_end If cmpxchl failed jump to the end
* .Lcs_success: Start of the success section
* movq %rcx, (%rdx) Set the pending op pointer to 0
* .Lcs_end: End of the critical section
*
* .Lcs_start and .Lcs_end establish the critical section range. .Lcs_success is
* technically not required, but there for illustration, debugging and testing.
*
* When CONFIG_COMPAT is enabled then the 64-bit VDSO provides two functions.
* One for the regular 64-bit sized pending operation pointer and one for a
* 32-bit sized pointer to support gaming emulators.
*
* The 32-bit VDSO provides only the one for 32-bit sized pointers.
*/
#define __stringify_1(x...) #x
#define __stringify(x...) __stringify_1(x)
#define LABEL(prefix, which) __stringify(prefix##_try_unlock_cs_##which:)
#define JNZ_END(prefix) "jnz " __stringify(prefix) "_try_unlock_cs_end\n"
#define CLEAR_POPQ "movq %[zero], %a[pop]\n"
#define CLEAR_POPL "movl %k[zero], %a[pop]\n"
#define futex_robust_try_unlock(prefix, clear_pop, __lock, __tid, __pop)\
({ \
asm volatile ( \
" \n" \
" lock cmpxchgl %k[zero], %a[lock] \n" \
" \n" \
LABEL(prefix, start) \
" \n" \
JNZ_END(prefix) \
" \n" \
LABEL(prefix, success) \
" \n" \
clear_pop \
" \n" \
LABEL(prefix, end) \
: [tid] "+&a" (__tid) \
: [lock] "D" (__lock), \
[pop] "d" (__pop), \
[zero] "r" (0UL) \
: "memory" \
); \
__tid; \
})
#ifdef __x86_64__
__u32 __vdso_futex_robust_list64_try_unlock(__u32 *lock, __u32 tid, __u64 *pop)
{
return futex_robust_try_unlock(__futex_list64, CLEAR_POPQ, lock, tid, pop);
}
#endif /* __x86_64__ */
#if defined(CONFIG_X86_32) || defined(CONFIG_COMPAT)
__u32 __vdso_futex_robust_list32_try_unlock(__u32 *lock, __u32 tid, __u32 *pop)
{
return futex_robust_try_unlock(__futex_list32, CLEAR_POPL, lock, tid, pop);
}
#endif /* CONFIG_X86_32 || CONFIG_COMPAT */
@@ -0,0 +1,21 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2006 Andi Kleen, SUSE Labs.
*
* Fast user context implementation of getcpu()
*/
#include <linux/kernel.h>
#include <asm/segment.h>
#include <vdso/processor.h>
notrace long
__vdso_getcpu(unsigned *cpu, unsigned *node, void *unused)
{
vdso_read_cpunode(cpu, node);
return 0;
}
long getcpu(unsigned *cpu, unsigned *node, void *tcache)
__attribute__((weak, alias("__vdso_getcpu")));
+46
View File
@@ -0,0 +1,46 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/err.h>
#include <linux/mm.h>
#include <asm/current.h>
#include <asm/traps.h>
#include <asm/vdso.h>
struct vdso_exception_table_entry {
int insn, fixup;
};
bool fixup_vdso_exception(struct pt_regs *regs, int trapnr,
unsigned long error_code, unsigned long fault_addr)
{
const struct vdso_image *image = current->mm->context.vdso_image;
const struct vdso_exception_table_entry *extable;
unsigned int nr_entries, i;
unsigned long base;
/*
* Do not attempt to fixup #DB or #BP. It's impossible to identify
* whether or not a #DB/#BP originated from within an SGX enclave and
* SGX enclaves are currently the only use case for vDSO fixup.
*/
if (trapnr == X86_TRAP_DB || trapnr == X86_TRAP_BP)
return false;
if (!current->mm->context.vdso)
return false;
base = (unsigned long)current->mm->context.vdso + image->extable_base;
nr_entries = image->extable_len / (sizeof(*extable));
extable = image->extable;
for (i = 0; i < nr_entries; i++) {
if (regs->ip == base + extable[i].insn) {
regs->ip = base + extable[i].fixup;
regs->di = trapnr;
regs->si = error_code;
regs->dx = fault_addr;
return true;
}
}
return false;
}
+28
View File
@@ -0,0 +1,28 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __VDSO_EXTABLE_H
#define __VDSO_EXTABLE_H
/*
* Inject exception fixup for vDSO code. Unlike normal exception fixup,
* vDSO uses a dedicated handler the addresses are relative to the overall
* exception table, not each individual entry.
*/
#ifdef __ASSEMBLER__
#define _ASM_VDSO_EXTABLE_HANDLE(from, to) \
ASM_VDSO_EXTABLE_HANDLE from to
.macro ASM_VDSO_EXTABLE_HANDLE from:req to:req
.pushsection __ex_table, "a"
.long (\from) - __ex_table
.long (\to) - __ex_table
.popsection
.endm
#else
#define _ASM_VDSO_EXTABLE_HANDLE(from, to) \
".pushsection __ex_table, \"a\"\n" \
".long (" #from ") - __ex_table\n" \
".long (" #to ") - __ex_table\n" \
".popsection\n"
#endif
#endif /* __VDSO_EXTABLE_H */
@@ -0,0 +1,86 @@
// SPDX-License-Identifier: GPL-2.0
/*
* (C) Copyright 2002 Linus Torvalds
* Portions based on the vdso-randomization code from exec-shield:
* Copyright(C) 2005-2006, Red Hat, Inc., Ingo Molnar
*
* This file contains the needed initializations to support sysenter.
*/
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/kernel.h>
#include <linux/mm_types.h>
#include <linux/elf.h>
#include <asm/processor.h>
#include <asm/vdso.h>
#ifdef CONFIG_COMPAT_VDSO
#define VDSO_DEFAULT 0
#else
#define VDSO_DEFAULT 1
#endif
/*
* Should the kernel map a VDSO page into processes and pass its
* address down to glibc upon exec()?
*/
unsigned int __read_mostly vdso32_enabled = VDSO_DEFAULT;
static int __init vdso32_setup(char *s)
{
vdso32_enabled = simple_strtoul(s, NULL, 0);
if (vdso32_enabled > 1) {
pr_warn("vdso32 values other than 0 and 1 are no longer allowed; vdso disabled\n");
vdso32_enabled = 0;
}
return 1;
}
/*
* For consistency, the argument vdso32=[012] affects the 32-bit vDSO
* behavior on both 64-bit and 32-bit kernels.
* On 32-bit kernels, vdso=[012] means the same thing.
*/
__setup("vdso32=", vdso32_setup);
#ifdef CONFIG_X86_32
__setup_param("vdso=", vdso_setup, vdso32_setup, 0);
#endif
#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h>
static const struct ctl_table vdso_table[] = {
{
#ifdef CONFIG_X86_64
.procname = "vsyscall32",
#else
.procname = "vdso_enabled",
#endif
.data = &vdso32_enabled,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
.extra1 = SYSCTL_ZERO,
.extra2 = SYSCTL_ONE,
},
};
static __init int ia32_binfmt_init(void)
{
#ifdef CONFIG_X86_64
/* Register vsyscall32 into the ABI table */
register_sysctl("abi", vdso_table);
#else
register_sysctl_init("vm", vdso_table);
#endif
return 0;
}
__initcall(ia32_binfmt_init);
#endif /* CONFIG_SYSCTL */
@@ -0,0 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-only
vdso32.lds
@@ -0,0 +1,29 @@
# SPDX-License-Identifier: GPL-2.0
#
# 32-bit vDSO images for x86.
#
# The vDSOs built in this directory
vdsos-y := 32
# Files to link into the vDSO:
vobjs-y := note.o vclock_gettime.o vgetcpu.o
vobjs-y += system_call.o sigreturn.o
vobjs-$(CONFIG_FUTEX_ROBUST_UNLOCK) += vfutex.o
# Compilation flags
flags-y := -DBUILD_VDSO32 -m32 -mregparm=0
flags-$(CONFIG_X86_64) += -include $(src)/fake_32bit_build.h
flags-remove-y := -m64
# Checker flags
CHECKFLAGS := $(subst -m64,-m32,$(CHECKFLAGS))
CHECKFLAGS := $(subst -D__x86_64__,-D__i386__,$(CHECKFLAGS))
# The location of this include matters!
include $(src)/../common/Makefile.include
# Linker options for the vdso
VDSO_LDFLAGS_32 := -m elf_i386 -soname linux-gate.so.1
$(obj)/vdso32.so.dbg: $(vobjs)
@@ -0,0 +1,26 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifdef CONFIG_X86_64
/*
* in case of a 32 bit VDSO for a 64 bit kernel fake a 32 bit kernel
* configuration
*/
#undef CONFIG_64BIT
#undef CONFIG_X86_64
#undef CONFIG_COMPAT
#undef CONFIG_PGTABLE_LEVELS
#undef CONFIG_ILLEGAL_POINTER_VALUE
#undef CONFIG_SPARSEMEM_VMEMMAP
#undef CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP
#undef CONFIG_NR_CPUS
#undef CONFIG_PARAVIRT_XXL
#define CONFIG_X86_32 1
#define CONFIG_PGTABLE_LEVELS 2
#define CONFIG_PAGE_OFFSET 0
#define CONFIG_ILLEGAL_POINTER_VALUE 0
#define CONFIG_NR_CPUS 1
#define BUILD_VDSO32_64
#endif
@@ -0,0 +1 @@
#include "common/note.S"
@@ -0,0 +1,84 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <linux/linkage.h>
#include <asm/unistd_32.h>
#include <asm/dwarf2.h>
#include <asm/asm-offsets.h>
.macro STARTPROC_SIGNAL_FRAME sc
CFI_STARTPROC simple
CFI_SIGNAL_FRAME
/* -4 as pretcode has already been popped */
CFI_DEF_CFA esp, \sc - 4
CFI_OFFSET eip, IA32_SIGCONTEXT_ip
CFI_OFFSET eax, IA32_SIGCONTEXT_ax
CFI_OFFSET ebx, IA32_SIGCONTEXT_bx
CFI_OFFSET ecx, IA32_SIGCONTEXT_cx
CFI_OFFSET edx, IA32_SIGCONTEXT_dx
CFI_OFFSET esp, IA32_SIGCONTEXT_sp
CFI_OFFSET ebp, IA32_SIGCONTEXT_bp
CFI_OFFSET esi, IA32_SIGCONTEXT_si
CFI_OFFSET edi, IA32_SIGCONTEXT_di
CFI_OFFSET es, IA32_SIGCONTEXT_es
CFI_OFFSET cs, IA32_SIGCONTEXT_cs
CFI_OFFSET ss, IA32_SIGCONTEXT_ss
CFI_OFFSET ds, IA32_SIGCONTEXT_ds
CFI_OFFSET eflags, IA32_SIGCONTEXT_flags
.endm
/*
* WARNING:
*
* A bug in the libgcc unwinder as of at least gcc 15.2 (2026) means that
* the unwinder fails to recognize the signal frame flag.
*
* There is a hacky legacy fallback path in libgcc which ends up
* getting invoked instead. It happens to work as long as BOTH of the
* following conditions are true:
*
* 1. There is at least one byte before the each of the sigreturn
* functions which falls outside any function. This is enforced by
* an explicit nop instruction before the ALIGN.
* 2. The code sequences between the entry point up to and including
* the int $0x80 below need to match EXACTLY. Do not change them
* in any way. The exact byte sequences are:
*
* __kernel_sigreturn:
* 0: 58 pop %eax
* 1: b8 77 00 00 00 mov $0x77,%eax
* 6: cd 80 int $0x80
*
* __kernel_rt_sigreturn:
* 0: b8 ad 00 00 00 mov $0xad,%eax
* 5: cd 80 int $0x80
*
* For details, see: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124050
*/
.text
.globl __kernel_sigreturn
.type __kernel_sigreturn,@function
nop /* libgcc hack: see comment above */
ALIGN
__kernel_sigreturn:
STARTPROC_SIGNAL_FRAME IA32_SIGFRAME_sigcontext
popl %eax
CFI_ADJUST_CFA_OFFSET -4
movl $__NR_sigreturn, %eax
int $0x80
SYM_INNER_LABEL(vdso32_sigreturn_landing_pad, SYM_L_GLOBAL)
ud2a
CFI_ENDPROC
.size __kernel_sigreturn,.-__kernel_sigreturn
.globl __kernel_rt_sigreturn
.type __kernel_rt_sigreturn,@function
nop /* libgcc hack: see comment above */
ALIGN
__kernel_rt_sigreturn:
STARTPROC_SIGNAL_FRAME IA32_RT_SIGFRAME_sigcontext
movl $__NR_rt_sigreturn, %eax
int $0x80
SYM_INNER_LABEL(vdso32_rt_sigreturn_landing_pad, SYM_L_GLOBAL)
ud2a
CFI_ENDPROC
.size __kernel_rt_sigreturn,.-__kernel_rt_sigreturn
.previous
@@ -0,0 +1,91 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* AT_SYSINFO entry point
*/
#include <linux/linkage.h>
#include <asm/dwarf2.h>
#include <asm/cpufeatures.h>
#include <asm/alternative.h>
.text
.globl __kernel_vsyscall
.type __kernel_vsyscall,@function
ALIGN
__kernel_vsyscall:
CFI_STARTPROC
/*
* If using int $0x80, there is no reason to muck about with the
* stack here. Unfortunately just overwriting the push instructions
* would mess up the CFI annotations, but it is only a 3-byte
* NOP in that case. This could be avoided by patching the
* vdso symbol table (not the code) and entry point, but that
* would a fair bit of tooling work or by simply compiling
* two different vDSO images, but that doesn't seem worth it.
*/
ALTERNATIVE "int $0x80; ret", "", X86_FEATURE_SYSFAST32
/*
* Reshuffle regs so that all of any of the entry instructions
* will preserve enough state.
*
* A really nice entry sequence would be:
* pushl %edx
* pushl %ecx
* movl %esp, %ecx
*
* Unfortunately, naughty Android versions between July and December
* 2015 actually hardcode the traditional Linux SYSENTER entry
* sequence. That is severely broken for a number of reasons (ask
* anyone with an AMD CPU, for example). Nonetheless, we try to keep
* it working approximately as well as it ever worked.
*
* This link may elucidate some of the history:
* https://android-review.googlesource.com/#/q/Iac3295376d61ef83e713ac9b528f3b50aa780cd7
* personally, I find it hard to understand what's going on there.
*
* Note to future user developers: DO NOT USE SYSENTER IN YOUR CODE.
* Execute an indirect call to the address in the AT_SYSINFO auxv
* entry. That is the ONLY correct way to make a fast 32-bit system
* call on Linux. (Open-coding int $0x80 is also fine, but it's
* slow.)
*/
pushl %ecx
CFI_ADJUST_CFA_OFFSET 4
CFI_REL_OFFSET ecx, 0
pushl %edx
CFI_ADJUST_CFA_OFFSET 4
CFI_REL_OFFSET edx, 0
pushl %ebp
CFI_ADJUST_CFA_OFFSET 4
CFI_REL_OFFSET ebp, 0
#define SYSENTER_SEQUENCE "movl %esp, %ebp; sysenter"
#define SYSCALL_SEQUENCE "movl %ecx, %ebp; syscall"
ALTERNATIVE SYSENTER_SEQUENCE, SYSCALL_SEQUENCE, X86_FEATURE_SYSCALL32
/* Re-enter using int $0x80 */
int $0x80
SYM_INNER_LABEL(int80_landing_pad, SYM_L_GLOBAL)
/*
* Restore EDX and ECX in case they were clobbered. EBP is not
* clobbered (the kernel restores it), but it's cleaner and
* probably faster to pop it than to adjust ESP using addl.
*/
popl %ebp
CFI_RESTORE ebp
CFI_ADJUST_CFA_OFFSET -4
popl %edx
CFI_RESTORE edx
CFI_ADJUST_CFA_OFFSET -4
popl %ecx
CFI_RESTORE ecx
CFI_ADJUST_CFA_OFFSET -4
RET
CFI_ENDPROC
.size __kernel_vsyscall,.-__kernel_vsyscall
.previous
@@ -0,0 +1 @@
#include "common/vclock_gettime.c"
@@ -0,0 +1,45 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Linker script for 32-bit vDSO.
* We #include the file to define the layout details.
*
* This file defines the version script giving the user-exported symbols in
* the DSO.
*/
#include <asm/page.h>
#define BUILD_VDSO32
#include "common/vdso-layout.lds.S"
/* The ELF entry point can be used to set the AT_SYSINFO value. */
ENTRY(__kernel_vsyscall);
/*
* This controls what userland symbols we export from the vDSO.
*/
VERSION
{
LINUX_2.6 {
global:
__vdso_clock_gettime;
__vdso_gettimeofday;
__vdso_time;
__vdso_clock_getres;
__vdso_clock_gettime64;
__vdso_clock_getres_time64;
__vdso_getcpu;
#ifdef CONFIG_FUTEX_ROBUST_UNLOCK
__vdso_futex_robust_list32_try_unlock;
#endif
};
LINUX_2.5 {
global:
__kernel_vsyscall;
__kernel_sigreturn;
__kernel_rt_sigreturn;
local: *;
};
}
@@ -0,0 +1 @@
#include "common/vfutex.c"
@@ -0,0 +1 @@
#include "common/vgetcpu.c"
@@ -0,0 +1,47 @@
# SPDX-License-Identifier: GPL-2.0
#
# 64-bit vDSO images for x86.
#
# The vDSOs built in this directory
vdsos-y := 64
vdsos-$(CONFIG_X86_X32_ABI) += x32
# Files to link into the vDSO:
vobjs-y := note.o vclock_gettime.o vgetcpu.o
vobjs-y += vgetrandom.o vgetrandom-chacha.o
vobjs-$(CONFIG_X86_SGX) += vsgx.o
vobjs-$(CONFIG_FUTEX_ROBUST_UNLOCK) += vfutex.o
# Compilation flags
flags-y := -DBUILD_VDSO64 -m64 -mcmodel=small
# The location of this include matters!
include $(src)/../common/Makefile.include
#
# X32 processes use x32 vDSO to access 64bit kernel data.
#
# Build x32 vDSO image:
# 1. Compile x32 vDSO as 64bit.
# 2. Convert object files to x32.
# 3. Build x32 VDSO image with x32 objects, which contains 64bit codes
# so that it can reach 64bit address space with 64bit pointers.
#
# Convert 64bit object file to x32 for x32 vDSO.
quiet_cmd_x32 = X32 $@
cmd_x32 = $(OBJCOPY) -O elf32-x86-64 $< $@
$(obj)/%-x32.o: $(obj)/%.o FORCE
$(call if_changed,x32)
vobjsx32 = $(patsubst %.o,%-x32.o,$(vobjs))
targets += $(patsubst %.o,%-x32.o,$(vobjs-y))
# Linker options for the vdso
VDSO_LDFLAGS_64 := -m elf_x86_64 -soname linux-vdso.so.1 -z max-page-size=4096
VDSO_LDFLAGS_x32 := $(subst elf_x86_64,elf32_x86_64,$(VDSO_LDFLAGS_64))
$(obj)/vdso64.so.dbg: $(vobjs)
$(obj)/vdsox32.so.dbg: $(vobjsx32)
@@ -0,0 +1 @@
#include "common/note.S"
@@ -0,0 +1 @@
#include "common/vclock_gettime.c"
@@ -0,0 +1,44 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Linker script for 64-bit vDSO.
* We #include the file to define the layout details.
*
* This file defines the version script giving the user-exported symbols in
* the DSO.
*/
#define BUILD_VDSO64
#include "common/vdso-layout.lds.S"
/*
* This controls what userland symbols we export from the vDSO.
*/
VERSION {
LINUX_2.6 {
global:
clock_gettime;
__vdso_clock_gettime;
gettimeofday;
__vdso_gettimeofday;
getcpu;
__vdso_getcpu;
time;
__vdso_time;
clock_getres;
__vdso_clock_getres;
#ifdef CONFIG_X86_SGX
__vdso_sgx_enter_enclave;
#endif
getrandom;
__vdso_getrandom;
#ifdef CONFIG_FUTEX_ROBUST_UNLOCK
__vdso_futex_robust_list64_try_unlock;
#ifdef CONFIG_COMPAT
__vdso_futex_robust_list32_try_unlock;
#endif
#endif
local: *;
};
}
@@ -0,0 +1,34 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Linker script for x32 vDSO.
* We #include the file to define the layout details.
*
* This file defines the version script giving the user-exported symbols in
* the DSO.
*/
#define BUILD_VDSOX32
#include "common/vdso-layout.lds.S"
/*
* This controls what userland symbols we export from the vDSO.
*/
VERSION {
LINUX_2.6 {
global:
__vdso_clock_gettime;
__vdso_gettimeofday;
__vdso_getcpu;
__vdso_time;
__vdso_clock_getres;
#ifdef CONFIG_FUTEX_ROBUST_UNLOCK
__vdso_futex_robust_list64_try_unlock;
#ifdef CONFIG_COMPAT
__vdso_futex_robust_list32_try_unlock;
#endif
#endif
local: *;
};
}
@@ -0,0 +1 @@
#include "common/vfutex.c"
@@ -0,0 +1 @@
#include "common/vgetcpu.c"
@@ -0,0 +1,178 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2022-2024 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
#include <linux/linkage.h>
#include <asm/frame.h>
.section .rodata, "a"
.align 16
CONSTANTS: .octa 0x6b20657479622d323320646e61707865
.text
/*
* Very basic SSE2 implementation of ChaCha20. Produces a given positive number
* of blocks of output with a nonce of 0, taking an input key and 8-byte
* counter. Importantly does not spill to the stack. Its arguments are:
*
* rdi: output bytes
* rsi: 32-byte key input
* rdx: 8-byte counter input/output
* rcx: number of 64-byte blocks to write to output
*/
SYM_FUNC_START(__arch_chacha20_blocks_nostack)
.set output, %rdi
.set key, %rsi
.set counter, %rdx
.set nblocks, %rcx
.set i, %al
/* xmm registers are *not* callee-save. */
.set temp, %xmm0
.set state0, %xmm1
.set state1, %xmm2
.set state2, %xmm3
.set state3, %xmm4
.set copy0, %xmm5
.set copy1, %xmm6
.set copy2, %xmm7
.set copy3, %xmm8
.set one, %xmm9
/* copy0 = "expand 32-byte k" */
movaps CONSTANTS(%rip),copy0
/* copy1,copy2 = key */
movups 0x00(key),copy1
movups 0x10(key),copy2
/* copy3 = counter || zero nonce */
movq 0x00(counter),copy3
/* one = 1 || 0 */
movq $1,%rax
movq %rax,one
.Lblock:
/* state0,state1,state2,state3 = copy0,copy1,copy2,copy3 */
movdqa copy0,state0
movdqa copy1,state1
movdqa copy2,state2
movdqa copy3,state3
movb $10,i
.Lpermute:
/* state0 += state1, state3 = rotl32(state3 ^ state0, 16) */
paddd state1,state0
pxor state0,state3
movdqa state3,temp
pslld $16,temp
psrld $16,state3
por temp,state3
/* state2 += state3, state1 = rotl32(state1 ^ state2, 12) */
paddd state3,state2
pxor state2,state1
movdqa state1,temp
pslld $12,temp
psrld $20,state1
por temp,state1
/* state0 += state1, state3 = rotl32(state3 ^ state0, 8) */
paddd state1,state0
pxor state0,state3
movdqa state3,temp
pslld $8,temp
psrld $24,state3
por temp,state3
/* state2 += state3, state1 = rotl32(state1 ^ state2, 7) */
paddd state3,state2
pxor state2,state1
movdqa state1,temp
pslld $7,temp
psrld $25,state1
por temp,state1
/* state1[0,1,2,3] = state1[1,2,3,0] */
pshufd $0x39,state1,state1
/* state2[0,1,2,3] = state2[2,3,0,1] */
pshufd $0x4e,state2,state2
/* state3[0,1,2,3] = state3[3,0,1,2] */
pshufd $0x93,state3,state3
/* state0 += state1, state3 = rotl32(state3 ^ state0, 16) */
paddd state1,state0
pxor state0,state3
movdqa state3,temp
pslld $16,temp
psrld $16,state3
por temp,state3
/* state2 += state3, state1 = rotl32(state1 ^ state2, 12) */
paddd state3,state2
pxor state2,state1
movdqa state1,temp
pslld $12,temp
psrld $20,state1
por temp,state1
/* state0 += state1, state3 = rotl32(state3 ^ state0, 8) */
paddd state1,state0
pxor state0,state3
movdqa state3,temp
pslld $8,temp
psrld $24,state3
por temp,state3
/* state2 += state3, state1 = rotl32(state1 ^ state2, 7) */
paddd state3,state2
pxor state2,state1
movdqa state1,temp
pslld $7,temp
psrld $25,state1
por temp,state1
/* state1[0,1,2,3] = state1[3,0,1,2] */
pshufd $0x93,state1,state1
/* state2[0,1,2,3] = state2[2,3,0,1] */
pshufd $0x4e,state2,state2
/* state3[0,1,2,3] = state3[1,2,3,0] */
pshufd $0x39,state3,state3
decb i
jnz .Lpermute
/* output0 = state0 + copy0 */
paddd copy0,state0
movups state0,0x00(output)
/* output1 = state1 + copy1 */
paddd copy1,state1
movups state1,0x10(output)
/* output2 = state2 + copy2 */
paddd copy2,state2
movups state2,0x20(output)
/* output3 = state3 + copy3 */
paddd copy3,state3
movups state3,0x30(output)
/* ++copy3.counter */
paddq one,copy3
/* output += 64, --nblocks */
addq $64,output
decq nblocks
jnz .Lblock
/* counter = copy3.counter */
movq copy3,0x00(counter)
/* Zero out the potentially sensitive regs, in case nothing uses these again. */
pxor state0,state0
pxor state1,state1
pxor state2,state2
pxor state3,state3
pxor copy1,copy1
pxor copy2,copy2
pxor temp,temp
ret
SYM_FUNC_END(__arch_chacha20_blocks_nostack)
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2022-2024 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
#include <linux/types.h>
#include "lib/vdso/getrandom.c"
ssize_t __vdso_getrandom(void *buffer, size_t len, unsigned int flags, void *opaque_state, size_t opaque_len)
{
return __cvdso_getrandom(buffer, len, flags, opaque_state, opaque_len);
}
ssize_t getrandom(void *, size_t, unsigned int, void *, size_t)
__attribute__((weak, alias("__vdso_getrandom")));
@@ -0,0 +1,150 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <linux/linkage.h>
#include <asm/errno.h>
#include <asm/enclu.h>
#include "extable.h"
/* Relative to %rbp. */
#define SGX_ENCLAVE_OFFSET_OF_RUN 16
/* The offsets relative to struct sgx_enclave_run. */
#define SGX_ENCLAVE_RUN_TCS 0
#define SGX_ENCLAVE_RUN_LEAF 8
#define SGX_ENCLAVE_RUN_EXCEPTION_VECTOR 12
#define SGX_ENCLAVE_RUN_EXCEPTION_ERROR_CODE 14
#define SGX_ENCLAVE_RUN_EXCEPTION_ADDR 16
#define SGX_ENCLAVE_RUN_USER_HANDLER 24
#define SGX_ENCLAVE_RUN_USER_DATA 32 /* not used */
#define SGX_ENCLAVE_RUN_RESERVED_START 40
#define SGX_ENCLAVE_RUN_RESERVED_END 256
.code64
.section .text, "ax"
SYM_FUNC_START(__vdso_sgx_enter_enclave)
/* Prolog */
.cfi_startproc
push %rbp
.cfi_adjust_cfa_offset 8
.cfi_rel_offset %rbp, 0
mov %rsp, %rbp
.cfi_def_cfa_register %rbp
push %rbx
.cfi_rel_offset %rbx, -8
mov %ecx, %eax
.Lenter_enclave:
/* EENTER <= function <= ERESUME */
cmp $EENTER, %eax
jb .Linvalid_input
cmp $ERESUME, %eax
ja .Linvalid_input
mov SGX_ENCLAVE_OFFSET_OF_RUN(%rbp), %rcx
/* Validate that the reserved area contains only zeros. */
mov $SGX_ENCLAVE_RUN_RESERVED_START, %rbx
1:
cmpq $0, (%rcx, %rbx)
jne .Linvalid_input
add $8, %rbx
cmpq $SGX_ENCLAVE_RUN_RESERVED_END, %rbx
jne 1b
/* Load TCS and AEP */
mov SGX_ENCLAVE_RUN_TCS(%rcx), %rbx
lea .Lasync_exit_pointer(%rip), %rcx
/* Single ENCLU serving as both EENTER and AEP (ERESUME) */
.Lasync_exit_pointer:
.Lenclu_eenter_eresume:
enclu
/* EEXIT jumps here unless the enclave is doing something fancy. */
mov SGX_ENCLAVE_OFFSET_OF_RUN(%rbp), %rbx
/* Set exit_reason. */
movl $EEXIT, SGX_ENCLAVE_RUN_LEAF(%rbx)
/* Invoke userspace's exit handler if one was provided. */
.Lhandle_exit:
cmpq $0, SGX_ENCLAVE_RUN_USER_HANDLER(%rbx)
jne .Linvoke_userspace_handler
/* Success, in the sense that ENCLU was attempted. */
xor %eax, %eax
.Lout:
pop %rbx
leave
.cfi_def_cfa %rsp, 8
RET
/* The out-of-line code runs with the pre-leave stack frame. */
.cfi_def_cfa %rbp, 16
.Linvalid_input:
mov $(-EINVAL), %eax
jmp .Lout
.Lhandle_exception:
mov SGX_ENCLAVE_OFFSET_OF_RUN(%rbp), %rbx
/* Set the exception info. */
mov %eax, (SGX_ENCLAVE_RUN_LEAF)(%rbx)
mov %di, (SGX_ENCLAVE_RUN_EXCEPTION_VECTOR)(%rbx)
mov %si, (SGX_ENCLAVE_RUN_EXCEPTION_ERROR_CODE)(%rbx)
mov %rdx, (SGX_ENCLAVE_RUN_EXCEPTION_ADDR)(%rbx)
jmp .Lhandle_exit
.Linvoke_userspace_handler:
/* Pass the untrusted RSP (at exit) to the callback via %rcx. */
mov %rsp, %rcx
/* Save struct sgx_enclave_exception %rbx is about to be clobbered. */
mov %rbx, %rax
/* Save the untrusted RSP offset in %rbx (non-volatile register). */
mov %rsp, %rbx
and $0xf, %rbx
/*
* Align stack per x86_64 ABI. Note, %rsp needs to be 16-byte aligned
* _after_ pushing the parameters on the stack, hence the bonus push.
*/
and $-0x10, %rsp
push %rax
/* Push struct sgx_enclave_exception as a param to the callback. */
push %rax
/* Clear RFLAGS.DF per x86_64 ABI */
cld
/*
* Load the callback pointer to %rax and lfence for LVI (load value
* injection) protection before making the call.
*/
mov SGX_ENCLAVE_RUN_USER_HANDLER(%rax), %rax
lfence
call *%rax
/* Undo the post-exit %rsp adjustment. */
lea 0x10(%rsp, %rbx), %rsp
/*
* If the return from callback is zero or negative, return immediately,
* else re-execute ENCLU with the positive return value interpreted as
* the requested ENCLU function.
*/
cmp $0, %eax
jle .Lout
jmp .Lenter_enclave
.cfi_endproc
_ASM_VDSO_EXTABLE_HANDLE(.Lenclu_eenter_eresume, .Lhandle_exception)
SYM_FUNC_END(__vdso_sgx_enter_enclave)
+306
View File
@@ -0,0 +1,306 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2007 Andi Kleen, SUSE Labs.
*
* This contains most of the x86 vDSO kernel-side code.
*/
#include <linux/mm.h>
#include <linux/err.h>
#include <linux/futex.h>
#include <linux/sched.h>
#include <linux/sched/task_stack.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/random.h>
#include <linux/elf.h>
#include <linux/cpu.h>
#include <linux/ptrace.h>
#include <linux/vdso_datastore.h>
#include <asm/pvclock.h>
#include <asm/vgtod.h>
#include <asm/proto.h>
#include <asm/vdso.h>
#include <asm/tlb.h>
#include <asm/page.h>
#include <asm/desc.h>
#include <asm/cpufeature.h>
#include <asm/vdso/vsyscall.h>
#include <clocksource/hyperv_timer.h>
static_assert(VDSO_NR_PAGES + VDSO_NR_VCLOCK_PAGES == __VDSO_PAGES);
unsigned int vclocks_used __read_mostly;
#if defined(CONFIG_X86_64)
unsigned int __read_mostly vdso64_enabled = 1;
#endif
int __init init_vdso_image(const struct vdso_image *image)
{
BUILD_BUG_ON(VDSO_CLOCKMODE_MAX >= 32);
BUG_ON(image->size % PAGE_SIZE != 0);
apply_alternatives((struct alt_instr *)(image->data + image->alt),
(struct alt_instr *)(image->data + image->alt +
image->alt_len));
return 0;
}
struct linux_binprm;
static vm_fault_t vdso_fault(const struct vm_special_mapping *sm,
struct vm_area_struct *vma, struct vm_fault *vmf)
{
const struct vdso_image *image = vma->vm_mm->context.vdso_image;
if (!image || (vmf->pgoff << PAGE_SHIFT) >= image->size)
return VM_FAULT_SIGBUS;
vmf->page = virt_to_page(image->data + (vmf->pgoff << PAGE_SHIFT));
get_page(vmf->page);
return 0;
}
static void vdso_fix_landing(const struct vdso_image *image,
struct vm_area_struct *new_vma)
{
struct pt_regs *regs = current_pt_regs();
unsigned long ipoffset = regs->ip -
(unsigned long)current->mm->context.vdso;
if (ipoffset < image->size)
regs->ip = new_vma->vm_start + ipoffset;
}
#ifdef CONFIG_FUTEX_ROBUST_UNLOCK
static void vdso_futex_robust_unlock_update_ips(void)
{
const struct vdso_image *image = current->mm->context.vdso_image;
unsigned long vdso = (unsigned long) current->mm->context.vdso;
struct futex_mm_data *fd = &current->mm->futex;
unsigned int idx = 0;
futex_reset_cs_ranges(fd);
#ifdef CONFIG_X86_64
futex_set_vdso_cs_range(fd, idx, vdso + image->sym___futex_list64_try_unlock_cs_start,
vdso + image->sym___futex_list64_try_unlock_cs_end, false);
idx++;
#endif /* CONFIG_X86_64 */
#if defined(CONFIG_X86_32) || defined(CONFIG_COMPAT)
futex_set_vdso_cs_range(fd, idx, vdso + image->sym___futex_list32_try_unlock_cs_start,
vdso + image->sym___futex_list32_try_unlock_cs_end, true);
#endif /* CONFIG_X86_32 || CONFIG_COMPAT */
}
#else
static inline void vdso_futex_robust_unlock_update_ips(void) { }
#endif
static int vdso_mremap(const struct vm_special_mapping *sm,
struct vm_area_struct *new_vma)
{
const struct vdso_image *image = current->mm->context.vdso_image;
vdso_fix_landing(image, new_vma);
current->mm->context.vdso = (void __user *)new_vma->vm_start;
vdso_futex_robust_unlock_update_ips();
return 0;
}
static vm_fault_t vvar_vclock_fault(const struct vm_special_mapping *sm,
struct vm_area_struct *vma, struct vm_fault *vmf)
{
switch (vmf->pgoff) {
case VDSO_PAGE_PVCLOCK_OFFSET:
{
struct pvclock_vsyscall_time_info *pvti =
pvclock_get_pvti_cpu0_va();
if (pvti && vclock_was_used(VDSO_CLOCKMODE_PVCLOCK))
return vmf_insert_pfn_prot(vma, vmf->address,
__pa(pvti) >> PAGE_SHIFT,
pgprot_decrypted(vma->vm_page_prot));
break;
}
case VDSO_PAGE_HVCLOCK_OFFSET:
{
unsigned long pfn = hv_get_tsc_pfn();
if (pfn && vclock_was_used(VDSO_CLOCKMODE_HVCLOCK))
return vmf_insert_pfn(vma, vmf->address, pfn);
break;
}
}
return VM_FAULT_SIGBUS;
}
static const struct vm_special_mapping vdso_mapping = {
.name = "[vdso]",
.fault = vdso_fault,
.mremap = vdso_mremap,
};
static const struct vm_special_mapping vvar_vclock_mapping = {
.name = "[vvar_vclock]",
.fault = vvar_vclock_fault,
};
/*
* Add vdso and vvar mappings to current process.
* @image - blob to map
* @addr - request a specific address (zero to map at free addr)
*/
static int map_vdso(const struct vdso_image *image, unsigned long addr)
{
struct mm_struct *mm = current->mm;
struct vm_area_struct *vma;
unsigned long text_start;
int ret = 0;
if (mmap_write_lock_killable(mm))
return -EINTR;
addr = get_unmapped_area(NULL, addr,
image->size + __VDSO_PAGES * PAGE_SIZE, 0, 0);
if (IS_ERR_VALUE(addr)) {
ret = addr;
goto up_fail;
}
text_start = addr + __VDSO_PAGES * PAGE_SIZE;
/*
* MAYWRITE to allow gdb to COW and set breakpoints
*/
vma = _install_special_mapping(mm,
text_start,
image->size,
VM_READ|VM_EXEC|
VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
VM_SEALED_SYSMAP,
&vdso_mapping);
if (IS_ERR(vma)) {
ret = PTR_ERR(vma);
goto up_fail;
}
vma = vdso_install_vvar_mapping(mm, addr);
if (IS_ERR(vma)) {
ret = PTR_ERR(vma);
do_munmap(mm, text_start, image->size, NULL);
goto up_fail;
}
vma = _install_special_mapping(mm,
VDSO_VCLOCK_PAGES_START(addr),
VDSO_NR_VCLOCK_PAGES * PAGE_SIZE,
VM_READ|VM_MAYREAD|VM_IO|VM_DONTDUMP|
VM_PFNMAP|VM_SEALED_SYSMAP,
&vvar_vclock_mapping);
if (IS_ERR(vma)) {
ret = PTR_ERR(vma);
do_munmap(mm, text_start, image->size, NULL);
do_munmap(mm, addr, VDSO_NR_PAGES * PAGE_SIZE, NULL);
goto up_fail;
}
current->mm->context.vdso = (void __user *)text_start;
current->mm->context.vdso_image = image;
vdso_futex_robust_unlock_update_ips();
up_fail:
mmap_write_unlock(mm);
return ret;
}
int map_vdso_once(const struct vdso_image *image, unsigned long addr)
{
struct mm_struct *mm = current->mm;
struct vm_area_struct *vma;
VMA_ITERATOR(vmi, mm, 0);
mmap_write_lock(mm);
/*
* Check if we have already mapped vdso blob - fail to prevent
* abusing from userspace install_special_mapping, which may
* not do accounting and rlimit right.
* We could search vma near context.vdso, but it's a slowpath,
* so let's explicitly check all VMAs to be completely sure.
*/
for_each_vma(vmi, vma) {
if (vma_is_special_mapping(vma, &vdso_mapping) ||
vma_is_special_mapping(vma, &vdso_vvar_mapping) ||
vma_is_special_mapping(vma, &vvar_vclock_mapping)) {
mmap_write_unlock(mm);
return -EEXIST;
}
}
mmap_write_unlock(mm);
return map_vdso(image, addr);
}
static int load_vdso32(void)
{
if (vdso32_enabled != 1) /* Other values all mean "disabled" */
return 0;
return map_vdso(&vdso32_image, 0);
}
int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
{
if (IS_ENABLED(CONFIG_X86_64)) {
if (!vdso64_enabled)
return 0;
return map_vdso(&vdso64_image, 0);
}
return load_vdso32();
}
#ifdef CONFIG_COMPAT
int compat_arch_setup_additional_pages(struct linux_binprm *bprm,
int uses_interp, bool x32)
{
if (IS_ENABLED(CONFIG_X86_X32_ABI) && x32) {
if (!vdso64_enabled)
return 0;
return map_vdso(&vdsox32_image, 0);
}
if (IS_ENABLED(CONFIG_IA32_EMULATION))
return load_vdso32();
return 0;
}
#endif
bool arch_syscall_is_vdso_sigreturn(struct pt_regs *regs)
{
const struct vdso_image *image = current->mm->context.vdso_image;
unsigned long vdso = (unsigned long) current->mm->context.vdso;
if (in_ia32_syscall() && image == &vdso32_image) {
if (regs->ip == vdso + image->sym_vdso32_sigreturn_landing_pad ||
regs->ip == vdso + image->sym_vdso32_rt_sigreturn_landing_pad)
return true;
}
return false;
}
#ifdef CONFIG_X86_64
static __init int vdso_setup(char *s)
{
vdso64_enabled = simple_strtoul(s, NULL, 0);
return 1;
}
__setup("vdso=", vdso_setup);
#endif /* CONFIG_X86_64 */