Beispiel #1
0
char *
elf_strptr(Elf * elf, size_t ndx, size_t off)
{
	Elf_Scn *	s;
	Elf_Data *	d;
	char *		rc;

	if (elf == 0)
		return (0);
		
	extern const char *elf_macho_str_off(size_t off);
	
	if (elf->ed_kind == ELF_K_MACHO && (ndx == SHN_MACHO || ndx == SHN_MACHO_64))
		return (char *)elf_macho_str_off(off);

	if ((s = elf_getscn(elf, ndx)) == 0) {
		_elf_seterr(EREQ_STRSCN, 0);
		return (0);
	}
	READLOCKS(elf, s)
	if (elf->ed_class == ELFCLASS32) {
		Elf32_Shdr* sh = (Elf32_Shdr*)s->s_shdr;

		if ((sh == 0) || (sh->sh_type != SHT_STRTAB)) {
			_elf_seterr(EREQ_STRSCN, 0);
			READUNLOCKS(elf, s)
			return (0);
		}
Beispiel #2
0
size_t
_elf_outsync(int fd, char *p, size_t sz, unsigned int flag)
{
	if (flag != 0) {
		int	err;
		/*
		 * The value of MS_SYNC changed from zero to non-zero
		 * in SunOS 5.7.  This double call covers both cases.
		 */
		if ((fd = msync(p, sz, MS_SYNC)) == -1)
			fd = msync(p, sz, 0);
		if (fd == -1)
			err = errno;
		(void) munmap(p, sz);
		if (fd == 0)
			return (sz);
		_elf_seterr(EIO_SYNC, err);
		return (0);
	}
	if ((lseek(fd, 0L, SEEK_SET) == 0) &&
	    (write(fd, p, sz) == sz) && (fsync(fd) == 0)) {
		(void) free(p);
		return (sz);
	}
	_elf_seterr(EIO_WRITE, errno);
	return (0);
}
Beispiel #3
0
off_t
_elfxx_update(Elf * elf, Elf_Cmd cmd)
{
	size_t		sz;
	unsigned	u;
	Ehdr		*eh = elf->ed_ehdr;

	if (elf == 0)
		return (-1);

	ELFWLOCK(elf)
	switch (cmd) {
	default:
		_elf_seterr(EREQ_UPDATE, 0);
		ELFUNLOCK(elf)
		return (-1);

	case ELF_C_WRIMAGE:
		if ((elf->ed_myflags & EDF_WRITE) == 0) {
			_elf_seterr(EREQ_UPDWRT, 0);
			ELFUNLOCK(elf)
			return (-1);
		}
		break;
	case ELF_C_WRITE:
		if ((elf->ed_myflags & EDF_WRITE) == 0) {
			_elf_seterr(EREQ_UPDWRT, 0);
			ELFUNLOCK(elf)
			return (-1);
		}
Beispiel #4
0
char *
_elf_read(int fd, off_t off, size_t fsz)
{
	char		*p;

	if (fsz == 0)
		return (0);

	if (fd == -1) {
		_elf_seterr(EREQ_NOFD, 0);
		return (0);
	}

	if (lseek(fd, off, 0) != off) {
		_elf_seterr(EIO_SEEK, errno);
		return (0);
	}
	if ((p = (char *)malloc(fsz)) == 0) {
		_elf_seterr(EMEM_DATA, errno);
		return (0);
	}

	if (read(fd, p, fsz) != fsz) {
		_elf_seterr(EIO_READ, errno);
		free(p);
		return (0);
	}
	return (p);
}
Beispiel #5
0
/*
 * Initialize archive member
 */
Elf *
_elf_member(int fd, Elf * ref, unsigned flags)
{
	register Elf	*elf;
	Member		*mh;
	size_t		base;

	if (ref->ed_nextoff >= ref->ed_fsz)
		return (0);
	if (ref->ed_fd == -1)		/* disabled */
		fd = -1;
	if (flags & EDF_WRITE) {
		_elf_seterr(EREQ_ARRDWR, 0);
		return (0);
	}
	if (ref->ed_fd != fd) {
		_elf_seterr(EREQ_ARMEMFD, 0);
		return (0);
	}
	if ((_elf_vm(ref, ref->ed_nextoff, sizeof (struct ar_hdr)) !=
	    OK_YES) || ((mh = _elf_armem(ref,
	    ref->ed_ident + ref->ed_nextoff, ref->ed_fsz)) == 0))
		return (0);

	base = ref->ed_nextoff + sizeof (struct ar_hdr);
	if (ref->ed_fsz - base < mh->m_hdr.ar_size) {
		_elf_seterr(EFMT_ARMEMSZ, 0);
		return (0);
	}
	if ((elf = (Elf *)calloc(1, sizeof (Elf))) == 0) {
		_elf_seterr(EMEM_ELF, errno);
		return (0);
	}
	++ref->ed_activ;
	elf->ed_parent = ref;
	elf->ed_fd = fd;
	elf->ed_myflags |= flags;
	elf->ed_armem = mh;
	elf->ed_fsz = mh->m_hdr.ar_size;
	elf->ed_baseoff = ref->ed_baseoff + base;
	elf->ed_memoff = base - mh->m_slide;
	elf->ed_siboff = base + elf->ed_fsz + (elf->ed_fsz & 1);
	ref->ed_nextoff = elf->ed_siboff;
	elf->ed_image = ref->ed_image;
	elf->ed_imagesz = ref->ed_imagesz;
	elf->ed_vm = ref->ed_vm;
	elf->ed_vmsz = ref->ed_vmsz;
	elf->ed_ident = ref->ed_ident + base - mh->m_slide;

	/*
	 * If this member is the archive string table,
	 * we've already altered the bytes.
	 */

	if (ref->ed_arstroff == ref->ed_nextoff)
		elf->ed_status = ES_COOKED;
	return (elf);
}
Beispiel #6
0
char *
_elf_outmap(int fd, size_t sz, unsigned int *pflag)
{
	char	*p;

	/*
	 * Note: Some NFS implementations do not provide from enlarging a file
	 * via ftruncate(), thus this may fail with ENOSUP.  In this case the
	 * fall through to the calloc() mechanism will occur.
	 */
	if ((!*pflag) && (ftruncate(fd, (off_t)sz) == 0) &&
	    (p = mmap((char *)0, sz, PROT_READ+PROT_WRITE,
	    MAP_SHARED, fd, (off_t)0)) != (char *)-1) {
		*pflag = 1;
		return (p);
	}

	*pflag = 0;

	/*
	 * If mmap fails, try calloc.  Some file systems don't mmap.  Note, we
	 * use calloc rather than malloc, as ld(1) assumes that the backing
	 * storage it is working with is zero filled.
	 */
	if ((p = (char *)calloc(1, sz)) == 0)
		_elf_seterr(EMEM_OUT, errno);
	return (p);
}
Beispiel #7
0
/*
 * Handle the decision of whether the current linker can handle the
 * desired object size, and if not, which error to issue.
 *
 * Input is the desired size. On failure, an error has been issued
 * and 0 is returned. On success, 1 is returned.
 */
static int
test_size(Lword hi)
{
#ifndef _LP64			/* 32-bit linker */
	/*
	 * A 32-bit libelf is limited to a 2GB output file. This limit
	 * is due to the fact that off_t is a signed value, and that
	 * libelf cannot support large file support:
	 *	- ABI reasons
	 *	- Memory use generally is 2x output file size anyway,
	 *		so lifting the file size limit will just send
	 *		you crashing into the 32-bit VM limit.
	 * If the output is an ELFCLASS64 object, or an ELFCLASS32 object
	 * under 4GB, switching to the 64-bit version of libelf will help.
	 * However, an ELFCLASS32 object must not exceed 4GB.
	 */
	if (hi > INT_MAX) {	/* Bigger than 2GB */
#ifndef _ELF64
		/* ELFCLASS32 object is fundamentally too big? */
		if (hi > UINT_MAX) {
			_elf_seterr(EFMT_FBIG_CLASS32, 0);
			return (0);
		}
#endif				/* _ELF64 */

		/* Should switch to the 64-bit libelf? */
		_elf_seterr(EFMT_FBIG_LARGEFILE, 0);
		return (0);
	}
#endif				/* !_LP64 */


#if	defined(_LP64) && !defined(_ELF64)   /* 64-bit linker, ELFCLASS32 */
	/*
	 * A 64-bit linker can produce any size output
	 * file, but if the resulting file is ELFCLASS32,
	 * it must not exceed 4GB.
	 */
	if (hi > UINT_MAX) {
		_elf_seterr(EFMT_FBIG_CLASS32, 0);
		return (0);
	}
#endif

	return (1);
}
Beispiel #8
0
size_t
elf_rand(Elf * elf, size_t off)
{
	if (elf == 0)
		return (0);
	ELFWLOCK(elf)
	if (elf->ed_kind != ELF_K_AR) {
		_elf_seterr(EREQ_AR, 0);
		ELFUNLOCK(elf)
		return (0);
	}
Beispiel #9
0
Elf_Arsym *
elf_getarsym(Elf *elf, size_t *ptr)
{
	Byte		*as;
	size_t		sz;
	Elf_Arsym	*rc;
	int		is64;

	if (ptr != 0)
		*ptr = 0;
	if (elf == NULL)
		return (0);
	ELFRLOCK(elf);
	if (elf->ed_kind != ELF_K_AR) {
		ELFUNLOCK(elf);
		_elf_seterr(EREQ_AR, 0);
		return (0);
	}
	if ((as = (Byte *)elf->ed_arsym) == 0) {
		ELFUNLOCK(elf);
		return (0);
	}
	if (elf->ed_myflags & EDF_ASALLOC) {
		if (ptr != 0)
			*ptr = elf->ed_arsymsz;
		ELFUNLOCK(elf);
		/* LINTED */
		return ((Elf_Arsym *)as);
	}
	is64 = (elf->ed_myflags & EDF_ARSYM64) != 0;

	/*
	 * We're gonna need a write lock.
	 */
	ELFUNLOCK(elf)
	ELFWLOCK(elf)
	sz = elf->ed_arsymsz;
	if (_elf_vm(elf, (size_t)(as - (Byte *)elf->ed_ident), sz) !=
	    OK_YES) {
		ELFUNLOCK(elf);
		return (0);
	}
	if ((elf->ed_arsym = arsym(as, sz, &elf->ed_arsymsz, is64)) == 0) {
		ELFUNLOCK(elf);
		return (0);
	}
	elf->ed_myflags |= EDF_ASALLOC;
	if (ptr != 0)
		*ptr = elf->ed_arsymsz;
	rc = (Elf_Arsym *)elf->ed_arsym;
	ELFUNLOCK(elf);
	return (rc);
}
Beispiel #10
0
int
_elf_slide(Elf * elf)
{
	NOTE(ASSUMING_PROTECTED(*elf))
	Elf		*par = elf->ed_parent;
	size_t		sz, szof;
	register char	*dst;
	register char	*src = elf->ed_ident;

	if (par == 0 || par->ed_kind != ELF_K_AR)
		return (0);

	/*
	 * This code relies on other code to ensure
	 * the ar_hdr is big enough to move into.
	 */
	if (elf->ed_ident[EI_CLASS] == ELFCLASS64)
		szof = sizeof (Elf64);
	else
		szof = sizeof (Elf32);
	if ((sz = (size_t)(src - (char *)elf->ed_image) % szof) == 0)
		return (0);
	dst = src - sz;
	elf->ed_ident -= sz;
	elf->ed_memoff -= sz;
	elf->ed_armem->m_slide = sz;
	if (_elf_vm(par, elf->ed_memoff, sz + elf->ed_fsz) != OK_YES)
		return (-1);

	/*
	 * If the archive has been mmaped in, and we're going to slide it,
	 * and it wasn't open for write in the first place, and we've never
	 * done the mprotect() operation before, then do it now.
	 */
	if ((elf->ed_vm == 0) && ((elf->ed_myflags & EDF_WRITE) == 0) &&
	    ((elf->ed_myflags & EDF_MPROTECT) == 0)) {
		if (mprotect((char *)elf->ed_image, elf->ed_imagesz,
		    PROT_READ|PROT_WRITE) == -1) {
			_elf_seterr(EIO_VM, errno);
			return (-1);
		}
		elf->ed_myflags |= EDF_MPROTECT;
	}

	if (memmove((void *)dst, (const void *)src, elf->ed_fsz) != (void *)dst)
		return (-1);
	else
		return (0);
}
Beispiel #11
0
Dnode *
_elf_dnode()
{
	register Dnode	*d;

	if ((d = (Dnode *)malloc(sizeof (Dnode))) == 0) {
		_elf_seterr(EMEM_DNODE, errno);
		return (0);
	}
	NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*d))
	*d = _elf_dnode_init;
	d->db_myflags = DBF_ALLOC;
	NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*d))
	return (d);
}
Beispiel #12
0
Phdr *
elf_newphdr(Elf * elf, size_t count)
{
	Elf_Void *	ph;
	size_t		sz;
	Phdr *		rc;
	unsigned	work;

	if (elf == 0)
		return (0);
	ELFRLOCK(elf)
	if (elf->ed_class != ELFCLASS) {
		_elf_seterr(EREQ_CLASS, 0);
		ELFUNLOCK(elf)
		return (0);
	}
Beispiel #13
0
Elf *
_elf_regular(int fd, unsigned flags)		/* initialize regular file */
{
	Elf		*elf;

	if ((elf = (Elf *)calloc(1, sizeof (Elf))) == 0) {
		_elf_seterr(EMEM_ELF, errno);
		return (0);
	}

	NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*elf))
	elf->ed_fd = fd;
	elf->ed_myflags |= flags;
	if (_elf_inmap(elf) != OK_YES) {
		free(elf);
		return (0);
	}
	NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*elf))
	return (elf);
}
Beispiel #14
0
Elf *
_elf_config(Elf * elf)
{
	char *		base;
	unsigned	encode;

	ELFRWLOCKINIT(&elf->ed_rwlock);

	/*
	 * Determine if this is a ELF file.
	 */
	base = elf->ed_ident;
	if ((elf->ed_fsz >= EI_NIDENT) &&
	    (_elf_vm(elf, (size_t)0, (size_t)EI_NIDENT) == OK_YES) &&
	    (base[EI_MAG0] == ELFMAG0) &&
	    (base[EI_MAG1] == ELFMAG1) &&
	    (base[EI_MAG2] == ELFMAG2) &&
	    (base[EI_MAG3] == ELFMAG3)) {
		elf->ed_kind = ELF_K_ELF;
		elf->ed_class = base[EI_CLASS];
		elf->ed_encode = base[EI_DATA];
		if ((elf->ed_version = base[EI_VERSION]) == 0)
			elf->ed_version = 1;
		elf->ed_identsz = EI_NIDENT;

		/*
		 * Allow writing only if originally specified read only.
		 * This is only necessary if the file must be translating
		 * from one encoding to another.
		 */
		ELFACCESSDATA(encode, _elf_encode)
		if ((elf->ed_vm == 0) && ((elf->ed_myflags & EDF_WRITE) == 0) &&
		    (elf->ed_encode != encode)) {
			if (mprotect((char *)elf->ed_image, elf->ed_imagesz,
			    PROT_READ|PROT_WRITE) == -1) {
				_elf_seterr(EIO_VM, errno);
				return (0);
			}
		}
		return (elf);
	}
Beispiel #15
0
/*
 * Convert ar_hdr to Member
 *	Converts ascii file representation to the binary memory values.
 */
Member *
_elf_armem(Elf *elf, char *file, size_t fsz)
{
	register struct ar_hdr	*f = (struct ar_hdr *)file;
	register Member		*m;
	register Memlist	*l, * ol;
	register Memident	*i;

	if (fsz < sizeof (struct ar_hdr)) {
		_elf_seterr(EFMT_ARHDRSZ, 0);
		return (0);
	}

	/*
	 * Determine in this member has already been processed
	 */
	for (l = elf->ed_memlist, ol = l; l; ol = l, l = l->m_next)
		for (i = (Memident *)(l + 1); i < l->m_free; i++)
			if (i->m_offset == file)
				return (i->m_member);

	if (f->ar_fmag[0] != fmag[0] || f->ar_fmag[1] != fmag[1]) {
		_elf_seterr(EFMT_ARFMAG, 0);
		return (0);
	}

	/*
	 * Allocate a new member structure and assign it to the next free
	 * free memlist ident.
	 */
	if ((m = (Member *)malloc(sizeof (Member))) == 0) {
		_elf_seterr(EMEM_ARMEM, errno);
		return (0);
	}
	if ((elf->ed_memlist == 0) || (ol->m_free == ol->m_end)) {
		if ((l = (Memlist *)malloc(sizeof (Memlist) +
		    (sizeof (Memident) * MEMIDENTNO))) == 0) {
			_elf_seterr(EMEM_ARMEM, errno);
			return (0);
		}
		l->m_next = 0;
		l->m_free = (Memident *)(l + 1);
		l->m_end = (Memident *)((uintptr_t)l->m_free +
		    (sizeof (Memident) * MEMIDENTNO));

		if (elf->ed_memlist == 0)
			elf->ed_memlist = l;
		else
			ol->m_next = l;
		ol = l;
	}
	ol->m_free->m_offset = file;
	ol->m_free->m_member = m;
	ol->m_free++;

	m->m_err = 0;
	(void) memcpy(m->m_name, f->ar_name, ARSZ(ar_name));
	m->m_name[ARSZ(ar_name)] = '\0';
	m->m_hdr.ar_name = m->m_name;
	(void) memcpy(m->m_raw, f->ar_name, ARSZ(ar_name));
	m->m_raw[ARSZ(ar_name)] = '\0';
	m->m_hdr.ar_rawname = m->m_raw;
	m->m_slide = 0;

	/*
	 * Classify file name.
	 * If a name error occurs, delay until getarhdr().
	 */

	if (f->ar_name[0] != '/') {	/* regular name */
		register char	*p;

		p = &m->m_name[sizeof (m->m_name)];
		while (*--p != '/')
			if (p <= m->m_name)
				break;
		*p = '\0';
	} else if (f->ar_name[1] >= '0' && f->ar_name[1] <= '9') { /* strtab */
		register unsigned long	j;

		j = _elf_number(&f->ar_name[1],
		    &f->ar_name[ARSZ(ar_name)], 10);
		if (j < elf->ed_arstrsz)
			m->m_hdr.ar_name = elf->ed_arstr + j;
		else {
			m->m_hdr.ar_name = 0;
			/*LINTED*/ /* MSG_INTL(EFMT_ARSTRNM) */
			m->m_err = (int)EFMT_ARSTRNM;
		}
	} else if (f->ar_name[1] == ' ')			/* "/" */
		m->m_name[1] = '\0';
	else if (f->ar_name[1] == '/' && f->ar_name[2] == ' ')	/* "//" */
		m->m_name[2] = '\0';
	else if (f->ar_name[1] == 'S' && f->ar_name[2] == 'Y' &&
	    f->ar_name[3] == 'M' && f->ar_name[4] == '6' &&
	    f->ar_name[5] == '4' && f->ar_name[6] == '/' &&
	    f->ar_name[7] == ' ')				/* "/SYM64/" */
		m->m_name[7] = '\0';
	else {							/* "/?" */
		m->m_hdr.ar_name = 0;
		/*LINTED*/ /* MSG_INTL(EFMT_ARUNKNM) */
		m->m_err = (int)EFMT_ARUNKNM;
	}

	m->m_hdr.ar_date = (time_t)_elf_number(f->ar_date,
	    &f->ar_date[ARSZ(ar_date)], 10);
	/* LINTED */
	m->m_hdr.ar_uid = (uid_t)_elf_number(f->ar_uid,
	    &f->ar_uid[ARSZ(ar_uid)], 10);
	/* LINTED */
	m->m_hdr.ar_gid = (gid_t)_elf_number(f->ar_gid,
	    &f->ar_gid[ARSZ(ar_gid)], 10);
	/* LINTED */
	m->m_hdr.ar_mode = (mode_t)_elf_number(f->ar_mode,
	    &f->ar_mode[ARSZ(ar_mode)], 8);
	m->m_hdr.ar_size = (off_t)_elf_number(f->ar_size,
	    &f->ar_size[ARSZ(ar_size)], 10);

	return (m);
}
Beispiel #16
0
void _SHIM_elf_seterr(int x) { _elf_seterr( 0, x); }
Beispiel #17
0
static size_t
_elf_upd_usr(Elf * elf)
{
	NOTE(ASSUMING_PROTECTED(*elf))
	Lword		hi;
	Elf_Scn *	s;
	register Lword	sz;
	Ehdr *		eh = elf->ed_ehdr;
	unsigned	ver = eh->e_version;
	register char	*p = (char *)eh->e_ident;


	/*
	 * Ehdr and Phdr table go first
	 */
	p[EI_MAG0] = ELFMAG0;
	p[EI_MAG1] = ELFMAG1;
	p[EI_MAG2] = ELFMAG2;
	p[EI_MAG3] = ELFMAG3;
	p[EI_CLASS] = ELFCLASS;
	/* LINTED */
	p[EI_VERSION] = (Byte)ver;
	hi = elf_fsize(ELF_T_EHDR, 1, ver);
	/* LINTED */
	eh->e_ehsize = (Half)hi;

	/*
	 * If phnum is zero, phoff "should" be zero too,
	 * but the application is responsible for it.
	 * Allow a non-zero value here and update the
	 * hi water mark accordingly.
	 */

	if (eh->e_phnum != 0)
		/* LINTED */
		eh->e_phentsize = (Half)elf_fsize(ELF_T_PHDR, 1, ver);
	else
		eh->e_phentsize = 0;
	if ((sz = eh->e_phoff + eh->e_phentsize * eh->e_phnum) > hi)
		hi = sz;

	/*
	 * Loop through sections, skipping index zero.
	 * Compute section size before changing hi.
	 * Allow null buffers for NOBITS.
	 */

	if ((s = elf->ed_hdscn) == 0)
		eh->e_shnum = 0;
	else {
		eh->e_shnum = 1;
		*(Shdr*)s->s_shdr = _elf_snode_init.sb_shdr;
		s = s->s_next;
	}
	for (; s != 0; s = s->s_next) {
		register Dnode	*d;
		register Lword	fsz, j;
		Shdr *sh = s->s_shdr;

		if ((s->s_myflags & SF_READY) == 0)
			(void) _elfxx_cookscn(s);

		++eh->e_shnum;
		sz = 0;
		for (d = s->s_hdnode; d != 0; d = d->db_next) {
			if ((fsz = elf_fsize(d->db_data.d_type, 1,
			    ver)) == 0)
				return (0);
			j = _elf_msize(d->db_data.d_type, ver);
			fsz *= (d->db_data.d_size / j);
			d->db_osz = (size_t)fsz;

			if ((sh->sh_type != SHT_NOBITS) &&
			    ((j = (d->db_data.d_off + d->db_osz)) > sz))
				sz = j;
		}
		if (sh->sh_size < sz) {
			_elf_seterr(EFMT_SCNSZ, 0);
			return (0);
		}
		if ((sh->sh_type != SHT_NOBITS) &&
		    (hi < sh->sh_offset + sh->sh_size))
			hi = sh->sh_offset + sh->sh_size;
	}

	/*
	 * Shdr table last.  Comment above for phnum/phoff applies here.
	 */
	if (eh->e_shnum != 0)
		/* LINTED */
		eh->e_shentsize = (Half)elf_fsize(ELF_T_SHDR, 1, ver);
	else
		eh->e_shentsize = 0;

	if ((sz = eh->e_shoff + eh->e_shentsize * eh->e_shnum) > hi)
		hi = sz;

#ifdef TEST_SIZE
	if (test_size(hi) == 0)
		return (0);
#endif

	return ((size_t)hi);
}
Beispiel #18
0
static Elf_Void *
arsym(Byte *off, size_t sz, size_t *e, int is64)
{
	char		*endstr = (char *)off + sz;
	register char	*str;
	Byte		*endoff;
	Elf_Void	*oas;
	size_t		eltsize = is64 ? 8 : 4;

	{
		register size_t	n;

		if (is64) {
			if (sz < 8 || (sz - 8) / 8 < (n = get8(off))) {
				_elf_seterr(EFMT_ARSYMSZ, 0);
				return (0);
			}
		} else {
			if (sz < 4 || (sz - 4) / 4 < (n = get4(off))) {
				_elf_seterr(EFMT_ARSYMSZ, 0);
				return (0);
			}
		}
		off += eltsize;
		endoff = off + n * eltsize;

		/*
		 * string table must be present, null terminated
		 */

		if (((str = (char *)endoff) >= endstr) ||
		    (*(endstr - 1) != '\0')) {
			_elf_seterr(EFMT_ARSYM, 0);
			return (0);
		}

		/*
		 * overflow can occur here, but not likely
		 */

		*e = n + 1;
		n = sizeof (Elf_Arsym) * (n + 1);
		if ((oas = malloc(n)) == 0) {
			_elf_seterr(EMEM_ARSYM, errno);
			return (0);
		}
	}
	{
		register Elf_Arsym	*as = (Elf_Arsym *)oas;

		while (off < endoff) {
			if (str >= endstr) {
				_elf_seterr(EFMT_ARSYMSTR, 0);
				free(oas);
				return (0);
			}
			if (is64)
				as->as_off = get8(off);
			else
				as->as_off = get4(off);
			as->as_name = str;
			as->as_hash = elf_hash(str);
			++as;
			off += eltsize;
			while (*str++ != '\0')
				/* LINTED */
				;
		}
		as->as_name = 0;
		as->as_off = 0;
		as->as_hash = ~(unsigned long)0L;
	}
	return (oas);
}
Beispiel #19
0
/*
 * Initial archive processing
 *	An archive may have two special members.
 *
 *	A symbol table, named / or /SYM64/, must be first if it is present.
 *	Both forms use the same layout differing in the width of the
 *	integer type used (32 or 64-bit respectively).
 *
 *	A long name string table, named //, must precede all "normal"
 *	members. This string table is used to hold the names of archive
 *	members with names that are longer than 15 characters. It should not
 *	be confused with the string table found at the end of the symbol
 *	table, which is used to hold symbol names.
 *
 *	This code "peeks" at headers but doesn't change them.
 *	Later processing wants original headers.
 *
 *	String table is converted, changing '/' name terminators
 *	to nulls.  The last byte in the string table, which should
 *	be '\n', is set to nil, guaranteeing null termination.  That
 *	byte should be '\n', but this code doesn't check.
 *
 *	The symbol table conversion is delayed until needed.
 */
void
_elf_arinit(Elf * elf)
{
	char				*base = elf->ed_ident;
	register char			*end = base + elf->ed_fsz;
	register struct ar_hdr		*a;
	register char			*hdr = base + SARMAG;
	register char			*mem;
	int				j;
	size_t				sz = SARMAG;

	elf->ed_status = ES_COOKED;
	elf->ed_nextoff = SARMAG;
	for (j = 0; j < 2; ++j)	 {	/* 2 special members */
		unsigned long	n;

		if (((end - hdr) < sizeof (struct ar_hdr)) ||
		    (_elf_vm(elf, (size_t)(SARMAG),
		    sizeof (struct ar_hdr)) != OK_YES))
			return;

		a = (struct ar_hdr *)hdr;
		mem = (char *)a + sizeof (struct ar_hdr);
		n = _elf_number(a->ar_size, &a->ar_size[ARSZ(ar_size)], 10);
		if ((end - mem < n) || (a->ar_name[0] != '/') ||
		    ((sz = n) != n)) {
			return;
		}

		hdr = mem + sz;
		if (a->ar_name[1] == ' ') {	/* 32-bit symbol table */
			elf->ed_arsym = mem;
			elf->ed_arsymsz = sz;
			elf->ed_arsymoff = (char *)a - base;
		} else if (a->ar_name[1] == '/' && a->ar_name[2] == ' ') {
						/* Long name string table */
			int	k;

			if (_elf_vm(elf, (size_t)(mem - elf->ed_ident),
			    sz) != OK_YES)
				return;
			if (elf->ed_vm == 0) {
				char	*nmem;
				if ((nmem = malloc(sz)) == 0) {
					_elf_seterr(EMEM_ARSTR, errno);
					return;
				}
				(void) memcpy(nmem, mem, sz);
				elf->ed_myflags |= EDF_ASTRALLOC;
				mem = nmem;
			}

			elf->ed_arstr = mem;
			elf->ed_arstrsz = sz;
			elf->ed_arstroff = (char *)a - base;
			for (k = 0; k < sz; k++) {
				if (*mem == '/')
					*mem = '\0';
				++mem;
			}
			*(mem - 1) = '\0';
		} else if (a->ar_name[1] == 'S' && a->ar_name[2] == 'Y' &&
		    a->ar_name[3] == 'M' && a->ar_name[4] == '6' &&
		    a->ar_name[5] == '4' && a->ar_name[6] == '/' &&
		    a->ar_name[7] == ' ') {
						/* 64-bit symbol table */
			elf->ed_arsym = mem;
			elf->ed_arsymsz = sz;
			elf->ed_arsymoff = (char *)a - base;
			elf->ed_myflags |= EDF_ARSYM64;
		} else {
			return;
		}
		hdr += sz & 1;
	}
}
Beispiel #20
0
static size_t
_elf_upd_lib(Elf * elf)
{
	NOTE(ASSUMING_PROTECTED(*elf))
	Lword		hi;
	Lword		hibit;
	Elf_Scn *	s;
	register Xword	sz;
	Ehdr *		eh = elf->ed_ehdr;
	unsigned	ver = eh->e_version;
	register char	*p = (char *)eh->e_ident;
	size_t		scncnt;

	/*
	 * Ehdr and Phdr table go first
	 */
	p[EI_MAG0] = ELFMAG0;
	p[EI_MAG1] = ELFMAG1;
	p[EI_MAG2] = ELFMAG2;
	p[EI_MAG3] = ELFMAG3;
	p[EI_CLASS] = ELFCLASS;
	/* LINTED */
	p[EI_VERSION] = (Byte)ver;
	hi = elf_fsize(ELF_T_EHDR, 1, ver);
	/* LINTED */
	eh->e_ehsize = (Half)hi;
	if (eh->e_phnum != 0) {
		/* LINTED */
		eh->e_phentsize = (Half)elf_fsize(ELF_T_PHDR, 1, ver);
		/* LINTED */
		eh->e_phoff = (Off)hi;
		hi += eh->e_phentsize * eh->e_phnum;
	} else {
		eh->e_phoff = 0;
		eh->e_phentsize = 0;
	}

	/*
	 * Obtain the first section header.  Typically, this section has NULL
	 * contents, however in the case of Extended ELF Sections this section
	 * is used to hold an alternative e_shnum, e_shstrndx and e_phnum.
	 * On initial allocation (see _elf_snode) the elements of this section
	 * would have been zeroed.  The e_shnum is initialized later, after the
	 * section header count has been determined.  The e_shstrndx and
	 * e_phnum may have already been initialized by the caller (for example,
	 * gelf_update_shdr() in mcs(1)).
	 */
	if ((s = elf->ed_hdscn) == 0) {
		eh->e_shnum = 0;
		scncnt = 0;
	} else {
		s = s->s_next;
		scncnt = 1;
	}

	/*
	 * Loop through sections.  Compute section size before changing hi.
	 * Allow null buffers for NOBITS.
	 */
	hibit = 0;
	for (; s != 0; s = s->s_next) {
		register Dnode	*d;
		register Lword	fsz, j;
		Shdr *sh = s->s_shdr;

		scncnt++;
		if (sh->sh_type == SHT_NULL) {
			*sh = _elf_snode_init.sb_shdr;
			continue;
		}

		if ((s->s_myflags & SF_READY) == 0)
			(void) _elfxx_cookscn(s);

		sh->sh_addralign = 1;
		if ((sz = (Xword)_elf_entsz(sh->sh_type, ver)) != 0)
			/* LINTED */
			sh->sh_entsize = (Half)sz;
		sz = 0;
		for (d = s->s_hdnode; d != 0; d = d->db_next) {
			if ((fsz = elf_fsize(d->db_data.d_type,
			    1, ver)) == 0)
				return (0);

			j = _elf_msize(d->db_data.d_type, ver);
			fsz *= (d->db_data.d_size / j);
			d->db_osz = (size_t)fsz;
			if ((j = d->db_data.d_align) > 1) {
				if (j > sh->sh_addralign)
					sh->sh_addralign = (Xword)j;

				if (sz % j != 0)
					sz += j - sz % j;
			}
			d->db_data.d_off = (off_t)sz;
			d->db_xoff = sz;
			sz += (Xword)fsz;
		}

		sh->sh_size = sz;
		/*
		 * We want to take into account the offsets for NOBITS
		 * sections and let the "sh_offsets" point to where
		 * the section would 'conceptually' fit within
		 * the file (as required by the ABI).
		 *
		 * But - we must also make sure that the NOBITS does
		 * not take up any actual space in the file.  We preserve
		 * the actual offset into the file in the 'hibit' variable.
		 * When we come to the first non-NOBITS section after a
		 * encountering a NOBITS section the hi counter is restored
		 * to its proper place in the file.
		 */
		if (sh->sh_type == SHT_NOBITS) {
			if (hibit == 0)
				hibit = hi;
		} else {
			if (hibit) {
				hi = hibit;
				hibit = 0;
			}
		}
		j = sh->sh_addralign;
		if ((fsz = hi % j) != 0)
			hi += j - fsz;

		/* LINTED */
		sh->sh_offset = (Off)hi;
		hi += sz;
	}

	/*
	 * if last section was a 'NOBITS' section then we need to
	 * restore the 'hi' counter to point to the end of the last
	 * non 'NOBITS' section.
	 */
	if (hibit) {
		hi = hibit;
		hibit = 0;
	}

	/*
	 * Shdr table last
	 */
	if (scncnt != 0) {
		if (hi % FSZ_LONG != 0)
			hi += FSZ_LONG - hi % FSZ_LONG;
		/* LINTED */
		eh->e_shoff = (Off)hi;
		/*
		 * If we are using 'extended sections' then the
		 * e_shnum is stored in the sh_size field of the
		 * first section header.
		 *
		 * NOTE: we set e_shnum to '0' because it's specified
		 * this way in the gABI, and in the hopes that
		 * this will cause less problems to unaware
		 * tools then if we'd set it to SHN_XINDEX (0xffff).
		 */
		if (scncnt < SHN_LORESERVE)
			eh->e_shnum = scncnt;
		else {
			Shdr	*sh;
			sh = (Shdr *)elf->ed_hdscn->s_shdr;
			sh->sh_size = scncnt;
			eh->e_shnum = 0;
		}
		/* LINTED */
		eh->e_shentsize = (Half)elf_fsize(ELF_T_SHDR, 1, ver);
		hi += eh->e_shentsize * scncnt;
	} else {
		eh->e_shoff = 0;
		eh->e_shentsize = 0;
	}

#if	!(defined(_LP64) && defined(_ELF64))
	if (hi > INT_MAX) {
		_elf_seterr(EFMT_FBIG, 0);
		return (0);
	}
#endif

	return ((size_t)hi);
}