xref: /netbsd/libexec/ld.elf_so/symver.c (revision fca326a7)
1*fca326a7Schristos /*	$NetBSD: symver.c,v 1.4 2013/05/09 15:38:14 christos Exp $	*/
207fac769Snonaka 
307fac769Snonaka /*-
407fac769Snonaka  * Copyright 1996, 1997, 1998, 1999, 2000 John D. Polstra.
507fac769Snonaka  * Copyright 2003 Alexander Kabaev <kan@FreeBSD.ORG>.
607fac769Snonaka  * Copyright 2009, 2010, 2011 Konstantin Belousov <kib@FreeBSD.ORG>.
707fac769Snonaka  * All rights reserved.
807fac769Snonaka  *
907fac769Snonaka  * Redistribution and use in source and binary forms, with or without
1007fac769Snonaka  * modification, are permitted provided that the following conditions
1107fac769Snonaka  * are met:
1207fac769Snonaka  * 1. Redistributions of source code must retain the above copyright
1307fac769Snonaka  *    notice, this list of conditions and the following disclaimer.
1407fac769Snonaka  * 2. Redistributions in binary form must reproduce the above copyright
1507fac769Snonaka  *    notice, this list of conditions and the following disclaimer in the
1607fac769Snonaka  *    documentation and/or other materials provided with the distribution.
1707fac769Snonaka  *
1807fac769Snonaka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1907fac769Snonaka  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2007fac769Snonaka  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2107fac769Snonaka  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2207fac769Snonaka  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2307fac769Snonaka  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2407fac769Snonaka  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2507fac769Snonaka  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2607fac769Snonaka  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2707fac769Snonaka  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2807fac769Snonaka  *
2907fac769Snonaka  * $FreeBSD: head/libexec/rtld-elf/rtld.c 220004 2011-03-25 18:23:10Z avg $
3007fac769Snonaka  */
3107fac769Snonaka 
3207fac769Snonaka /*-
3307fac769Snonaka  * Copyright (c) 2011 The NetBSD Foundation, Inc.
3407fac769Snonaka  * All rights reserved.
3507fac769Snonaka  *
3607fac769Snonaka  * This code is derived from software contributed to The NetBSD Foundation
3707fac769Snonaka  * by NONAKA Kimihiro.
3807fac769Snonaka  *
3907fac769Snonaka  * Redistribution and use in source and binary forms, with or without
4007fac769Snonaka  * modification, are permitted provided that the following conditions
4107fac769Snonaka  * are met:
4207fac769Snonaka  * 1. Redistributions of source code must retain the above copyright
4307fac769Snonaka  *    notice, this list of conditions and the following disclaimer.
4407fac769Snonaka  * 2. Redistributions in binary form must reproduce the above copyright
4507fac769Snonaka  *    notice, this list of conditions and the following disclaimer in the
4607fac769Snonaka  *    documentation and/or other materials provided with the distribution.
4707fac769Snonaka  *
4807fac769Snonaka  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
4907fac769Snonaka  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
5007fac769Snonaka  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
5107fac769Snonaka  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
5207fac769Snonaka  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5307fac769Snonaka  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5407fac769Snonaka  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
5507fac769Snonaka  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
5607fac769Snonaka  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
5707fac769Snonaka  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
5807fac769Snonaka  * POSSIBILITY OF SUCH DAMAGE.
5907fac769Snonaka  */
6007fac769Snonaka 
6107fac769Snonaka #include <sys/cdefs.h>
62*fca326a7Schristos __RCSID("$NetBSD: symver.c,v 1.4 2013/05/09 15:38:14 christos Exp $");
6307fac769Snonaka 
6407fac769Snonaka #include <sys/param.h>
6507fac769Snonaka #include <sys/exec_elf.h>
6607fac769Snonaka #include <string.h>
6707fac769Snonaka 
6807fac769Snonaka #include "debug.h"
6907fac769Snonaka #include "rtld.h"
7007fac769Snonaka 
7157fae3deSchristos void
_rtld_object_add_name(Obj_Entry * obj,const char * name)7257fae3deSchristos _rtld_object_add_name(Obj_Entry *obj, const char *name)
7357fae3deSchristos {
7457fae3deSchristos     Name_Entry *entry;
7557fae3deSchristos     size_t len;
7657fae3deSchristos 
7757fae3deSchristos     len = strlen(name);
7857fae3deSchristos     entry = xmalloc(sizeof(Name_Entry) + len);
7957fae3deSchristos 
8057fae3deSchristos     if (entry != NULL) {
8157fae3deSchristos 	strcpy(entry->name, name);
82*fca326a7Schristos 	SIMPLEQ_INSERT_TAIL(&obj->names, entry, link);
8357fae3deSchristos     }
8457fae3deSchristos }
8507fac769Snonaka 
8607fac769Snonaka int
_rtld_object_match_name(const Obj_Entry * obj,const char * name)8707fac769Snonaka _rtld_object_match_name(const Obj_Entry *obj, const char *name)
8807fac769Snonaka {
8907fac769Snonaka 	Name_Entry *entry;
9007fac769Snonaka 
91*fca326a7Schristos 	SIMPLEQ_FOREACH(entry, &obj->names, link) {
9207fac769Snonaka 		dbg(("name: %s, entry->name: %s", name, entry->name));
9307fac769Snonaka 		if (strcmp(name, entry->name) == 0)
9407fac769Snonaka 			return 1;
9507fac769Snonaka 	}
9607fac769Snonaka 	return 0;
9707fac769Snonaka }
9807fac769Snonaka 
99018f912cSchristos #ifdef RTLD_LOADER
10007fac769Snonaka static Obj_Entry *
locate_dependency(const Obj_Entry * obj,const char * name)10107fac769Snonaka locate_dependency(const Obj_Entry *obj, const char *name)
10207fac769Snonaka {
10307fac769Snonaka 	const Objlist_Entry *entry;
10407fac769Snonaka 	const Needed_Entry *needed;
10507fac769Snonaka 
10607fac769Snonaka 	SIMPLEQ_FOREACH(entry, &_rtld_list_main, link) {
10707fac769Snonaka 		if (_rtld_object_match_name(entry->obj, name))
10807fac769Snonaka 			return entry->obj;
10907fac769Snonaka 	}
11007fac769Snonaka 
11107fac769Snonaka 	for (needed = obj->needed; needed != NULL; needed = needed->next) {
11207fac769Snonaka 		dbg(("needed: name: %s, str: %s", name,
11307fac769Snonaka 		    &obj->strtab[needed->name]));
11407fac769Snonaka 		if (strcmp(name, &obj->strtab[needed->name]) == 0 ||
11507fac769Snonaka 		    (needed->obj != NULL && _rtld_object_match_name(needed->obj, name))) {
11607fac769Snonaka 			/*
11707fac769Snonaka 			 * If there is DT_NEEDED for the name we are looking
11807fac769Snonaka 			 * for, we are all set.  Note that object might not be
11907fac769Snonaka 			 * found if dependency was not loaded yet, so the
12007fac769Snonaka 			 * function can return NULL here.  This is expected
12107fac769Snonaka 			 * and handled properly by the caller.
12207fac769Snonaka 			 */
12307fac769Snonaka 			return needed->obj;
12407fac769Snonaka 		}
12507fac769Snonaka 	}
12607fac769Snonaka 
12707fac769Snonaka 	_rtld_error("%s: Unexpected inconsistency: dependency %s not found",
12807fac769Snonaka 	    obj->path, name);
12907fac769Snonaka 	return NULL;
13007fac769Snonaka }
13107fac769Snonaka 
13207fac769Snonaka static int
check_object_provided_version(Obj_Entry * refobj,const Obj_Entry * depobj,const Elf_Vernaux * vna)13307fac769Snonaka check_object_provided_version(Obj_Entry *refobj, const Obj_Entry *depobj,
13407fac769Snonaka     const Elf_Vernaux *vna)
13507fac769Snonaka {
13607fac769Snonaka 	const char *vername = &refobj->strtab[vna->vna_name];
13707fac769Snonaka 	const char *depstrtab = depobj->strtab;
13807fac769Snonaka 	const Elf_Verdef *vd = depobj->verdef;
13907fac769Snonaka 	const Elf_Word hash = vna->vna_hash;
14007fac769Snonaka 
14107fac769Snonaka 	if (vd == NULL) {
14207fac769Snonaka 		_rtld_error("%s: version %s required by %s not defined",
14307fac769Snonaka 		    depobj->path, vername, refobj->path);
14407fac769Snonaka 		return -1;
14507fac769Snonaka 	}
14607fac769Snonaka 
14707fac769Snonaka 	for (;; vd = (const Elf_Verdef *)((const char *)vd + vd->vd_next)) {
14807fac769Snonaka 		if (vd->vd_version != VER_DEF_CURRENT) {
14907fac769Snonaka 			_rtld_error(
15007fac769Snonaka 			    "%s: Unsupported version %d of Elf_Verdef entry",
15107fac769Snonaka 			    depobj->path, vd->vd_version);
15207fac769Snonaka 			return -1;
15307fac769Snonaka 		}
15407fac769Snonaka 		dbg(("hash: 0x%x, vd_hash: 0x%x", hash, vd->vd_hash));
15507fac769Snonaka 		if (hash == vd->vd_hash) {
15607fac769Snonaka 			const Elf_Verdaux *vda = (const Elf_Verdaux *)
15707fac769Snonaka 			    ((const char *)vd + vd->vd_aux);
15807fac769Snonaka 			dbg(("vername: %s, str: %s", vername,
15907fac769Snonaka 			    &depstrtab[vda->vda_name]));
16007fac769Snonaka 			if (strcmp(vername, &depstrtab[vda->vda_name]) == 0)
16107fac769Snonaka 				return 0;
16207fac769Snonaka 		}
16307fac769Snonaka 		if (vd->vd_next == 0)
16407fac769Snonaka 			break;
16507fac769Snonaka 	}
16607fac769Snonaka 	if (vna->vna_flags & VER_FLG_WEAK)
16707fac769Snonaka 		return 0;
16807fac769Snonaka 
16907fac769Snonaka 	_rtld_error("%s: version %s required by %s not found", depobj->path,
17007fac769Snonaka 	    vername, refobj->path);
17107fac769Snonaka 	return -1;
17207fac769Snonaka }
17307fac769Snonaka 
17407fac769Snonaka int
_rtld_verify_object_versions(Obj_Entry * obj)17507fac769Snonaka _rtld_verify_object_versions(Obj_Entry *obj)
17607fac769Snonaka {
17707fac769Snonaka 	const char *strtab = obj->strtab;
17807fac769Snonaka 	const Elf_Verneed *vn;
17907fac769Snonaka 	const Elf_Vernaux *vna;
18007fac769Snonaka 	const Elf_Verdef *vd;
18107fac769Snonaka 	const Elf_Verdaux *vda;
18207fac769Snonaka 	const Obj_Entry *depobj;
18307fac769Snonaka 	int maxvertab, vernum;
18407fac769Snonaka 
18507fac769Snonaka 	dbg(("obj->path: %s", obj->path));
18607fac769Snonaka 
18707fac769Snonaka 	/*
18807fac769Snonaka 	 * If we don't have string table or objects that have their version
18907fac769Snonaka 	 * requirements already checked, we must be ok.
19007fac769Snonaka 	 */
19107fac769Snonaka 	if (strtab == NULL || obj->vertab != NULL)
19207fac769Snonaka 		return 0;
19307fac769Snonaka 
19407fac769Snonaka 	maxvertab = 0;
19507fac769Snonaka 
19607fac769Snonaka 	/*
19707fac769Snonaka 	 * Walk over defined and required version records and figure out
19807fac769Snonaka 	 * max index used by any of them. Do very basic sanity checking
19907fac769Snonaka 	 * while there.
20007fac769Snonaka 	 */
20107fac769Snonaka 	for (vn = obj->verneed;
20207fac769Snonaka 	     vn != NULL;
20307fac769Snonaka 	     vn = (const Elf_Verneed *)((const char *)vn + vn->vn_next)) {
20407fac769Snonaka 
20507fac769Snonaka 		if (vn->vn_version != VER_NEED_CURRENT) {
20607fac769Snonaka 			_rtld_error(
20707fac769Snonaka 			    "%s: Unsupported version %d of Elf_Verneed entry",
20807fac769Snonaka 			    obj->path, vn->vn_version);
20907fac769Snonaka 			return -1;
21007fac769Snonaka 		}
21107fac769Snonaka 
21207fac769Snonaka 		dbg(("verneed: vn_file: %d, str: %s",
21307fac769Snonaka 		    vn->vn_file, &strtab[vn->vn_file]));
21407fac769Snonaka 		depobj = locate_dependency(obj, &strtab[vn->vn_file]);
21507fac769Snonaka 		assert(depobj != NULL);
21607fac769Snonaka 
21707fac769Snonaka 		for (vna = (const Elf_Vernaux *)((const char *)vn + vn->vn_aux);
21807fac769Snonaka 		     /*CONSTCOND*/1;
21907fac769Snonaka 		     vna = (const Elf_Vernaux *)((const char *)vna + vna->vna_next)) {
22007fac769Snonaka 
22107fac769Snonaka 			if (check_object_provided_version(obj, depobj, vna) == -1)
22207fac769Snonaka 				return -1;
22307fac769Snonaka 
22407fac769Snonaka 			vernum = VER_NEED_IDX(vna->vna_other);
22507fac769Snonaka 			if (vernum > maxvertab)
22607fac769Snonaka 				maxvertab = vernum;
22707fac769Snonaka 
22807fac769Snonaka 			if (vna->vna_next == 0) {
22907fac769Snonaka 				/* No more symbols. */
23007fac769Snonaka 				break;
23107fac769Snonaka 			}
23207fac769Snonaka 		}
23307fac769Snonaka 
23407fac769Snonaka 		if (vn->vn_next == 0) {
23507fac769Snonaka 			/* No more dependencies. */
23607fac769Snonaka 			break;
23707fac769Snonaka 		}
23807fac769Snonaka 	}
23907fac769Snonaka 
24007fac769Snonaka 	for (vd = obj->verdef;
24107fac769Snonaka 	     vd != NULL;
24207fac769Snonaka 	     vd = (const Elf_Verdef *)((const char *)vd + vd->vd_next)) {
24307fac769Snonaka 
24407fac769Snonaka 		if (vd->vd_version != VER_DEF_CURRENT) {
24507fac769Snonaka 			_rtld_error(
24607fac769Snonaka 			    "%s: Unsupported version %d of Elf_Verdef entry",
24707fac769Snonaka 			    obj->path, vd->vd_version);
24807fac769Snonaka 			return -1;
24907fac769Snonaka 		}
25007fac769Snonaka 
25107fac769Snonaka 		dbg(("verdef: vn_ndx: 0x%x", vd->vd_ndx));
25207fac769Snonaka 		vernum = VER_DEF_IDX(vd->vd_ndx);
25307fac769Snonaka 		if (vernum > maxvertab)
25407fac769Snonaka 			maxvertab = vernum;
25507fac769Snonaka 
25607fac769Snonaka 		if (vd->vd_next == 0) {
25707fac769Snonaka 			/* No more definitions. */
25807fac769Snonaka 			break;
25907fac769Snonaka 		}
26007fac769Snonaka 	}
26107fac769Snonaka 
26207fac769Snonaka 	dbg(("maxvertab: %d", maxvertab));
26307fac769Snonaka 	if (maxvertab == 0)
26407fac769Snonaka 		return 0;
26507fac769Snonaka 
26607fac769Snonaka 	/*
26707fac769Snonaka 	 * Store version information in array indexable by version index.
26807fac769Snonaka 	 * Verify that object version requirements are satisfied along the
26907fac769Snonaka 	 * way.
27007fac769Snonaka 	 */
27107fac769Snonaka 	obj->vertabnum = maxvertab + 1;
27207fac769Snonaka 	obj->vertab = (Ver_Entry *)xcalloc(obj->vertabnum * sizeof(Ver_Entry));
27307fac769Snonaka 
27407fac769Snonaka 	for (vn = obj->verneed;
27507fac769Snonaka 	     vn != NULL;
27607fac769Snonaka 	     vn = (const Elf_Verneed *)((const char *)vn + vn->vn_next)) {
27707fac769Snonaka 
27807fac769Snonaka 		for (vna = (const Elf_Vernaux *)((const char *)vn + vn->vn_aux);
27907fac769Snonaka 		     /*CONSTCOND*/1;
28007fac769Snonaka 		     vna = (const Elf_Vernaux *)((const char *)vna + vna->vna_next)) {
28107fac769Snonaka 
28207fac769Snonaka 			vernum = VER_NEED_IDX(vna->vna_other);
28307fac769Snonaka 			assert(vernum <= maxvertab);
28407fac769Snonaka 			obj->vertab[vernum].hash = vna->vna_hash;
28507fac769Snonaka 			obj->vertab[vernum].name = &strtab[vna->vna_name];
28607fac769Snonaka 			obj->vertab[vernum].file = &strtab[vn->vn_file];
28707fac769Snonaka 			obj->vertab[vernum].flags =
28807fac769Snonaka 			    (vna->vna_other & VER_NEED_HIDDEN)
28907fac769Snonaka 			      ? VER_INFO_HIDDEN : 0;
29007fac769Snonaka 			dbg(("verneed: vernum: %d, hash: 0x%x, name: %s, "
29107fac769Snonaka 			    "file: %s, flags: 0x%x", vernum,
29207fac769Snonaka 			    obj->vertab[vernum].hash, obj->vertab[vernum].name,
29307fac769Snonaka 			    obj->vertab[vernum].file,
29407fac769Snonaka 			    obj->vertab[vernum].flags));
29507fac769Snonaka 
29607fac769Snonaka 			if (vna->vna_next == 0) {
29707fac769Snonaka 				/* No more symbols. */
29807fac769Snonaka 				break;
29907fac769Snonaka 			}
30007fac769Snonaka 		}
30107fac769Snonaka 		if (vn->vn_next == 0) {
30207fac769Snonaka 			/* No more dependencies. */
30307fac769Snonaka 			break;
30407fac769Snonaka 		}
30507fac769Snonaka 	}
30607fac769Snonaka 
30707fac769Snonaka 	for (vd = obj->verdef;
30807fac769Snonaka 	     vd != NULL;
30907fac769Snonaka 	     vd = (const Elf_Verdef *)((const char *)vd + vd->vd_next)) {
31007fac769Snonaka 
31107fac769Snonaka 		if ((vd->vd_flags & VER_FLG_BASE) == 0) {
31207fac769Snonaka 			vernum = VER_DEF_IDX(vd->vd_ndx);
31307fac769Snonaka 			assert(vernum <= maxvertab);
31407fac769Snonaka 			vda = (const Elf_Verdaux *)
31507fac769Snonaka 			    ((const char *)vd + vd->vd_aux);
31607fac769Snonaka 			obj->vertab[vernum].hash = vd->vd_hash;
31707fac769Snonaka 			obj->vertab[vernum].name = &strtab[vda->vda_name];
31807fac769Snonaka 			obj->vertab[vernum].file = NULL;
31907fac769Snonaka 			obj->vertab[vernum].flags = 0;
32007fac769Snonaka 			dbg(("verdef: vernum: %d, hash: 0x%x, name: %s",
32107fac769Snonaka 			    vernum, obj->vertab[vernum].hash,
32207fac769Snonaka 			    obj->vertab[vernum].name));
32307fac769Snonaka 		}
32407fac769Snonaka 
32507fac769Snonaka 		if (vd->vd_next == 0) {
32607fac769Snonaka 			/* No more definitions. */
32707fac769Snonaka 			break;
32807fac769Snonaka 		}
32907fac769Snonaka 	}
33007fac769Snonaka 
33107fac769Snonaka 	return 0;
33207fac769Snonaka }
333018f912cSchristos #endif
334