Message ID | 1460000983-28170-9-git-send-email-konrad.wilk@oracle.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Konrad Rzeszutek Wilk writes ("[PATCH v6 08/24] xsplice: Add helper elf routines"): > From: Ross Lagerwall <ross.lagerwall@citrix.com> > > Add Elf routines and data structures in preparation for loading an > xSplice payload. > > We make an assumption that the max number of sections an ELF payload > can have is 64. We can in future make this be dependent on the > names of the sections and verifying against a list, but for right now > this suffices. > > Also we a whole lot of checks to make sure that the ELF payload > file is not corrupted nor that the offsets point past the file. This is good, but: ideally I would like to avoid conducting a detailed security review of this code. My understanding of this is that the purpose of this machinery is to supply binary runtime patches to the hypervisor. So I think someone who can inject malicious xsplice payloads can already control the host. Is that right ? If so then bugs in this loader cannot be any security impact. It might be worth mentioning somewhere that this loader must not be used for xsplice payloads for guest kernels. Ian.
>>> On 07.04.16 at 18:19, <Ian.Jackson@eu.citrix.com> wrote: > Konrad Rzeszutek Wilk writes ("[PATCH v6 08/24] xsplice: Add helper elf > routines"): >> From: Ross Lagerwall <ross.lagerwall@citrix.com> >> >> Add Elf routines and data structures in preparation for loading an >> xSplice payload. >> >> We make an assumption that the max number of sections an ELF payload >> can have is 64. We can in future make this be dependent on the >> names of the sections and verifying against a list, but for right now >> this suffices. >> >> Also we a whole lot of checks to make sure that the ELF payload >> file is not corrupted nor that the offsets point past the file. > > This is good, but: ideally I would like to avoid conducting a detailed > security review of this code. > > My understanding of this is that the purpose of this machinery is to > supply binary runtime patches to the hypervisor. So I think someone > who can inject malicious xsplice payloads can already control the > host. Is that right ? > > If so then bugs in this loader cannot be any security impact. Well, in a way this depends on re-visiting the position we take related to heavy disaggregation, which I mean to put up as a subject on the hackathon. Jan
On 07/04/16 17:19, Ian Jackson wrote: > Konrad Rzeszutek Wilk writes ("[PATCH v6 08/24] xsplice: Add helper elf routines"): >> From: Ross Lagerwall <ross.lagerwall@citrix.com> >> >> Add Elf routines and data structures in preparation for loading an >> xSplice payload. >> >> We make an assumption that the max number of sections an ELF payload >> can have is 64. We can in future make this be dependent on the >> names of the sections and verifying against a list, but for right now >> this suffices. >> >> Also we a whole lot of checks to make sure that the ELF payload >> file is not corrupted nor that the offsets point past the file. > This is good, but: ideally I would like to avoid conducting a detailed > security review of this code. > > My understanding of this is that the purpose of this machinery is to > supply binary runtime patches to the hypervisor. So I think someone > who can inject malicious xsplice payloads can already control the > host. Is that right ? Correct. > > If so then bugs in this loader cannot be any security impact. I agree. The reason for the checks is so Xen doesn't accidentally fall over a malformed ELF. Earlier versions of this patch were a bit too lax in trusting the integrity of the ELF image for my liking, which is why I specifically asked for better verification. > It might be worth mentioning somewhere that this loader must not be > used for xsplice payloads for guest kernels. I don't see how this is related. If the host admin wanted to patch guest kernels without using the kernels internal self-patching mechanism, it would be infinitely easier to do the patching from dom0, using toolstack mapping powers. ~Andrew
On Thu, Apr 07, 2016 at 05:19:37PM +0100, Ian Jackson wrote: > Konrad Rzeszutek Wilk writes ("[PATCH v6 08/24] xsplice: Add helper elf routines"): > > From: Ross Lagerwall <ross.lagerwall@citrix.com> > > > > Add Elf routines and data structures in preparation for loading an > > xSplice payload. > > > > We make an assumption that the max number of sections an ELF payload > > can have is 64. We can in future make this be dependent on the > > names of the sections and verifying against a list, but for right now > > this suffices. > > > > Also we a whole lot of checks to make sure that the ELF payload > > file is not corrupted nor that the offsets point past the file. > > This is good, but: ideally I would like to avoid conducting a detailed > security review of this code. > > My understanding of this is that the purpose of this machinery is to > supply binary runtime patches to the hypervisor. So I think someone > who can inject malicious xsplice payloads can already control the > host. Is that right ? <nods>The payload could be just fine from an ELF perspective and insert an patch that immediately calls BUG_ON(). > > If so then bugs in this loader cannot be any security impact. Yes. > > It might be worth mentioning somewhere that this loader must not be > used for xsplice payloads for guest kernels. How "fun" would that be! Also I do want signature checking on the payloads so at least we would only load ones that are trusted from a vendor. But that is v2 goal. > > Ian.
Andrew Cooper writes ("Re: [PATCH v6 08/24] xsplice: Add helper elf routines"): > On 07/04/16 17:19, Ian Jackson wrote: > > My understanding of this is that the purpose of this machinery is to > > supply binary runtime patches to the hypervisor. So I think someone > > who can inject malicious xsplice payloads can already control the > > host. Is that right ? > > Correct. OK, good, then from my point of view: Acked-by: Ian Jackson <ian.jackson@eu.citrix.com> > > It might be worth mentioning somewhere that this loader must not be > > used for xsplice payloads for guest kernels. > > I don't see how this is related. If the host admin wanted to patch > guest kernels without using the kernels internal self-patching > mechanism, it would be infinitely easier to do the patching from dom0, > using toolstack mapping powers. Well, maybe. I was worried about someone trying to make this ELF xsplice code dynamically patch a guest kernel at load time. That might seem like a convenient idea to them. But if you think it's not likely, then fine. Ian.
On 07/04/16 04:49, Konrad Rzeszutek Wilk wrote: > +static int elf_resolve_sections(struct xsplice_elf *elf, const void *data) > +{ > + struct xsplice_elf_sec *sec; > + unsigned int i; > + Elf_Off delta; > + int rc; > + > + /* xsplice_elf_load sanity checked e_shnum. */ > + sec = xmalloc_array(struct xsplice_elf_sec, elf->hdr->e_shnum); > + if ( !sec ) > + { > + printk(XENLOG_ERR XSPLICE"%s: Could not allocate memory for section table!\n", > + elf->name); > + return -ENOMEM; > + } > + > + elf->sec = sec; > + > + delta = elf->hdr->e_shoff + elf->hdr->e_shnum * elf->hdr->e_shentsize; Have we verified any of these to be sane yet? (i.e. what about calculation overflow?) (Edit: e_shnum yes, e_shentsize and e_shoff look to be no) > + if ( delta >= elf->len ) > + { > + dprintk(XENLOG_DEBUG, XSPLICE "%s: Section table is past end of payload!\n", > + elf->name); > + return -EINVAL; > + } (Mis)-alignment > +static int elf_get_sym(struct xsplice_elf *elf, const void *data) > +{ > + const struct xsplice_elf_sec *symtab_sec, *strtab_sec; > + struct xsplice_elf_sym *sym; > + unsigned int i, delta, offset, nsym; > + > + symtab_sec = elf->symtab; > + strtab_sec = elf->strtab; > + > + /* Pointers arithmetic to get file offset. */ > + offset = strtab_sec->data - data; > + > + /* Checked already in elf_resolve_sections, but just in case. */ > + ASSERT(offset == strtab_sec->sec->sh_offset); > + ASSERT(offset < elf->len && (offset + strtab_sec->sec->sh_size <= elf->len)); > + > + /* symtab_sec->data was computed in elf_resolve_sections. */ > + ASSERT((symtab_sec->sec->sh_offset + data) == symtab_sec->data); > + > + /* No need to check values as elf_resolve_sections did it. */ > + nsym = symtab_sec->sec->sh_size / symtab_sec->sec->sh_entsize; Has anything checked sh_entsize for being 0 or -1 ? Being unsigned, -1 cant happen, but nothing checks got being nonzero. With these things fixed, Reviewed-by: Andrew Cooper<andrew.cooper3@citrix.com>
On Fri, Apr 08, 2016 at 03:53:44PM +0100, Andrew Cooper wrote: > On 07/04/16 04:49, Konrad Rzeszutek Wilk wrote: > > +static int elf_resolve_sections(struct xsplice_elf *elf, const void *data) > > +{ > > + struct xsplice_elf_sec *sec; > > + unsigned int i; > > + Elf_Off delta; > > + int rc; > > + > > + /* xsplice_elf_load sanity checked e_shnum. */ > > + sec = xmalloc_array(struct xsplice_elf_sec, elf->hdr->e_shnum); > > + if ( !sec ) > > + { > > + printk(XENLOG_ERR XSPLICE"%s: Could not allocate memory for section table!\n", > > + elf->name); > > + return -ENOMEM; > > + } > > + > > + elf->sec = sec; > > + > > + delta = elf->hdr->e_shoff + elf->hdr->e_shnum * elf->hdr->e_shentsize; > > Have we verified any of these to be sane yet? (i.e. what about > calculation overflow?) > > (Edit: e_shnum yes, e_shentsize and e_shoff look to be no) e_shentsize is uint16_t e_shoff is uint64_t or uint32_t. Where you think a check against UINT_MAX/ULONG_MAX for the e_shoff? > > > + if ( delta >= elf->len ) This should have been > As I found out some linkers are happy to place that whole section table at the end of the file. Which means that this checks gets triggered. > > + { > > + dprintk(XENLOG_DEBUG, XSPLICE "%s: Section table is past end of payload!\n", > > + elf->name); > > + return -EINVAL; > > + } > > (Mis)-alignment > > > > +static int elf_get_sym(struct xsplice_elf *elf, const void *data) > > +{ > > + const struct xsplice_elf_sec *symtab_sec, *strtab_sec; > > + struct xsplice_elf_sym *sym; > > + unsigned int i, delta, offset, nsym; > > + > > + symtab_sec = elf->symtab; > > + strtab_sec = elf->strtab; > > + > > + /* Pointers arithmetic to get file offset. */ > > + offset = strtab_sec->data - data; > > + > > + /* Checked already in elf_resolve_sections, but just in case. */ > > + ASSERT(offset == strtab_sec->sec->sh_offset); > > + ASSERT(offset < elf->len && (offset + strtab_sec->sec->sh_size <= elf->len)); > > + > > + /* symtab_sec->data was computed in elf_resolve_sections. */ > > + ASSERT((symtab_sec->sec->sh_offset + data) == symtab_sec->data); > > + > > + /* No need to check values as elf_resolve_sections did it. */ > > + nsym = symtab_sec->sec->sh_size / symtab_sec->sec->sh_entsize; > > Has anything checked sh_entsize for being 0 or -1 ? Let me double-check. > > Being unsigned, -1 cant happen, but nothing checks got being nonzero. > > With these things fixed, Reviewed-by: Andrew > Cooper<andrew.cooper3@citrix.com>
On 08/04/16 22:26, Konrad Rzeszutek Wilk wrote: > On Fri, Apr 08, 2016 at 03:53:44PM +0100, Andrew Cooper wrote: >> On 07/04/16 04:49, Konrad Rzeszutek Wilk wrote: >>> +static int elf_resolve_sections(struct xsplice_elf *elf, const void *data) >>> +{ >>> + struct xsplice_elf_sec *sec; >>> + unsigned int i; >>> + Elf_Off delta; >>> + int rc; >>> + >>> + /* xsplice_elf_load sanity checked e_shnum. */ >>> + sec = xmalloc_array(struct xsplice_elf_sec, elf->hdr->e_shnum); >>> + if ( !sec ) >>> + { >>> + printk(XENLOG_ERR XSPLICE"%s: Could not allocate memory for section table!\n", >>> + elf->name); >>> + return -ENOMEM; >>> + } >>> + >>> + elf->sec = sec; >>> + >>> + delta = elf->hdr->e_shoff + elf->hdr->e_shnum * elf->hdr->e_shentsize; >> Have we verified any of these to be sane yet? (i.e. what about >> calculation overflow?) >> >> (Edit: e_shnum yes, e_shentsize and e_shoff look to be no) > e_shentsize is uint16_t > e_shoff is uint64_t or uint32_t. > > Where you think a check against UINT_MAX/ULONG_MAX for the e_shoff? e_shoff needs checking to be within elf->len alone, before a calculation involving e_shoff is checked against elf->len. Specifically, if it were say (uint64_t)-1 in the elf header, then this calculation would overflow and the check below would pass. Similarly, something should check e_shentsize against an exact value, given that its size is used to infer the layout of the section header fields. > >>> + if ( delta >= elf->len ) > This should have been > > > As I found out some linkers are happy to place that whole section table > at the end of the file. Which means that this checks gets triggered. This is normal. Traditionally, program headers live at the start of the image, and section headers at the end. The spec doesn't enforce this however. >>> + { >>> + dprintk(XENLOG_DEBUG, XSPLICE "%s: Section table is past end of payload!\n", >>> + elf->name); >>> + return -EINVAL; >>> + } >> (Mis)-alignment >> >> >>> +static int elf_get_sym(struct xsplice_elf *elf, const void *data) >>> +{ >>> + const struct xsplice_elf_sec *symtab_sec, *strtab_sec; >>> + struct xsplice_elf_sym *sym; >>> + unsigned int i, delta, offset, nsym; >>> + >>> + symtab_sec = elf->symtab; >>> + strtab_sec = elf->strtab; >>> + >>> + /* Pointers arithmetic to get file offset. */ >>> + offset = strtab_sec->data - data; >>> + >>> + /* Checked already in elf_resolve_sections, but just in case. */ >>> + ASSERT(offset == strtab_sec->sec->sh_offset); >>> + ASSERT(offset < elf->len && (offset + strtab_sec->sec->sh_size <= elf->len)); >>> + >>> + /* symtab_sec->data was computed in elf_resolve_sections. */ >>> + ASSERT((symtab_sec->sec->sh_offset + data) == symtab_sec->data); >>> + >>> + /* No need to check values as elf_resolve_sections did it. */ >>> + nsym = symtab_sec->sec->sh_size / symtab_sec->sec->sh_entsize; >> Has anything checked sh_entsize for being 0 or -1 ? > Let me double-check. Git grep says elf_resolve_sections() has if ( !elf->symtab->sec->sh_size || elf->symtab->sec->sh_entsize < sizeof(Elf_Sym) ) { dprintk(XENLOG_DEBUG, XSPLICE "%s: Symbol table header is corrupted!\n", elf->name); return -EINVAL; } I would check for !=, rather than < Nothing good can come of having sh_entsize being bigger than what we expect an Elf_Sym to be. Also be aware that Elf_Sym.sh_entsize and Ehdr.e_shentsize appear to be multiple locations containing the same information. I would also cross check them. ~Andrew
>>> On 09.04.16 at 00:10, <andrew.cooper3@citrix.com> wrote: > On 08/04/16 22:26, Konrad Rzeszutek Wilk wrote: >> On Fri, Apr 08, 2016 at 03:53:44PM +0100, Andrew Cooper wrote: >>> On 07/04/16 04:49, Konrad Rzeszutek Wilk wrote: >>>> + nsym = symtab_sec->sec->sh_size / symtab_sec->sec->sh_entsize; >>> Has anything checked sh_entsize for being 0 or -1 ? >> Let me double-check. > > Git grep says elf_resolve_sections() has > > if ( !elf->symtab->sec->sh_size || > elf->symtab->sec->sh_entsize < sizeof(Elf_Sym) ) > { > dprintk(XENLOG_DEBUG, XSPLICE "%s: Symbol table header is corrupted!\n", > elf->name); > return -EINVAL; > } > > I would check for !=, rather than < > > Nothing good can come of having sh_entsize being bigger than what we > expect an Elf_Sym to be. The whole purpose of recording the section table entry size is such that the structure could eventually get extended without breaking existing consumers. Hence != is not what the standard suggests to be used. > Also be aware that Elf_Sym.sh_entsize and Ehdr.e_shentsize appear to be > multiple locations containing the same information. I would also cross > check them. You mean Elf_Section.sh_entsize, which has a completely different purpose (see e.g. relocation sections). Jan
diff --git a/xen/common/Makefile b/xen/common/Makefile index 1e4bc70..afd84b6 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -59,6 +59,7 @@ obj-y += wait.o obj-$(CONFIG_XENOPROF) += xenoprof.o obj-y += xmalloc_tlsf.o obj-$(CONFIG_XSPLICE) += xsplice.o +obj-$(CONFIG_XSPLICE) += xsplice_elf.o obj-bin-$(CONFIG_X86) += $(foreach n,decompress bunzip2 unxz unlzma unlzo unlz4 earlycpio,$(n).init.o) diff --git a/xen/common/xsplice_elf.c b/xen/common/xsplice_elf.c new file mode 100644 index 0000000..b244d42 --- /dev/null +++ b/xen/common/xsplice_elf.c @@ -0,0 +1,348 @@ +/* + * Copyright (C) 2016 Citrix Systems R&D Ltd. + */ + +#include <xen/errno.h> +#include <xen/lib.h> +#include <xen/xsplice_elf.h> +#include <xen/xsplice.h> + +const struct xsplice_elf_sec *xsplice_elf_sec_by_name(const struct xsplice_elf *elf, + const char *name) +{ + unsigned int i; + + for ( i = 1; i < elf->hdr->e_shnum; i++ ) + { + if ( !strcmp(name, elf->sec[i].name) ) + return &elf->sec[i]; + } + + return NULL; +} + +static int elf_verify_strtab(const struct xsplice_elf_sec *sec) +{ + const Elf_Shdr *s; + const uint8_t *contents; + + s = sec->sec; + + if ( s->sh_type != SHT_STRTAB ) + return -EINVAL; + + if ( !s->sh_size ) + return -EOPNOTSUPP; + + contents = (const uint8_t *)sec->data; + + if ( contents[0] || contents[s->sh_size - 1] ) + return -EINVAL; + + return 0; +} + +static int elf_resolve_sections(struct xsplice_elf *elf, const void *data) +{ + struct xsplice_elf_sec *sec; + unsigned int i; + Elf_Off delta; + int rc; + + /* xsplice_elf_load sanity checked e_shnum. */ + sec = xmalloc_array(struct xsplice_elf_sec, elf->hdr->e_shnum); + if ( !sec ) + { + printk(XENLOG_ERR XSPLICE"%s: Could not allocate memory for section table!\n", + elf->name); + return -ENOMEM; + } + + elf->sec = sec; + + delta = elf->hdr->e_shoff + elf->hdr->e_shnum * elf->hdr->e_shentsize; + if ( delta >= elf->len ) + { + dprintk(XENLOG_DEBUG, XSPLICE "%s: Section table is past end of payload!\n", + elf->name); + return -EINVAL; + } + + for ( i = 1; i < elf->hdr->e_shnum; i++ ) + { + delta = elf->hdr->e_shoff + i * elf->hdr->e_shentsize; + + sec[i].sec = data + delta; + + delta = sec[i].sec->sh_offset; + + /* + * N.B. elf_resolve_section_names, elf_get_sym skip this check as + * we do it here. + */ + if ( delta && (delta + sec[i].sec->sh_size > elf->len) ) + { + dprintk(XENLOG_DEBUG, XSPLICE "%s: Section [%u] data is past end of payload!\n", + elf->name, i); + return -EINVAL; + } + + sec[i].data = data + delta; + /* Name is populated in xsplice_elf_sections_name. */ + sec[i].name = NULL; + + if ( sec[i].sec->sh_type == SHT_SYMTAB ) + { + if ( elf->symtab ) + { + dprintk(XENLOG_DEBUG, XSPLICE "%s: Unsupported multiple symbol tables!\n", + elf->name); + return -EOPNOTSUPP; + } + + elf->symtab = &sec[i]; + + /* + * elf->symtab->sec->sh_link would point to the right section + * but we hadn't finished parsing all the sections. + */ + if ( elf->symtab->sec->sh_link > elf->hdr->e_shnum ) + { + dprintk(XENLOG_DEBUG, XSPLICE + "%s: Symbol table idx (%u) to strtab past end (%u)\n", + elf->name, elf->symtab->sec->sh_link, + elf->hdr->e_shnum); + return -EINVAL; + } + } + } + + if ( !elf->symtab ) + { + dprintk(XENLOG_DEBUG, XSPLICE "%s: No symbol table found!\n", + elf->name); + return -EINVAL; + } + + if ( !elf->symtab->sec->sh_size || + elf->symtab->sec->sh_entsize < sizeof(Elf_Sym) ) + { + dprintk(XENLOG_DEBUG, XSPLICE "%s: Symbol table header is corrupted!\n", + elf->name); + return -EINVAL; + } + + /* + * There can be multiple SHT_STRTAB (.shstrtab, .strtab) so pick one + * associated with the symbol table. + */ + elf->strtab = &sec[elf->symtab->sec->sh_link]; + + rc = elf_verify_strtab(elf->strtab); + if ( rc ) + { + dprintk(XENLOG_DEBUG, XSPLICE "%s: String table section is corrupted\n", + elf->name); + } + + return rc; +} + +static int elf_resolve_section_names(struct xsplice_elf *elf, const void *data) +{ + const char *shstrtab; + unsigned int i; + Elf_Off offset, delta; + struct xsplice_elf_sec *sec; + int rc; + + /* + * The elf->sec[0 -> e_shnum] structures have been verified by + * elf_resolve_sections. Find file offset for section string table + * (normally called .shstrtab) + */ + sec = &elf->sec[elf->hdr->e_shstrndx]; + + rc = elf_verify_strtab(sec); + if ( rc ) + { + dprintk(XENLOG_DEBUG, XSPLICE "%s: Section string table is corrupted\n", + elf->name); + return rc; + } + + /* Verified in elf_resolve_sections but just in case. */ + offset = sec->sec->sh_offset; + ASSERT(offset < elf->len && (offset + sec->sec->sh_size <= elf->len)); + + shstrtab = data + offset; + + for ( i = 1; i < elf->hdr->e_shnum; i++ ) + { + delta = elf->sec[i].sec->sh_name; + + if ( delta && delta >= sec->sec->sh_size ) + { + dprintk(XENLOG_DEBUG, XSPLICE "%s: shstrtab [%u] data is past end of payload!\n", + elf->name, i); + return -EINVAL; + } + + elf->sec[i].name = shstrtab + delta; + } + + return 0; +} + +static int elf_get_sym(struct xsplice_elf *elf, const void *data) +{ + const struct xsplice_elf_sec *symtab_sec, *strtab_sec; + struct xsplice_elf_sym *sym; + unsigned int i, delta, offset, nsym; + + symtab_sec = elf->symtab; + strtab_sec = elf->strtab; + + /* Pointers arithmetic to get file offset. */ + offset = strtab_sec->data - data; + + /* Checked already in elf_resolve_sections, but just in case. */ + ASSERT(offset == strtab_sec->sec->sh_offset); + ASSERT(offset < elf->len && (offset + strtab_sec->sec->sh_size <= elf->len)); + + /* symtab_sec->data was computed in elf_resolve_sections. */ + ASSERT((symtab_sec->sec->sh_offset + data) == symtab_sec->data); + + /* No need to check values as elf_resolve_sections did it. */ + nsym = symtab_sec->sec->sh_size / symtab_sec->sec->sh_entsize; + + sym = xmalloc_array(struct xsplice_elf_sym, nsym); + if ( !sym ) + { + printk(XENLOG_ERR XSPLICE "%s: Could not allocate memory for symbols\n", + elf->name); + return -ENOMEM; + } + + /* So we don't leak memory. */ + elf->sym = sym; + + for ( i = 1; i < nsym; i++ ) + { + Elf_Sym *s = &((Elf_Sym *)symtab_sec->data)[i]; + + /* If st->name is STN_UNDEF zero, the check will always be true. */ + delta = s->st_name; + + if ( delta && (delta > strtab_sec->sec->sh_size) ) + { + dprintk(XENLOG_DEBUG, XSPLICE "%s: Symbol [%u] data is past end of payload!\n", + elf->name, i); + return -EINVAL; + } + + sym[i].sym = s; + sym[i].name = data + (delta + offset); + } + elf->nsym = nsym; + + return 0; +} + +static int xsplice_header_check(const struct xsplice_elf *elf) +{ + const Elf_Ehdr *hdr = elf->hdr; + + if ( sizeof(*elf->hdr) > elf->len ) + { + dprintk(XENLOG_DEBUG, XSPLICE "%s: Section header is bigger than payload!\n", + elf->name); + return -EINVAL; + } + + if ( !IS_ELF(*hdr) ) + { + printk(XENLOG_ERR XSPLICE "%s: Not an ELF payload!\n", elf->name); + return -EINVAL; + } + + if ( hdr->e_ident[EI_CLASS] != ELFCLASS64 || + hdr->e_ident[EI_DATA] != ELFDATA2LSB || + hdr->e_ident[EI_OSABI] != ELFOSABI_SYSV || + hdr->e_type != ET_REL || + hdr->e_phnum != 0 ) + { + printk(XENLOG_ERR XSPLICE "%s: Invalid ELF payload!\n", elf->name); + return -EOPNOTSUPP; + } + + if ( elf->hdr->e_shstrndx == SHN_UNDEF ) + { + dprintk(XENLOG_DEBUG, XSPLICE "%s: Section name idx is undefined!?\n", + elf->name); + return -EINVAL; + } + + /* Check that section name index is within the sections. */ + if ( elf->hdr->e_shstrndx >= elf->hdr->e_shnum ) + { + dprintk(XENLOG_DEBUG, XSPLICE "%s: Section name idx (%u) is past end of sections (%u)!\n", + elf->name, elf->hdr->e_shstrndx, elf->hdr->e_shnum); + return -EINVAL; + } + + if ( elf->hdr->e_shnum > 64 ) + { + dprintk(XENLOG_DEBUG, XSPLICE "%s: Too many (%u) sections!\n", + elf->name, elf->hdr->e_shnum); + return -EINVAL; + } + + return 0; +} + +int xsplice_elf_load(struct xsplice_elf *elf, const void *data) +{ + int rc; + + elf->hdr = data; + + rc = xsplice_header_check(elf); + if ( rc ) + return rc; + + rc = elf_resolve_sections(elf, data); + if ( rc ) + return rc; + + rc = elf_resolve_section_names(elf, data); + if ( rc ) + return rc; + + rc = elf_get_sym(elf, data); + if ( rc ) + return rc; + + return 0; +} + +void xsplice_elf_free(struct xsplice_elf *elf) +{ + xfree(elf->sec); + elf->sec = NULL; + xfree(elf->sym); + elf->sym = NULL; + elf->nsym = 0; + elf->name = NULL; + elf->len = 0; +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/xen/xsplice.h b/xen/include/xen/xsplice.h index 5c84851..00482d0 100644 --- a/xen/include/xen/xsplice.h +++ b/xen/include/xen/xsplice.h @@ -10,6 +10,9 @@ struct xen_sysctl_xsplice_op; #ifdef CONFIG_XSPLICE +/* Convenience define for printk. */ +#define XSPLICE "xsplice: " + int xsplice_op(struct xen_sysctl_xsplice_op *); #else diff --git a/xen/include/xen/xsplice_elf.h b/xen/include/xen/xsplice_elf.h new file mode 100644 index 0000000..3231639 --- /dev/null +++ b/xen/include/xen/xsplice_elf.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2016 Citrix Systems R&D Ltd. + */ + +#ifndef __XEN_XSPLICE_ELF_H__ +#define __XEN_XSPLICE_ELF_H__ + +#include <xen/types.h> +#include <xen/elfstructs.h> + +/* The following describes an Elf file as consumed by xSplice. */ +struct xsplice_elf_sec { + const Elf_Shdr *sec; /* Hooked up in elf_resolve_sections.*/ + const char *name; /* Human readable name hooked in + elf_resolve_section_names. */ + const void *data; /* Pointer to the section (done by + elf_resolve_sections). */ +}; + +struct xsplice_elf_sym { + Elf_Sym *sym; + const char *name; +}; + +struct xsplice_elf { + const char *name; /* Pointer to payload->name. */ + size_t len; /* Length of the ELF file. */ + const Elf_Ehdr *hdr; /* ELF file. */ + struct xsplice_elf_sec *sec; /* Array of sections, allocated by us. */ + struct xsplice_elf_sym *sym; /* Array of symbols , allocated by us. */ + unsigned int nsym; + const struct xsplice_elf_sec *symtab;/* Pointer to .symtab section - aka to sec[x]. */ + const struct xsplice_elf_sec *strtab;/* Pointer to .strtab section - aka to sec[y]. */ +}; + +const struct xsplice_elf_sec *xsplice_elf_sec_by_name(const struct xsplice_elf *elf, + const char *name); +int xsplice_elf_load(struct xsplice_elf *elf, const void *data); +void xsplice_elf_free(struct xsplice_elf *elf); + +#endif /* __XEN_XSPLICE_ELF_H__ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */