[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v4 19/34] xsplice, symbols: Implement symbol name resolution on address.
If in the payload we do not have the old_addr we can resolve the virtual address based on the UNDEFined symbols. We also use an boolean flag: new_symbol to track symbols. The usual case this is used is by: * A payload may introduce a new symbol * A payload may override an existing symbol (introduced in Xen or another payload) * Overriding symbols must exist in the symtab for backtraces. * A payload must always link against the object which defines the new symbol. Considering that payloads may be loaded in any order it would be incorrect to link against a payload which simply overrides a symbol because you could end up with a chain of jumps which is inefficient and may result in the expected function not being executed. Also we include a local definition block in the symbols.c file. Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@xxxxxxxxxx> Signed-off-by: Ross Lagerwall <ross.lagerwall@xxxxxxxxxx> --- Cc: Keir Fraser <keir@xxxxxxx> Cc: Jan Beulich <jbeulich@xxxxxxxx> Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> v1: Ross original version. v2: Include test-case and document update. v3: s/size_t/ssize_t/ v4: Include core_text_size, core_text calculation --- xen/arch/x86/Makefile | 6 +- xen/arch/x86/test/Makefile | 4 +- xen/arch/x86/test/xen_hello_world.c | 5 +- xen/common/symbols.c | 33 ++++++++ xen/common/xsplice.c | 163 ++++++++++++++++++++++++++++++++++++ xen/common/xsplice_elf.c | 19 ++++- xen/include/xen/symbols.h | 2 + xen/include/xen/xsplice.h | 8 ++ 8 files changed, 231 insertions(+), 9 deletions(-) diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index 5f40e63..a2e3017 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -112,12 +112,14 @@ $(TARGET)-syms: prelink.o xen.lds $(BASEDIR)/common/symbols-dummy.o $(LD) $(LDFLAGS) -T xen.lds -N prelink.o \ $(BASEDIR)/common/symbols-dummy.o -o $(@D)/.$(@F).0 $(NM) -pa --format=sysv $(@D)/.$(@F).0 \ - | $(BASEDIR)/tools/symbols --sysv --sort >$(@D)/.$(@F).0.S + | $(BASEDIR)/tools/symbols --all-symbols --sysv --sort \ + >$(@D)/.$(@F).0.S $(MAKE) -f $(BASEDIR)/Rules.mk $(@D)/.$(@F).0.o $(LD) $(LDFLAGS) -T xen.lds -N prelink.o \ $(@D)/.$(@F).0.o -o $(@D)/.$(@F).1 $(NM) -pa --format=sysv $(@D)/.$(@F).1 \ - | $(BASEDIR)/tools/symbols --sysv --sort --warn-dup >$(@D)/.$(@F).1.S + | $(BASEDIR)/tools/symbols --all-symbols --sysv --sort --warn-dup \ + >$(@D)/.$(@F).1.S $(MAKE) -f $(BASEDIR)/Rules.mk $(@D)/.$(@F).1.o $(LD) $(LDFLAGS) -T xen.lds -N prelink.o \ $(@D)/.$(@F).1.o -o $@ diff --git a/xen/arch/x86/test/Makefile b/xen/arch/x86/test/Makefile index 941f586..45df301 100644 --- a/xen/arch/x86/test/Makefile +++ b/xen/arch/x86/test/Makefile @@ -32,14 +32,12 @@ clean:: # the last entry in the build target. # .PHONY: config.h -config.h: OLD_CODE=$(call CODE_ADDR,$(BASEDIR)/xen-syms,xen_extra_version) config.h: OLD_CODE_SZ=$(call CODE_SZ,$(BASEDIR)/xen-syms,xen_extra_version) config.h: NEW_CODE_SZ=$(call CODE_SZ,$<,xen_hello_world) config.h: xen_hello_world_func.o (set -e; \ echo "#define NEW_CODE_SZ $(NEW_CODE_SZ)"; \ - echo "#define OLD_CODE_SZ $(OLD_CODE_SZ)"; \ - echo "#define OLD_CODE $(OLD_CODE)") > $@ + echo "#define OLD_CODE_SZ $(OLD_CODE_SZ)") > $@ .PHONY: xsplice xsplice: config.h diff --git a/xen/arch/x86/test/xen_hello_world.c b/xen/arch/x86/test/xen_hello_world.c index f6ac098..243eb3f 100644 --- a/xen/arch/x86/test/xen_hello_world.c +++ b/xen/arch/x86/test/xen_hello_world.c @@ -11,10 +11,13 @@ static char xen_hello_world_name[] = "xen_hello_world"; extern const char *xen_hello_world(void); +/* External symbol. */ +extern const char *xen_extra_version(void); + struct xsplice_patch_func __section(".xsplice.funcs") xsplice_xen_hello_world = { .name = xen_hello_world_name, .new_addr = (unsigned long)(xen_hello_world), - .old_addr = OLD_CODE, + .old_addr = (unsigned long)(xen_extra_version), .new_size = NEW_CODE_SZ, .old_size = OLD_CODE_SZ, }; diff --git a/xen/common/symbols.c b/xen/common/symbols.c index 2cc416e..4fe7a87 100644 --- a/xen/common/symbols.c +++ b/xen/common/symbols.c @@ -225,3 +225,36 @@ int xensyms_read(uint32_t *symnum, char *type, return 0; } + +uint64_t symbols_lookup_by_name(const char *symname) +{ + uint32_t symnum = 0; + uint64_t addr = 0, outaddr = 0; + int rc; + char type; + char name[KSYM_NAME_LEN + 1] = {0}; + + do { + rc = xensyms_read(&symnum, &type, &addr, name); + if ( rc ) + break; + + if ( !strcmp(name, symname) ) + { + outaddr = addr; + break; + } + } while ( name[0] != '\0' ); + + return outaddr; +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/common/xsplice.c b/xen/common/xsplice.c index d456671..54120bb 100644 --- a/xen/common/xsplice.c +++ b/xen/common/xsplice.c @@ -13,6 +13,7 @@ #include <xen/smp.h> #include <xen/softirq.h> #include <xen/spinlock.h> +#include <xen/symbols.h> #include <xen/vmap.h> #include <xen/wait.h> #include <xen/xsplice_elf.h> @@ -44,9 +45,14 @@ struct payload { void *payload_address; /* Virtual address mapped. */ size_t payload_pages; /* Nr of the pages. */ mfn_t *mfn; /* Array of MFNs of the pages. */ + size_t core_size; /* Everything else - .data,.rodata, etc. */ + size_t core_text_size; /* Only .text size. */ struct list_head applied_list; /* Linked to 'applied_list'. */ struct xsplice_patch_func *funcs; /* The array of functions to patch. */ unsigned int nfuncs; /* Nr of functions to patch. */ + struct xsplice_symbol *symtab; /* All symbols. */ + char *strtab; /* Pointer to .strtab. */ + unsigned int nsyms; /* Nr of entries in .strtab and symbols. */ char name[XEN_XSPLICE_NAME_SIZE + 1];/* Name of it. */ }; @@ -97,6 +103,34 @@ static int verify_payload(const xen_sysctl_xsplice_upload_t *upload) return 0; } +uint64_t xsplice_symbols_lookup_by_name(const char *symname) +{ + struct payload *data; + unsigned int i; + uint64_t value = 0; + + spin_lock_recursive(&payload_lock); + + list_for_each_entry ( data, &payload_list, list ) + { + for ( i = 0; i < data->nsyms; i++ ) + { + if ( !data->symtab[i].new_symbol ) + continue; + + if ( !strcmp(data->symtab[i].name, symname) ) + { + value = data->symtab[i].value; + goto out; + } + } + } + +out: + spin_unlock_recursive(&payload_lock); + return value; +} + static int find_payload(const xen_xsplice_name_t *name, struct payload **f) { struct payload *data; @@ -199,6 +233,7 @@ static int move_payload(struct payload *payload, struct xsplice_elf *elf) (SHF_ALLOC|SHF_EXECINSTR) ) calc_section(&elf->sec[i], &size); } + payload->core_text_size = size; /* Compute rw data. */ for ( i = 0; i < elf->hdr->e_shnum; i++ ) @@ -217,6 +252,7 @@ static int move_payload(struct payload *payload, struct xsplice_elf *elf) !(elf->sec[i].sec->sh_flags & SHF_WRITE) ) calc_section(&elf->sec[i], &size); } + payload->core_size = size; size = PFN_UP(size); buf = arch_xsplice_alloc_payload(size, XSPLICE_VA_RX, &payload->mfn); @@ -322,10 +358,131 @@ static int prepare_payload(struct payload *payload, for ( j = 0; j < 24; j++ ) if ( f->pad[j] ) return -EINVAL; + + /* Lookup function's old address if not already resolved. */ + if ( !f->old_addr ) + { + f->old_addr = symbols_lookup_by_name(f->name); + if ( !f->old_addr ) + { + f->old_addr = xsplice_symbols_lookup_by_name(f->name); + if ( !f->old_addr ) + { + printk(XENLOG_ERR "%s%s: Could not resolve old address of %s\n", + XSPLICE, elf->name, f->name); + return -ENOENT; + } + } + dprintk(XENLOG_DEBUG, "%s%s: Resolved old address %s => 0x%"PRIx64"\n", + XSPLICE, elf->name, f->name, f->old_addr); + } } return 0; } +static bool_t is_core_symbol(const struct xsplice_elf *elf, + const struct xsplice_elf_sym *sym) +{ + if ( sym->sym->st_shndx == SHN_UNDEF || + sym->sym->st_shndx >= elf->hdr->e_shnum ) + return 0; + + return !!( (elf->sec[sym->sym->st_shndx].sec->sh_flags & SHF_ALLOC) && + (ELF64_ST_TYPE(sym->sym->st_info) == STT_OBJECT || + ELF64_ST_TYPE(sym->sym->st_info) == STT_FUNC) ); +} + +/* + * MUST be called after prepare_payload as we depend on payload->nfuncs. + */ +static int build_symbol_table(struct payload *payload, + const struct xsplice_elf *elf) +{ + unsigned int i, j, nsyms = 0; + size_t strtab_len = 0; + struct xsplice_symbol *symtab; + char *strtab; + + ASSERT(payload->nfuncs); + + /* Recall that 0 is always NULL. */ + for ( i = 1; i < elf->nsym; i++ ) + { + if ( is_core_symbol(elf, elf->sym + i) ) + { + nsyms++; + strtab_len += strlen(elf->sym[i].name) + 1; + } + } + + symtab = xmalloc_array(struct xsplice_symbol, nsyms); + if ( !symtab ) + return -ENOMEM; + + strtab = xmalloc_bytes(strtab_len); + if ( !strtab ) + { + xfree(symtab); + return -ENOMEM; + } + + nsyms = 0; + strtab_len = 0; + for ( i = 1; i < elf->nsym; i++ ) + { + if ( is_core_symbol(elf, elf->sym + i) ) + { + symtab[nsyms].name = strtab + strtab_len; + symtab[nsyms].size = elf->sym[i].sym->st_size; + symtab[nsyms].value = elf->sym[i].sym->st_value; + symtab[nsyms].new_symbol = 0; /* To be checked below. */ + strtab_len += strlcpy(strtab + strtab_len, elf->sym[i].name, + KSYM_NAME_LEN) + 1; + nsyms++; + } + } + + for ( i = 0; i < nsyms; i++ ) + { + bool_t found = 0; + + for ( j = 0; j < payload->nfuncs; j++ ) + { + if ( symtab[i].value == payload->funcs[j].new_addr ) + { + found = 1; + break; + } + } + + if ( !found ) + { + if ( xsplice_symbols_lookup_by_name(symtab[i].name) ) + { + printk(XENLOG_ERR "%s%s: duplicate new symbol: %s\n", + XSPLICE, elf->name, symtab[i].name); + xfree(symtab); + xfree(strtab); + return -EEXIST; + } + symtab[i].new_symbol = 1; + dprintk(XENLOG_DEBUG, "%s%s: new symbol %s\n", + XSPLICE, elf->name, symtab[i].name); + } + else + { + dprintk(XENLOG_DEBUG, "%s%s: overriding symbol %s\n", + XSPLICE, elf->name, symtab[i].name); + } + } + + payload->symtab = symtab; + payload->strtab = strtab; + payload->nsyms = nsyms; + + return 0; +} + /* * We MUST be holding the payload_lock spinlock. */ @@ -336,6 +493,8 @@ static void free_payload(struct payload *data) payload_cnt--; payload_version++; free_payload_data(data); + xfree(data->symtab); + xfree(data->strtab); xfree(data); } @@ -376,6 +535,8 @@ static int load_payload_data(struct payload *payload, void *raw, ssize_t len) if ( rc ) goto out; + rc = build_symbol_table(payload, &elf); + rc = secure_payload(payload, &elf); out: if ( rc ) @@ -440,6 +601,8 @@ static int xsplice_upload(xen_sysctl_xsplice_upload_t *upload) vfree(raw_data); if ( rc ) { + xfree(data->symtab); + xfree(data->strtab); xfree(data); } return rc; diff --git a/xen/common/xsplice_elf.c b/xen/common/xsplice_elf.c index 6128726..1ed133c 100644 --- a/xen/common/xsplice_elf.c +++ b/xen/common/xsplice_elf.c @@ -4,6 +4,7 @@ #include <xen/errno.h> #include <xen/lib.h> +#include <xen/symbols.h> #include <xen/xsplice_elf.h> #include <xen/xsplice.h> @@ -225,9 +226,21 @@ int xsplice_elf_resolve_symbols(struct xsplice_elf *elf) return -EINVAL; break; case SHN_UNDEF: - printk(XENLOG_ERR "%s%s: Unknown symbol: %s\n", - XSPLICE, elf->name, elf->sym[i].name); - return -ENOENT; + elf->sym[i].sym->st_value = symbols_lookup_by_name(elf->sym[i].name); + if ( !elf->sym[i].sym->st_value ) + { + elf->sym[i].sym->st_value = + xsplice_symbols_lookup_by_name(elf->sym[i].name); + if ( !elf->sym[i].sym->st_value ) + { + printk(XENLOG_ERR "%s%s: Unknown symbol: %s\n", + XSPLICE, elf->name, elf->sym[i].name); + return -ENOENT; + } + } + dprintk(XENLOG_DEBUG, "%s%s: Undefined symbol resolved: %s => 0x%"PRIx64"\n", + XSPLICE, elf->name, elf->sym[i].name, + elf->sym[i].sym->st_value); break; case SHN_ABS: dprintk(XENLOG_DEBUG, "%s%s: Absolute symbol: %s => 0x%"PRIx64"\n", diff --git a/xen/include/xen/symbols.h b/xen/include/xen/symbols.h index fe9ed8f..e6101d1 100644 --- a/xen/include/xen/symbols.h +++ b/xen/include/xen/symbols.h @@ -23,4 +23,6 @@ const char *symbols_lookup(unsigned long addr, int xensyms_read(uint32_t *symnum, char *type, uint64_t *address, char *name); +uint64_t symbols_lookup_by_name(const char *symname); + #endif /*_XEN_SYMBOLS_H*/ diff --git a/xen/include/xen/xsplice.h b/xen/include/xen/xsplice.h index b48a811..2e2fb78 100644 --- a/xen/include/xen/xsplice.h +++ b/xen/include/xen/xsplice.h @@ -33,8 +33,16 @@ struct xsplice_patch_func { /* Convenience define for printk. */ #define XSPLICE "xsplice: " +struct xsplice_symbol { + const char *name; + uint64_t value; + ssize_t size; + bool_t new_symbol; +}; + int xsplice_op(struct xen_sysctl_xsplice_op *); void check_for_xsplice_work(void); +uint64_t xsplice_symbols_lookup_by_name(const char *symname); /* Arch hooks. */ int arch_xsplice_verify_elf(const struct xsplice_elf *elf, void *data); -- 2.5.0 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |