mirror of
https://github.com/checkpoint-restore/criu
synced 2025-08-22 01:51:51 +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 += 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)
|
||||
$(E) " LINK " $@
|
||||
$(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-e += $(ARCH_DIR)/restorer.o
|
||||
restorer-obj-e += $(ARCH_DIR)/vdso-pie.o
|
||||
restorer-libs-e += $(SYSCALL-LIB)
|
||||
|
||||
cflags-y += -DCR_NOGLIBC -fpie -Wa,--noexecstack -fno-stack-protector
|
||||
|
Loading…
x
Reference in New Issue
Block a user