mirror of
https://github.com/checkpoint-restore/criu
synced 2025-08-30 13:58:34 +00:00
vdso: Introduce vdso pie-engine
It's quite minimal at moment and provides only two helpers - vdso_redirect_calls, to patch vdso area redirectling calls to some new place. - vdso_fill_symtable, to parse vma area as vdso library and fill symbols table with offsets and names. Because these routines will be needed in both regular criu code and restorer code -- we compile it in pie format. Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org> Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
This commit is contained in:
parent
9208108c9f
commit
61cc86ddd2
4
Makefile
4
Makefile
@ -146,6 +146,10 @@ PROGRAM-BUILTINS += pie/util-net.o
|
|||||||
PROGRAM-BUILTINS += protobuf/built-in.o
|
PROGRAM-BUILTINS += protobuf/built-in.o
|
||||||
PROGRAM-BUILTINS += built-in.o
|
PROGRAM-BUILTINS += built-in.o
|
||||||
|
|
||||||
|
$(ARCH_DIR)/vdso-pie.o: pie
|
||||||
|
$(Q) $(MAKE) $(build)=pie $(ARCH_DIR)/vdso-pie.o
|
||||||
|
PROGRAM-BUILTINS += $(ARCH_DIR)/vdso-pie.o
|
||||||
|
|
||||||
$(PROGRAM): $(SYSCALL-LIB) $(ARCH-LIB) $(PROGRAM-BUILTINS)
|
$(PROGRAM): $(SYSCALL-LIB) $(ARCH-LIB) $(PROGRAM-BUILTINS)
|
||||||
$(E) " LINK " $@
|
$(E) " LINK " $@
|
||||||
$(Q) $(CC) $(CFLAGS) $^ $(LIBS) -o $@
|
$(Q) $(CC) $(CFLAGS) $^ $(LIBS) -o $@
|
||||||
|
11
arch/arm/include/asm/vdso.h
Normal file
11
arch/arm/include/asm/vdso.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef __CR_ASM_VDSO_H__
|
||||||
|
#define __CR_ASM_VDSO_H__
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
struct vdso_symtable;
|
||||||
|
|
||||||
|
extern int vdso_redirect_calls(void *base_to, void *base_from, struct vdso_symtable *to, struct vdso_symtable *from);
|
||||||
|
extern int vdso_fill_symtable(char *mem, size_t size,struct vdso_symtable *t);
|
||||||
|
|
||||||
|
#endif /* __CR_ASM_VDSO_H__ */
|
35
arch/arm/vdso-pie.c
Normal file
35
arch/arm/vdso-pie.c
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <elf.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
#include "asm/string.h"
|
||||||
|
#include "asm/types.h"
|
||||||
|
|
||||||
|
#include "compiler.h"
|
||||||
|
#include "crtools.h"
|
||||||
|
#include "vdso.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
#ifdef LOG_PREFIX
|
||||||
|
# undef LOG_PREFIX
|
||||||
|
#endif
|
||||||
|
#define LOG_PREFIX "vdso: "
|
||||||
|
|
||||||
|
int vdso_redirect_calls(void *base_to, void *base_from,
|
||||||
|
struct vdso_symtable *to,
|
||||||
|
struct vdso_symtable *from)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vdso_fill_symtable(char *mem, size_t size, struct vdso_symtable *t)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
11
arch/x86/include/asm/vdso.h
Normal file
11
arch/x86/include/asm/vdso.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef __CR_ASM_VDSO_H__
|
||||||
|
#define __CR_ASM_VDSO_H__
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
struct vdso_symtable;
|
||||||
|
|
||||||
|
extern int vdso_redirect_calls(void *base_to, void *base_from, struct vdso_symtable *to, struct vdso_symtable *from);
|
||||||
|
extern int vdso_fill_symtable(char *mem, size_t size,struct vdso_symtable *t);
|
||||||
|
|
||||||
|
#endif /* __CR_ASM_VDSO_H__ */
|
226
arch/x86/vdso-pie.c
Normal file
226
arch/x86/vdso-pie.c
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <elf.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
#include "asm/string.h"
|
||||||
|
#include "asm/types.h"
|
||||||
|
|
||||||
|
#include "compiler.h"
|
||||||
|
#include "crtools.h"
|
||||||
|
#include "vdso.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
#ifdef LOG_PREFIX
|
||||||
|
# undef LOG_PREFIX
|
||||||
|
#endif
|
||||||
|
#define LOG_PREFIX "vdso: "
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u16 movabs;
|
||||||
|
u64 imm64;
|
||||||
|
u16 jmp_rax;
|
||||||
|
u32 guards;
|
||||||
|
} __packed jmp_t;
|
||||||
|
|
||||||
|
int vdso_redirect_calls(void *base_to, void *base_from,
|
||||||
|
struct vdso_symtable *to,
|
||||||
|
struct vdso_symtable *from)
|
||||||
|
{
|
||||||
|
jmp_t jmp = {
|
||||||
|
.movabs = 0xb848,
|
||||||
|
.jmp_rax = 0xe0ff,
|
||||||
|
.guards = 0xcccccccc,
|
||||||
|
};
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(to->symbols); i++) {
|
||||||
|
if (vdso_symbol_empty(&from->symbols[i]))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
pr_debug("jmp: %lx/%lx -> %lx/%lx (index %d)\n",
|
||||||
|
(unsigned long)base_from, from->symbols[i].offset,
|
||||||
|
(unsigned long)base_to, to->symbols[i].offset, i);
|
||||||
|
|
||||||
|
jmp.imm64 = (unsigned long)base_to + to->symbols[i].offset;
|
||||||
|
builtin_memcpy((void *)(base_from + from->symbols[i].offset), &jmp, sizeof(jmp));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int get_symbol_index(char *symbol, char *symbols[], size_t size)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0; symbol && i < size; i++) {
|
||||||
|
if (!builtin_strcmp(symbol, symbols[i]))
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return VDSO_SYMBOL_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if pointer is out-of-bound */
|
||||||
|
static bool __ptr_oob(void *ptr, void *start, size_t size)
|
||||||
|
{
|
||||||
|
void *end = (void *)((unsigned long)start + size);
|
||||||
|
return ptr > end || ptr < start;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vdso_fill_symtable(char *mem, size_t size, struct vdso_symtable *t)
|
||||||
|
{
|
||||||
|
Elf64_Ehdr *ehdr = (void *)mem;
|
||||||
|
Elf64_Shdr *shdr, *shdr_strtab;
|
||||||
|
Elf64_Shdr *shdr_dynsym;
|
||||||
|
Elf64_Shdr *shdr_dynstr;
|
||||||
|
Elf64_Phdr *phdr;
|
||||||
|
Elf64_Shdr *text;
|
||||||
|
Elf64_Sym *sym;
|
||||||
|
|
||||||
|
char *section_names, *dynsymbol_names;
|
||||||
|
|
||||||
|
unsigned long base = VDSO_BAD_ADDR;
|
||||||
|
unsigned int i, j, k;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Elf header bytes. For detailed
|
||||||
|
* description see Elf specification.
|
||||||
|
*/
|
||||||
|
char vdso_ident[] = {
|
||||||
|
0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
char *vdso_x86_symbols[VDSO_SYMBOL_MAX] = {
|
||||||
|
[VDSO_SYMBOL_GETTIMEOFDAY] = VDSO_SYMBOL_GETTIMEOFDAY_NAME,
|
||||||
|
[VDSO_SYMBOL_GETCPU] = VDSO_SYMBOL_GETCPU_NAME,
|
||||||
|
[VDSO_SYMBOL_CLOCK_GETTIME] = VDSO_SYMBOL_CLOCK_GETTIME_NAME,
|
||||||
|
[VDSO_SYMBOL_TIME] = VDSO_SYMBOL_TIME_NAME,
|
||||||
|
};
|
||||||
|
|
||||||
|
BUILD_BUG_ON(sizeof(vdso_ident) != sizeof(ehdr->e_ident));
|
||||||
|
|
||||||
|
pr_debug("Parsing at %lx %lx\n",
|
||||||
|
(long)mem, (long)mem + (long)size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make sure it's a file we support.
|
||||||
|
*/
|
||||||
|
if (builtin_memcmp(ehdr->e_ident, vdso_ident, sizeof(vdso_ident))) {
|
||||||
|
pr_debug("Elf header magic mismatch\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Figure out base virtual address.
|
||||||
|
*/
|
||||||
|
phdr = (void *)&mem[ehdr->e_phoff];
|
||||||
|
for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
|
||||||
|
if (__ptr_oob(phdr, mem, size))
|
||||||
|
goto err;
|
||||||
|
if (phdr->p_type == PT_LOAD) {
|
||||||
|
base = phdr->p_vaddr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (base != VDSO_BAD_ADDR) {
|
||||||
|
pr_debug("Base address %lx\n", base);
|
||||||
|
} else {
|
||||||
|
pr_debug("No base address found\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Where the section names lays.
|
||||||
|
*/
|
||||||
|
if (ehdr->e_shstrndx == SHN_UNDEF) {
|
||||||
|
pr_err("Section names are not found\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
shdr = (void *)&mem[ehdr->e_shoff];
|
||||||
|
shdr_strtab = &shdr[ehdr->e_shstrndx];
|
||||||
|
if (__ptr_oob(shdr_strtab, mem, size))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
section_names = (void *)&mem[shdr_strtab->sh_offset];
|
||||||
|
shdr_dynsym = shdr_dynstr = text = NULL;
|
||||||
|
|
||||||
|
for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
|
||||||
|
if (__ptr_oob(shdr, mem, size))
|
||||||
|
goto err;
|
||||||
|
if (__ptr_oob(§ion_names[shdr->sh_name], mem, size))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
pr_debug("section: %2d -> %s\n",
|
||||||
|
i, §ion_names[shdr->sh_name]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (shdr->sh_type == SHT_DYNSYM &&
|
||||||
|
builtin_strcmp(§ion_names[shdr->sh_name],
|
||||||
|
".dynsym") == 0) {
|
||||||
|
shdr_dynsym = shdr;
|
||||||
|
} else if (shdr->sh_type == SHT_STRTAB &&
|
||||||
|
builtin_strcmp(§ion_names[shdr->sh_name],
|
||||||
|
".dynstr") == 0) {
|
||||||
|
shdr_dynstr = shdr;
|
||||||
|
} else if (shdr->sh_type == SHT_PROGBITS &&
|
||||||
|
builtin_strcmp(§ion_names[shdr->sh_name],
|
||||||
|
".text") == 0) {
|
||||||
|
text = shdr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!shdr_dynsym || !shdr_dynstr || !text) {
|
||||||
|
pr_debug("No required sections found\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
dynsymbol_names = (void *)&mem[shdr_dynstr->sh_offset];
|
||||||
|
if (__ptr_oob(dynsymbol_names, mem, size) ||
|
||||||
|
__ptr_oob(shdr_dynsym, mem, size) ||
|
||||||
|
__ptr_oob(text, mem, size))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Walk over global symbols and choose ones we need.
|
||||||
|
*/
|
||||||
|
j = shdr_dynsym->sh_size / sizeof(*sym);
|
||||||
|
sym = (void *)&mem[shdr_dynsym->sh_offset];
|
||||||
|
|
||||||
|
for (i = 0; i < j; i++, sym++) {
|
||||||
|
if (__ptr_oob(sym, mem, size))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
if (ELF64_ST_BIND(sym->st_info) != STB_GLOBAL ||
|
||||||
|
ELF64_ST_TYPE(sym->st_info) != STT_FUNC)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (__ptr_oob(&dynsymbol_names[sym->st_name], mem, size))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
k = get_symbol_index(&dynsymbol_names[sym->st_name],
|
||||||
|
vdso_x86_symbols,
|
||||||
|
ARRAY_SIZE(vdso_x86_symbols));
|
||||||
|
if (k != VDSO_SYMBOL_MAX) {
|
||||||
|
builtin_memcpy(t->symbols[k].name, vdso_x86_symbols[k],
|
||||||
|
sizeof(t->symbols[k].name));
|
||||||
|
t->symbols[k].offset = (unsigned long)sym->st_value - base;
|
||||||
|
#if 0
|
||||||
|
pr_debug("symbol: %#-16lx %2d %s\n",
|
||||||
|
t->symbols[k].offset, sym->st_shndx, t->symbols[k].name);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
err:
|
||||||
|
return -1;
|
||||||
|
}
|
69
include/vdso.h
Normal file
69
include/vdso.h
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
#ifndef __CR_VDSO_H__
|
||||||
|
#define __CR_VDSO_H__
|
||||||
|
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
#include "asm/vdso.h"
|
||||||
|
|
||||||
|
#define VDSO_PROT (PROT_READ | PROT_EXEC)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a minimal amount of symbols
|
||||||
|
* we should support at the moment.
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
VDSO_SYMBOL_GETTIMEOFDAY,
|
||||||
|
VDSO_SYMBOL_GETCPU,
|
||||||
|
VDSO_SYMBOL_CLOCK_GETTIME,
|
||||||
|
VDSO_SYMBOL_TIME,
|
||||||
|
|
||||||
|
VDSO_SYMBOL_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
#define VDSO_SYMBOL_GETTIMEOFDAY_NAME "__vdso_gettimeofday"
|
||||||
|
#define VDSO_SYMBOL_GETCPU_NAME "__vdso_getcpu"
|
||||||
|
#define VDSO_SYMBOL_CLOCK_GETTIME_NAME "__vdso_clock_gettime"
|
||||||
|
#define VDSO_SYMBOL_TIME_NAME "__vdso_time"
|
||||||
|
|
||||||
|
#define VDSO_BAD_ADDR (-1ul)
|
||||||
|
|
||||||
|
struct vdso_symbol {
|
||||||
|
char name[32];
|
||||||
|
unsigned long offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define VDSO_SYMBOL_INIT \
|
||||||
|
{ .offset = VDSO_BAD_ADDR, }
|
||||||
|
|
||||||
|
/* Check if symbol present in symtable */
|
||||||
|
static inline bool vdso_symbol_empty(struct vdso_symbol *s)
|
||||||
|
{
|
||||||
|
return s->offset == VDSO_BAD_ADDR && s->name[0] == '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
struct vdso_symtable {
|
||||||
|
unsigned long vma_start;
|
||||||
|
unsigned long vma_end;
|
||||||
|
struct vdso_symbol symbols[VDSO_SYMBOL_MAX];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define VDSO_SYMTABLE_INIT \
|
||||||
|
{ \
|
||||||
|
.vma_start = VDSO_BAD_ADDR, \
|
||||||
|
.vma_end = VDSO_BAD_ADDR, \
|
||||||
|
.symbols = { \
|
||||||
|
[0 ... VDSO_SYMBOL_MAX - 1] = \
|
||||||
|
(struct vdso_symbol)VDSO_SYMBOL_INIT, \
|
||||||
|
}, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define VDSO_INIT_SYMTABLE(symtable) \
|
||||||
|
*(symtable) = (struct vdso_symtable)VDSO_SYMTABLE_INIT
|
||||||
|
|
||||||
|
/* Size of VMA associated with vdso */
|
||||||
|
static inline unsigned long vdso_vma_size(struct vdso_symtable *t)
|
||||||
|
{
|
||||||
|
return t->vma_end - t->vma_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __CR_VDSO_H__ */
|
@ -10,6 +10,7 @@ parasite-libs-e += $(SYSCALL-LIB)
|
|||||||
|
|
||||||
restorer-obj-y += restorer.o
|
restorer-obj-y += restorer.o
|
||||||
restorer-obj-e += $(ARCH_DIR)/restorer.o
|
restorer-obj-e += $(ARCH_DIR)/restorer.o
|
||||||
|
restorer-obj-e += $(ARCH_DIR)/vdso-pie.o
|
||||||
restorer-libs-e += $(SYSCALL-LIB)
|
restorer-libs-e += $(SYSCALL-LIB)
|
||||||
|
|
||||||
cflags-y += -DCR_NOGLIBC -fpie -Wa,--noexecstack -fno-stack-protector
|
cflags-y += -DCR_NOGLIBC -fpie -Wa,--noexecstack -fno-stack-protector
|
||||||
|
Loading…
x
Reference in New Issue
Block a user