Beispiel #1
0
int _dl_unmap_cache(void)
{
	if (_dl_cache_addr == NULL || _dl_cache_addr == MAP_FAILED)
		return -1;

#if 1
	_dl_munmap(_dl_cache_addr, _dl_cache_size);
	_dl_cache_addr = NULL;
#endif

	return 0;
}
Beispiel #2
0
int _dl_unmap_cache(void)
{
	if (_dl_cache_addr == NULL || _dl_cache_addr == (caddr_t) - 1)
		return -1;

#if 1
	_dl_munmap(_dl_cache_addr, _dl_cache_size);
	_dl_cache_addr = NULL;
#endif

	return 0;
}
Beispiel #3
0
void
_dl_load_list_free(struct load_list *load_list)
{
	struct load_list *next;
	Elf_Addr align = _dl_pagesz - 1;

	while (load_list != NULL) {
		if (load_list->start != NULL)
			_dl_munmap(load_list->start,
			    ((load_list->size) + align) & ~align);
		next = load_list->next;
		_dl_free(load_list);
		load_list = next;
	}
}
Beispiel #4
0
void
_dl_unload_shlib(elf_object_t *object)
{
	struct dep_node *n;
	DL_DEB(("unload_shlib called on %s\n", object->load_name));
	if (OBJECT_REF_CNT(object) == 0 &&
	    (object->status & STAT_UNLOADED) == 0) {
		object->status |= STAT_UNLOADED;
		TAILQ_FOREACH(n, &object->child_list, next_sib)
			_dl_unload_shlib(n->data);
		TAILQ_FOREACH(n, &object->grpref_list, next_sib)
			_dl_unload_shlib(n->data);
		DL_DEB(("unload_shlib unloading on %s\n", object->load_name));
		_dl_load_list_free(object->load_list);
		_dl_munmap((void *)object->load_base, object->load_size);
		_dl_remove_object(object);
	}
}
Beispiel #5
0
int _dl_map_cache(void)
{
	int fd;
	struct stat st;
	header_t *header;
	libentry_t *libent;
	int i, strtabsize;

	if (_dl_cache_addr == MAP_FAILED)
		return -1;
	else if (_dl_cache_addr != NULL)
		return 0;

	if (_dl_stat(LDSO_CACHE, &st)
	    || (fd = _dl_open(LDSO_CACHE, O_RDONLY|O_CLOEXEC, 0)) < 0) {
		_dl_cache_addr = MAP_FAILED;	/* so we won't try again */
		return -1;
	}

	_dl_cache_size = st.st_size;
	_dl_cache_addr = _dl_mmap(0, _dl_cache_size, PROT_READ, LDSO_CACHE_MMAP_FLAGS, fd, 0);
	_dl_close(fd);
	if (_dl_mmap_check_error(_dl_cache_addr)) {
		_dl_dprintf(2, "%s:%i: can't map '%s'\n",
				_dl_progname, __LINE__, LDSO_CACHE);
		return -1;
	}

	header = (header_t *) _dl_cache_addr;

	if (_dl_cache_size < sizeof(header_t) ||
			_dl_memcmp(header->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN)
			|| _dl_memcmp(header->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN)
			|| _dl_cache_size <
			(sizeof(header_t) + header->nlibs * sizeof(libentry_t))
			|| _dl_cache_addr[_dl_cache_size - 1] != '\0')
	{
		_dl_dprintf(2, "%s: cache '%s' is corrupt\n", _dl_progname,
				LDSO_CACHE);
		goto fail;
	}

	strtabsize = _dl_cache_size - sizeof(header_t) -
		header->nlibs * sizeof(libentry_t);
	libent = (libentry_t *) & header[1];

	for (i = 0; i < header->nlibs; i++) {
		if (libent[i].sooffset >= strtabsize ||
				libent[i].liboffset >= strtabsize)
		{
			_dl_dprintf(2, "%s: cache '%s' is corrupt\n", _dl_progname, LDSO_CACHE);
			goto fail;
		}
	}

	return 0;

fail:
	_dl_munmap(_dl_cache_addr, _dl_cache_size);
	_dl_cache_addr = MAP_FAILED;
	return -1;
}
Beispiel #6
0
elf_object_t *
_dl_tryload_shlib(const char *libname, int type, int flags)
{
	int	libfile, i;
	struct load_list *next_load, *load_list = NULL;
	Elf_Addr maxva = 0, minva = ELFDEFNNAME(NO_ADDR);
	Elf_Addr libaddr, loff, align = _dl_pagesz - 1;
	elf_object_t *object;
	char	hbuf[4096];
	Elf_Dyn *dynp = 0;
	Elf_Ehdr *ehdr;
	Elf_Phdr *phdp;
	struct stat sb;
	void *prebind_data;

#define ROUND_PG(x) (((x) + align) & ~(align))
#define TRUNC_PG(x) ((x) & ~(align))

	libfile = _dl_open(libname, O_RDONLY);
	if (libfile < 0) {
		_dl_errno = DL_CANT_OPEN;
		return(0);
	}

	if ( _dl_fstat(libfile, &sb) < 0) {
		_dl_errno = DL_CANT_OPEN;
		return(0);
	}

	for (object = _dl_objects; object != NULL; object = object->next) {
		if (object->dev == sb.st_dev &&
		    object->inode == sb.st_ino) {
			object->obj_flags |= flags & DF_1_GLOBAL;
			_dl_close(libfile);
			if (_dl_loading_object == NULL)
				_dl_loading_object = object;
			if (object->load_object != _dl_objects &&
			    object->load_object != _dl_loading_object) {
				_dl_link_grpref(object->load_object,
				    _dl_loading_object);
			}
			return(object);
		}
	}

	_dl_read(libfile, hbuf, sizeof(hbuf));
	ehdr = (Elf_Ehdr *)hbuf;
	if (ehdr->e_ident[0] != ELFMAG0  || ehdr->e_ident[1] != ELFMAG1 ||
	    ehdr->e_ident[2] != ELFMAG2 || ehdr->e_ident[3] != ELFMAG3 ||
	    ehdr->e_type != ET_DYN || ehdr->e_machine != MACHID) {
		_dl_close(libfile);
		_dl_errno = DL_NOT_ELF;
		return(0);
	}

	/*
	 *  Alright, we might have a winner!
	 *  Figure out how much VM space we need.
	 */
	phdp = (Elf_Phdr *)(hbuf + ehdr->e_phoff);
	for (i = 0; i < ehdr->e_phnum; i++, phdp++) {
		switch (phdp->p_type) {
		case PT_LOAD:
			if (phdp->p_vaddr < minva)
				minva = phdp->p_vaddr;
			if (phdp->p_vaddr + phdp->p_memsz > maxva)
				maxva = phdp->p_vaddr + phdp->p_memsz;
			break;
		case PT_DYNAMIC:
			dynp = (Elf_Dyn *)phdp->p_vaddr;
			break;
		case PT_TLS:
			_dl_printf("%s: unsupported TLS program header in %s\n",
			    _dl_progname, libname);
			_dl_close(libfile);
			_dl_errno = DL_CANT_LOAD_OBJ;
			return(0);
		default:
			break;
		}
	}
	minva = TRUNC_PG(minva);
	maxva = ROUND_PG(maxva);

	/*
	 * We map the entire area to see that we can get the VM
	 * space required. Map it unaccessible to start with.
	 *
	 * We must map the file we'll map later otherwise the VM
	 * system won't be able to align the mapping properly
	 * on VAC architectures.
	 */
	libaddr = (Elf_Addr)_dl_mmap(0, maxva - minva, PROT_NONE,
	    MAP_PRIVATE|MAP_FILE, libfile, 0);
	if (_dl_mmap_error(libaddr)) {
		_dl_printf("%s: rtld mmap failed mapping %s.\n",
		    _dl_progname, libname);
		_dl_close(libfile);
		_dl_errno = DL_CANT_MMAP;
		return(0);
	}

	loff = libaddr - minva;
	phdp = (Elf_Phdr *)(hbuf + ehdr->e_phoff);

	for (i = 0; i < ehdr->e_phnum; i++, phdp++) {
		switch (phdp->p_type) {
		case PT_LOAD: {
			char *start = (char *)(TRUNC_PG(phdp->p_vaddr)) + loff;
			Elf_Addr off = (phdp->p_vaddr & align);
			Elf_Addr size = off + phdp->p_filesz;
			void *res;

			if (size != 0) {
				res = _dl_mmap(start, ROUND_PG(size),
				    PFLAGS(phdp->p_flags),
				    MAP_FIXED|MAP_PRIVATE, libfile,
				    TRUNC_PG(phdp->p_offset));
			} else
				res = NULL;	/* silence gcc */
			next_load = _dl_malloc(sizeof(struct load_list));
			next_load->next = load_list;
			load_list = next_load;
			next_load->start = start;
			next_load->size = size;
			next_load->prot = PFLAGS(phdp->p_flags);
			if (size != 0 && _dl_mmap_error(res)) {
				_dl_printf("%s: rtld mmap failed mapping %s.\n",
				    _dl_progname, libname);
				_dl_close(libfile);
				_dl_errno = DL_CANT_MMAP;
				_dl_munmap((void *)libaddr, maxva - minva);
				_dl_load_list_free(load_list);
				return(0);
			}
			if (phdp->p_flags & PF_W) {
				/* Zero out everything past the EOF */
				if ((size & align) != 0)
					_dl_memset(start + size, 0,
					    _dl_pagesz - (size & align));
				if (ROUND_PG(size) ==
				    ROUND_PG(off + phdp->p_memsz))
					continue;
				start = start + ROUND_PG(size);
				size = ROUND_PG(off + phdp->p_memsz) -
				    ROUND_PG(size);
				res = _dl_mmap(start, size,
				    PFLAGS(phdp->p_flags),
				    MAP_FIXED|MAP_PRIVATE|MAP_ANON, -1, 0);
				if (_dl_mmap_error(res)) {
					_dl_printf("%s: rtld mmap failed mapping %s.\n",
					    _dl_progname, libname);
					_dl_close(libfile);
					_dl_errno = DL_CANT_MMAP;
					_dl_munmap((void *)libaddr, maxva - minva);
					_dl_load_list_free(load_list);
					return(0);
				}
			}
			break;
		}

		case PT_OPENBSD_RANDOMIZE:
			_dl_randombuf((char *)(phdp->p_vaddr + loff),
			    phdp->p_memsz);
			break;

		default:
			break;
		}
	}

	prebind_data = prebind_load_fd(libfile, libname);

	_dl_close(libfile);

	dynp = (Elf_Dyn *)((unsigned long)dynp + loff);
	object = _dl_finalize_object(libname, dynp,
	    (Elf_Phdr *)((char *)libaddr + ehdr->e_phoff), ehdr->e_phnum,type,
	    libaddr, loff);
	if (object) {
		object->prebind_data = prebind_data;
		object->load_size = maxva - minva;	/*XXX*/
		object->load_list = load_list;
		/* set inode, dev from stat info */
		object->dev = sb.st_dev;
		object->inode = sb.st_ino;
		object->obj_flags |= flags;
		_dl_set_sod(object->load_name, &object->sod);
	} else {
		_dl_munmap((void *)libaddr, maxva - minva);
		_dl_load_list_free(load_list);
	}
	return(object);
}
Beispiel #7
0
static int do_dlclose(void *vhandle, int need_fini)
{
	struct dyn_elf *rpnt, *rpnt1;
	struct dyn_elf *spnt, *spnt1;
	elf_phdr *ppnt;
	struct elf_resolve *tpnt;
	int (*dl_elf_fini) (void);
	void (*dl_brk) (void);
	struct dyn_elf *handle;
	unsigned int end;
	int i = 0;

	handle = (struct dyn_elf *) vhandle;
	rpnt1 = NULL;
	for (rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle) {
		if (rpnt == handle) {
			break;
		}
		rpnt1 = rpnt;
	}

	if (!rpnt) {
		_dl_error_number = LD_BAD_HANDLE;
		return 1;
	}

	/* OK, this is a valid handle - now close out the file.
	 * We check if we need to call fini () on the handle. */
	spnt = need_fini ? handle : handle->next;
	for (; spnt; spnt = spnt1) {
		spnt1 = spnt->next;

		/* We appended the module list to the end - when we get back here, 
		   quit. The access counts were not adjusted to account for being here. */
		if (spnt == _dl_symbol_tables)
			break;
		if (spnt->dyn->usage_count == 1
			&& spnt->dyn->libtype == loaded_file) {
			tpnt = spnt->dyn;
			/* Apparently crt1 for the application is responsible for handling this.
			 * We only need to run the init/fini for shared libraries
			 */

			if (tpnt->dynamic_info[DT_FINI]) {
				dl_elf_fini = (int (*)(void)) (tpnt->loadaddr + 
					tpnt->dynamic_info[DT_FINI]);
				(*dl_elf_fini) ();
			}
		}
	}
	if (rpnt1)
		rpnt1->next_handle = rpnt->next_handle;
	else
		_dl_handles = rpnt->next_handle;

	/* OK, this is a valid handle - now close out the file */
	for (rpnt = handle; rpnt; rpnt = rpnt1) {
		rpnt1 = rpnt->next;

		/* We appended the module list to the end - when we get back here, 
		   quit. The access counts were not adjusted to account for being here. */
		if (rpnt == _dl_symbol_tables)
			break;

		rpnt->dyn->usage_count--;
		if (rpnt->dyn->usage_count == 0
			&& rpnt->dyn->libtype == loaded_file) {
			tpnt = rpnt->dyn;
			/* Apparently crt1 for the application is responsible for handling this.
			 * We only need to run the init/fini for shared libraries
			 */
#if 0

			/* We have to do this above, before we start closing objects.  
			 * Otherwise when the needed symbols for _fini handling are 
			 * resolved a coredump would occur. Rob Ryan ([email protected])*/ 
			if (tpnt->dynamic_info[DT_FINI]) { 
			    dl_elf_fini = (int (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]);
				(*dl_elf_fini) ();
			}
#endif
			end = 0;
			for (i = 0, ppnt = rpnt->dyn->ppnt;
				 i < rpnt->dyn->n_phent; ppnt++, i++) {
				if (ppnt->p_type != PT_LOAD)
					continue;
				if (end < ppnt->p_vaddr + ppnt->p_memsz)
					end = ppnt->p_vaddr + ppnt->p_memsz;
			}
			_dl_munmap(rpnt->dyn->loadaddr, end);
			/* Next, remove rpnt->dyn from the loaded_module list */
			if (_dl_loaded_modules == rpnt->dyn) {
				_dl_loaded_modules = rpnt->dyn->next;
				if (_dl_loaded_modules)
					_dl_loaded_modules->prev = 0;
			} else
				for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next)
					if (tpnt->next == rpnt->dyn) {
						tpnt->next = tpnt->next->next;
						if (tpnt->next)
							tpnt->next->prev = tpnt;
						break;
					}
			free(rpnt->dyn->libname);
			free(rpnt->dyn);
		}
		free(rpnt);
	}


	if (_dl_debug_addr) {
	    dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
	    if (dl_brk != NULL) {
		_dl_debug_addr->r_state = RT_DELETE;
		(*dl_brk) ();

		_dl_debug_addr->r_state = RT_CONSISTENT;
		(*dl_brk) ();
	    }
	}

	return 0;
}