Exemplo n.º 1
0
static int
_elf_update_pointers(Elf *elf, char *outbuf, size_t len) {
    Elf_Scn *scn;
    Scn_Data *sd;
    char *data, *rawdata;

    elf_assert(elf);
    elf_assert(elf->e_data);
    elf_assert(!elf->e_parent);
    elf_assert(!elf->e_unmap_data);
    elf_assert(elf->e_kind == ELF_K_ELF);
    elf_assert(len >= EI_NIDENT);

    /* resize memory images */
    if (len <= elf->e_dsize) {
	/* don't shorten the memory image */
	data = elf->e_data;
    }
    else if ((data = (char*)realloc(elf->e_data, len))) {
	elf->e_dsize = len;
    }
    else {
	seterr(ERROR_IO_2BIG);
	return -1;
    }
    if (elf->e_rawdata == elf->e_data) {
	/* update frozen raw image */
	memcpy(data, outbuf, len);
	elf->e_data = elf->e_rawdata = data;
	/* cooked data is stored outside the raw image */
	return 0;
    }
    if (elf->e_rawdata) {
	/* update raw image */
	if (!(rawdata = (char*)realloc(elf->e_rawdata, len))) {
	    seterr(ERROR_IO_2BIG);
	    return -1;
	}
	memcpy(rawdata, outbuf, len);
	elf->e_rawdata = rawdata;
    }
    if (data == elf->e_data) {
	/* nothing more to do */
	return 0;
    }
    /* adjust internal pointers */
    for (scn = elf->e_scn_1; scn; scn = scn->s_link) {
	elf_assert(scn->s_magic == SCN_MAGIC);
	elf_assert(scn->s_elf == elf);
	if ((sd = scn->s_data_1)) {
	    elf_assert(sd->sd_magic == DATA_MAGIC);
	    elf_assert(sd->sd_scn == scn);
	    if (sd->sd_memdata && !sd->sd_free_data) {
		elf_assert(ptrinside(sd->sd_memdata, elf->e_data, elf->e_dsize));
		if (sd->sd_data.d_buf == sd->sd_memdata) {
		    newptr(sd->sd_memdata, elf->e_data, data);
		    sd->sd_data.d_buf = sd->sd_memdata;
		}
		else {
		    newptr(sd->sd_memdata, elf->e_data, data);
		}
	    }
	}
	if ((sd = scn->s_rawdata)) {
	    elf_assert(sd->sd_magic == DATA_MAGIC);
	    elf_assert(sd->sd_scn == scn);
	    if (sd->sd_memdata && sd->sd_free_data) {
		size_t off, len;

		if (elf->e_class == ELFCLASS32) {
		    off = scn->s_shdr32.sh_offset;
		    len = scn->s_shdr32.sh_size;
		}
#if __LIBELF64
		else if (elf->e_class == ELFCLASS64) {
		    off = scn->s_shdr64.sh_offset;
		    len = scn->s_shdr64.sh_size;
		}
#endif /* __LIBELF64 */
		else {
		    seterr(ERROR_UNIMPLEMENTED);
		    return -1;
		}
		if (!(rawdata = (char*)realloc(sd->sd_memdata, len))) {
		    seterr(ERROR_IO_2BIG);
		    return -1;
		}
		memcpy(rawdata, outbuf + off, len);
		if (sd->sd_data.d_buf == sd->sd_memdata) {
		    sd->sd_data.d_buf = rawdata;
		}
		sd->sd_memdata = rawdata;
	    }
	}
    }
    elf->e_data = data;
    return 0;
}
Exemplo n.º 2
0
static off_t
_elf32_write(Elf *elf, char *outbuf, size_t len) {
    Elf32_Ehdr *ehdr;
    Elf32_Shdr *shdr;
    Elf_Scn *scn;
    Scn_Data *sd;
    Elf_Data src;
    Elf_Data dst;
    unsigned encode;

    elf_assert(len);
    elf_assert(elf->e_ehdr);
    ehdr = (Elf32_Ehdr*)elf->e_ehdr;
    encode = ehdr->e_ident[EI_DATA];

    src.d_buf = ehdr;
    src.d_type = ELF_T_EHDR;
    src.d_size = _msize(ELFCLASS32, _elf_version, ELF_T_EHDR);
    src.d_version = _elf_version;
    dst.d_buf = outbuf;
    dst.d_size = ehdr->e_ehsize;
    dst.d_version = ehdr->e_version;
    if (!elf32_xlatetof(&dst, &src, encode)) {
	return -1;
    }

    if (elf->e_phnum) {
	src.d_buf = elf->e_phdr;
	src.d_type = ELF_T_PHDR;
	src.d_size = elf->e_phnum * _msize(ELFCLASS32, _elf_version, ELF_T_PHDR);
	src.d_version = _elf_version;
	dst.d_buf = outbuf + ehdr->e_phoff;
	dst.d_size = elf->e_phnum * ehdr->e_phentsize;
	dst.d_version = ehdr->e_version;
	if (!elf32_xlatetof(&dst, &src, encode)) {
	    return -1;
	}
    }

    for (scn = elf->e_scn_1; scn; scn = scn->s_link) {
	elf_assert(scn->s_magic == SCN_MAGIC);
	elf_assert(scn->s_elf == elf);

	src.d_buf = &scn->s_uhdr;
	src.d_type = ELF_T_SHDR;
	src.d_size = _msize(ELFCLASS32, EV_CURRENT, ELF_T_SHDR);
	src.d_version = EV_CURRENT;
	dst.d_buf = outbuf + ehdr->e_shoff + scn->s_index * ehdr->e_shentsize;
	dst.d_size = ehdr->e_shentsize;
	dst.d_version = ehdr->e_version;
	if (!elf32_xlatetof(&dst, &src, encode)) {
	    return -1;
	}

	if (scn->s_index == SHN_UNDEF) {
	    continue;
	}
	shdr = &scn->s_shdr32;
	if (shdr->sh_type == SHT_NULL || shdr->sh_type == SHT_NOBITS) {
	    continue;
	}
	/* XXX: this is probably no longer necessary */
	if (scn->s_data_1 && !elf_getdata(scn, NULL)) {
	    return -1;
	}
	for (sd = scn->s_data_1; sd; sd = sd->sd_link) {
	    elf_assert(sd->sd_magic == DATA_MAGIC);
	    elf_assert(sd->sd_scn == scn);
	    src = sd->sd_data;
	    if (!src.d_size) {
		continue;
	    }
	    if (!src.d_buf) {
		seterr(ERROR_NULLBUF);
		return -1;
	    }
	    dst.d_buf = outbuf + shdr->sh_offset + src.d_off;
	    dst.d_size = src.d_size;
	    dst.d_version = ehdr->e_version;
	    if (valid_type(src.d_type)) {
		size_t tmp;

		tmp = _elf32_xltsize(&src, dst.d_version, ELFDATA2LSB, 1);
		if (tmp == (size_t)-1) {
		    return -1;
		}
		dst.d_size = tmp;
	    }
	    else {
		src.d_type = ELF_T_BYTE;
	    }
	    if (!elf32_xlatetof(&dst, &src, encode)) {
		return -1;
	    }
	}
    }

    /* cleanup */
    if (elf->e_readable && _elf_update_pointers(elf, outbuf, len)) {
	return -1;
    }
    /* NOTE: ehdr is no longer valid! */
    ehdr = (Elf32_Ehdr*)elf->e_ehdr; elf_assert(ehdr);
    elf->e_encoding = ehdr->e_ident[EI_DATA];
    elf->e_version = ehdr->e_ident[EI_VERSION];
    elf->e_elf_flags &= ~ELF_F_DIRTY;
    elf->e_ehdr_flags &= ~ELF_F_DIRTY;
    elf->e_phdr_flags &= ~ELF_F_DIRTY;
    for (scn = elf->e_scn_1; scn; scn = scn->s_link) {
	scn->s_scn_flags &= ~ELF_F_DIRTY;
	scn->s_shdr_flags &= ~ELF_F_DIRTY;
	for (sd = scn->s_data_1; sd; sd = sd->sd_link) {
	    sd->sd_data_flags &= ~ELF_F_DIRTY;
	}
	if (elf->e_readable) {
	    shdr = &scn->s_shdr32;
	    scn->s_type = shdr->sh_type;
	    scn->s_size = shdr->sh_size;
	    scn->s_offset = shdr->sh_offset;
	}
    }
    elf->e_size = len;
    return len;
}
Exemplo n.º 3
0
static off_t
scn_data_layout(Elf_Scn *scn, unsigned v, unsigned type, size_t *algn, unsigned *flag) {
    Elf *elf = scn->s_elf;
    Elf_Data *data;
    int layout = (elf->e_elf_flags & ELF_F_LAYOUT) == 0;
    size_t scn_align = 1;
    size_t len = 0;
    Scn_Data *sd;
    size_t fsize;

    if (!(sd = scn->s_data_1)) {
	/* no data in section */
	*algn = scn_align;
	return (off_t)len;
    }
    /* load data from file, if any */
    if (!(data = elf_getdata(scn, NULL))) {
	return (off_t)-1;
    }
    elf_assert(data == &sd->sd_data);
    for (; sd; sd = sd->sd_link) {
	elf_assert(sd->sd_magic == DATA_MAGIC);
	elf_assert(sd->sd_scn == scn);

	if (!valid_version(sd->sd_data.d_version)) {
	    return (off_t)-1;
	}

	fsize = sd->sd_data.d_size;
	if (fsize && type != SHT_NOBITS && valid_type(sd->sd_data.d_type)) {
	    if (elf->e_class == ELFCLASS32) {
		fsize = _elf32_xltsize(&sd->sd_data, v, ELFDATA2LSB, 1);
	    }
#if __LIBELF64
	    else if (elf->e_class == ELFCLASS64) {
		fsize = _elf64_xltsize(&sd->sd_data, v, ELFDATA2LSB, 1);
	    }
#endif /* __LIBELF64 */
	    else {
		elf_assert(valid_class(elf->e_class));
		seterr(ERROR_UNIMPLEMENTED);
		return (off_t)-1;
	    }
	    if (fsize == (size_t)-1) {
		return (off_t)-1;
	    }
	}

	if (layout) {
	    align(len, sd->sd_data.d_align);
	    scn_align = max(scn_align, sd->sd_data.d_align);
	    rewrite(sd->sd_data.d_off, (off_t)len, sd->sd_data_flags);
	    len += fsize;
	}
	else {
	    len = max(len, sd->sd_data.d_off + fsize);
	}

	*flag |= sd->sd_data_flags;
    }
    *algn = scn_align;
    return (off_t)len;
}
Exemplo n.º 4
0
static off_t
_elf64_layout(Elf *elf, unsigned *flag) {
    int layout = (elf->e_elf_flags & ELF_F_LAYOUT) == 0;
    Elf64_Ehdr *ehdr = (Elf64_Ehdr*)elf->e_ehdr;
    size_t off = 0;
    unsigned version;
    unsigned encoding;
    size_t align_addr;
    size_t entsize;
    unsigned phnum;
    unsigned shnum;
    Elf_Scn *scn;

    *flag = elf->e_elf_flags | elf->e_phdr_flags;

    if ((version = ehdr->e_version) == EV_NONE) {
	version = EV_CURRENT;
    }
    if (!valid_version(version)) {
	seterr(ERROR_UNKNOWN_VERSION);
	return -1;
    }
    if ((encoding = ehdr->e_ident[EI_DATA]) == ELFDATANONE) {
	encoding = native_encoding;
    }
    if (!valid_encoding(encoding)) {
	seterr(ERROR_UNKNOWN_ENCODING);
	return -1;
    }
    entsize = _fsize(ELFCLASS64, version, ELF_T_EHDR);
    elf_assert(entsize);
    rewrite(ehdr->e_ehsize, entsize, elf->e_ehdr_flags);
    off = entsize;

    align_addr = _fsize(ELFCLASS64, version, ELF_T_ADDR);
    elf_assert(align_addr);

    if ((phnum = elf->e_phnum)) {
	entsize = _fsize(ELFCLASS64, version, ELF_T_PHDR);
	elf_assert(entsize);
	if (layout) {
	    align(off, align_addr);
	    rewrite(ehdr->e_phoff, off, elf->e_ehdr_flags);
	    off += phnum * entsize;
	}
	else {
	    off = max(off, ehdr->e_phoff + phnum * entsize);
	}
    }
    else {
	entsize = 0;
	if (layout) {
	    rewrite(ehdr->e_phoff, 0, elf->e_ehdr_flags);
	}
    }
    if (phnum >= PN_XNUM) {
	Elf_Scn *scn = elf->e_scn_1;
	Elf32_Shdr *shdr = &scn->s_shdr32;

	/* modify first section header, too! */
	elf_assert(scn);
	elf_assert(scn->s_index == 0);
	rewrite(shdr->sh_info, phnum, scn->s_shdr_flags);
	*flag |= scn->s_shdr_flags;
	phnum = PN_XNUM;
    }
    rewrite(ehdr->e_phnum, phnum, elf->e_ehdr_flags);
    rewrite(ehdr->e_phentsize, entsize, elf->e_ehdr_flags);

    for (scn = elf->e_scn_1, shnum = 0; scn; scn = scn->s_link, ++shnum) {
	Elf64_Shdr *shdr = &scn->s_shdr64;
	size_t scn_align = 1;
	off_t len;

	elf_assert(scn->s_index == shnum);

	*flag |= scn->s_scn_flags;

	if (scn->s_index == SHN_UNDEF) {
	    rewrite(shdr->sh_entsize, 0, scn->s_shdr_flags);
	    if (layout) {
		rewrite(shdr->sh_offset, 0, scn->s_shdr_flags);
		rewrite(shdr->sh_size, 0, scn->s_shdr_flags);
		rewrite(shdr->sh_addralign, 0, scn->s_shdr_flags);
	    }
	    *flag |= scn->s_shdr_flags;
	    continue;
	}
	if (shdr->sh_type == SHT_NULL) {
	    *flag |= scn->s_shdr_flags;
	    continue;
	}

	len = scn_data_layout(scn, version, shdr->sh_type, &scn_align, flag);
	if (len == -1) {
	    return -1;
	}

	/*
	 * Never override the program's choice.
	 */
	if (shdr->sh_entsize == 0) {
	    entsize = scn_entsize(elf, version, shdr->sh_type);
	    if (entsize > 1) {
		rewrite(shdr->sh_entsize, entsize, scn->s_shdr_flags);
	    }
	}

	if (layout) {
	    align(off, scn_align);
	    rewrite(shdr->sh_offset, off, scn->s_shdr_flags);
	    rewrite(shdr->sh_size, (size_t)len, scn->s_shdr_flags);
	    rewrite(shdr->sh_addralign, scn_align, scn->s_shdr_flags);

	    if (shdr->sh_type != SHT_NOBITS) {
		off += (size_t)len;
	    }
	}
	else if ((size_t)len > shdr->sh_size) {
	    seterr(ERROR_SCN2SMALL);
	    return -1;
	}
	else {
	    Elf_Scn *scn2;
	    size_t end1, end2;

	    end1 = shdr->sh_offset;
	    if (shdr->sh_type != SHT_NOBITS) {
		end1 += shdr->sh_size;
	    }
	    if (shdr->sh_offset < off) {
		/*
		 * check for overlapping sections
		 */
		for (scn2 = elf->e_scn_1; scn2; scn2 = scn2->s_link) {
		    if (scn2 == scn) {
			break;
		    }
		    end2 = scn2->s_shdr64.sh_offset;
		    if (scn2->s_shdr64.sh_type != SHT_NOBITS) {
			end2 += scn2->s_shdr64.sh_size;
		    }
		    if (end1 > scn2->s_shdr64.sh_offset
		     && end2 > shdr->sh_offset) {
			seterr(ERROR_SCN_OVERLAP);
			return -1;
		    }
		}
	    }
	    if (off < end1) {
		off = end1;
	    }
	}
	*flag |= scn->s_shdr_flags;
    }

    if (shnum) {
	entsize = _fsize(ELFCLASS64, version, ELF_T_SHDR);
	elf_assert(entsize);
	if (layout) {
	    align(off, align_addr);
	    rewrite(ehdr->e_shoff, off, elf->e_ehdr_flags);
	    off += shnum * entsize;
	}
	else {
	    off = max(off, ehdr->e_shoff + shnum * entsize);
	}
    }
    else {
	entsize = 0;
	if (layout) {
	    rewrite(ehdr->e_shoff, 0, elf->e_ehdr_flags);
	}
    }
    if (shnum >= SHN_LORESERVE) {
	Elf_Scn *scn = elf->e_scn_1;
	Elf64_Shdr *shdr = &scn->s_shdr64;

	elf_assert(scn->s_index == 0);
	rewrite(shdr->sh_size, shnum, scn->s_shdr_flags);
	*flag |= scn->s_shdr_flags;
	shnum = 0;
    }
    rewrite(ehdr->e_shnum, shnum, elf->e_ehdr_flags);
    rewrite(ehdr->e_shentsize, entsize, elf->e_ehdr_flags);

    rewrite(ehdr->e_ident[EI_MAG0], ELFMAG0, elf->e_ehdr_flags);
    rewrite(ehdr->e_ident[EI_MAG1], ELFMAG1, elf->e_ehdr_flags);
    rewrite(ehdr->e_ident[EI_MAG2], ELFMAG2, elf->e_ehdr_flags);
    rewrite(ehdr->e_ident[EI_MAG3], ELFMAG3, elf->e_ehdr_flags);
    rewrite(ehdr->e_ident[EI_CLASS], ELFCLASS64, elf->e_ehdr_flags);
    rewrite(ehdr->e_ident[EI_DATA], encoding, elf->e_ehdr_flags);
    rewrite(ehdr->e_ident[EI_VERSION], version, elf->e_ehdr_flags);
    rewrite(ehdr->e_version, version, elf->e_ehdr_flags);

    *flag |= elf->e_ehdr_flags;

    return off;
}
Exemplo n.º 5
0
Elf_Data*
elf_getdata(Elf_Scn *scn, Elf_Data *data) {
    Scn_Data *sd;
    Elf *elf;

    if (!scn) {
	return NULL;
    }
    elf_assert(scn->s_magic == SCN_MAGIC);
    if (scn->s_index == SHN_UNDEF) {
	seterr(ERROR_NULLSCN);
    }
    else if (data) {
	for (sd = scn->s_data_1; sd; sd = sd->sd_link) {
	    elf_assert(sd->sd_magic == DATA_MAGIC);
	    elf_assert(sd->sd_scn == scn);
	    if (data == &sd->sd_data) {
		/*
		 * sd_link allocated by elf_newdata().
		 */
		return &sd->sd_link->sd_data;
	    }
	}
	seterr(ERROR_SCNDATAMISMATCH);
    }
    else if ((sd = scn->s_data_1)) {
	elf_assert(sd->sd_magic == DATA_MAGIC);
	elf_assert(sd->sd_scn == scn);
	elf = scn->s_elf;
	elf_assert(elf);
	elf_assert(elf->e_magic == ELF_MAGIC);
	if (sd->sd_freeme) {
	    /* allocated by elf_newdata() */
	    return &sd->sd_data;
	}
	else if (scn->s_type == SHT_NULL) {
	    seterr(ERROR_NULLSCN);
	}
	else if (sd->sd_memdata) {
	    /* already cooked */
	    return &sd->sd_data;
	}
	else if (scn->s_offset < 0 || scn->s_offset > elf->e_size) {
	    seterr(ERROR_OUTSIDE);
	}
	else if (scn->s_type == SHT_NOBITS || !scn->s_size) {
	    /* no data to read */
	    return &sd->sd_data;
	}
	else if (scn->s_offset + scn->s_size > elf->e_size) {
	    seterr(ERROR_TRUNC_SCN);
	}
	else if (valid_class(elf->e_class)) {
	    return _elf_cook_scn(elf, scn, sd);
	}
	else {
	    seterr(ERROR_UNKNOWN_CLASS);
	}
    }
    return NULL;
}
Exemplo n.º 6
0
static Elf_Data*
_elf_cook_scn(Elf *elf, Elf_Scn *scn, Scn_Data *sd) {
    Elf_Data dst;
    Elf_Data src;
    int flag = 0;
    size_t dlen;

    elf_assert(elf->e_data);

    /*
     * Prepare source
     */
    src = sd->sd_data;
    src.d_version = elf->e_version;
    if (elf->e_rawdata) {
	src.d_buf = elf->e_rawdata + scn->s_offset;
    }
    else {
	src.d_buf = elf->e_data + scn->s_offset;
    }

    /*
     * Prepare destination (needs prepared source!)
     */
    dst = sd->sd_data;
    if (elf->e_class == ELFCLASS32) {
	dlen = _elf32_xltsize(&src, dst.d_version, elf->e_encoding, 0);
    }
#if __LIBELF64
    else if (elf->e_class == ELFCLASS64) {
	dlen = _elf64_xltsize(&src, dst.d_version, elf->e_encoding, 0);
    }
#endif /* __LIBELF64 */
    else {
	elf_assert(valid_class(elf->e_class));
	seterr(ERROR_UNIMPLEMENTED);
	return NULL;
    }
    if (dlen == (size_t)-1) {
	return NULL;
    }
    dst.d_size = dlen;
    if (elf->e_rawdata != elf->e_data && dst.d_size <= src.d_size) {
	dst.d_buf = elf->e_data + scn->s_offset;
    }
    else if (!(dst.d_buf = malloc(dst.d_size))) {
	seterr(ERROR_MEM_SCNDATA);
	return NULL;
    }
    else {
	flag = 1;
    }

    /*
     * Translate data
     */
    if (_elf_xlatetom(elf, &dst, &src)) {
	sd->sd_memdata = (char*)dst.d_buf;
	sd->sd_data = dst;
	if (!(sd->sd_free_data = flag)) {
	    elf->e_cooked = 1;
	}
	return &sd->sd_data;
    }

    if (flag) {
	free(dst.d_buf);
    }
    return NULL;
}
Exemplo n.º 7
0
Elf_Arsym*
elf_getarsym(Elf *elf, size_t *ptr) {
    Elf_Arsym *syms;
    size_t count;
    size_t tmp;
    size_t i;
    char *s;
    char *e;

    if (!ptr) {
	ptr = &tmp;
    }
    *ptr = 0;
    if (!elf) {
	return NULL;
    }
    elf_assert(elf->e_magic == ELF_MAGIC);
    if (elf->e_kind != ELF_K_AR) {
	seterr(ERROR_NOTARCHIVE);
	return NULL;
    }
    if (elf->e_symtab && !elf->e_free_syms) {
	if (elf->e_symlen < 4) {
	    seterr(ERROR_SIZE_ARSYMTAB);
	    return NULL;
	}
	count = __load_u32M(elf->e_symtab);
	if (elf->e_symlen < 4 * (count + 1)) {
	    seterr(ERROR_SIZE_ARSYMTAB);
	    return NULL;
	}
	if (!(syms = (Elf_Arsym*)malloc((count + 1) * sizeof(*syms)))) {
	    seterr(ERROR_MEM_ARSYMTAB);
	    return NULL;
	}
	s = elf->e_symtab + 4 * (count + 1);
	e = elf->e_symtab + elf->e_symlen;
	for (i = 0; i < count; i++, s++) {
	    syms[i].as_name = s;
	    while (s < e && *s) {
		s++;
	    }
	    if (s >= e) {
		seterr(ERROR_SIZE_ARSYMTAB);
		free(syms);
		return NULL;
	    }
	    elf_assert(!*s);
	    syms[i].as_hash = elf_hash(syms[i].as_name);
	    syms[i].as_off = __load_u32M(elf->e_symtab + 4 * (i + 1));
	}
	syms[count].as_name = NULL;
	syms[count].as_hash = ~0UL;
	syms[count].as_off = 0;
	elf->e_symtab = (char*)syms;
	elf->e_symlen = count + 1;
	elf->e_free_syms = 1;
    }
    *ptr = elf->e_symlen;
    return (Elf_Arsym*)elf->e_symtab;
}