Commit 61cc86dd authored by Cyrill Gorcunov's avatar Cyrill Gorcunov Committed by Pavel Emelyanov

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: 's avatarCyrill Gorcunov <gorcunov@openvz.org>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent 9208108c
...@@ -146,6 +146,10 @@ PROGRAM-BUILTINS += pie/util-net.o ...@@ -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 $@
......
#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__ */
#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;
}
#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__ */
#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(&section_names[shdr->sh_name], mem, size))
goto err;
#if 0
pr_debug("section: %2d -> %s\n",
i, &section_names[shdr->sh_name]);
#endif
if (shdr->sh_type == SHT_DYNSYM &&
builtin_strcmp(&section_names[shdr->sh_name],
".dynsym") == 0) {
shdr_dynsym = shdr;
} else if (shdr->sh_type == SHT_STRTAB &&
builtin_strcmp(&section_names[shdr->sh_name],
".dynstr") == 0) {
shdr_dynstr = shdr;
} else if (shdr->sh_type == SHT_PROGBITS &&
builtin_strcmp(&section_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;
}
#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) ...@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment