Home | History | Annotate | Line # | Download | only in ld.elf_so
      1 /*	$NetBSD: symver.c,v 1.4 2013/05/09 15:38:14 christos Exp $	*/
      2 
      3 /*-
      4  * Copyright 1996, 1997, 1998, 1999, 2000 John D. Polstra.
      5  * Copyright 2003 Alexander Kabaev <kan (at) FreeBSD.ORG>.
      6  * Copyright 2009, 2010, 2011 Konstantin Belousov <kib (at) FreeBSD.ORG>.
      7  * All rights reserved.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28  *
     29  * $FreeBSD: head/libexec/rtld-elf/rtld.c 220004 2011-03-25 18:23:10Z avg $
     30  */
     31 
     32 /*-
     33  * Copyright (c) 2011 The NetBSD Foundation, Inc.
     34  * All rights reserved.
     35  *
     36  * This code is derived from software contributed to The NetBSD Foundation
     37  * by NONAKA Kimihiro.
     38  *
     39  * Redistribution and use in source and binary forms, with or without
     40  * modification, are permitted provided that the following conditions
     41  * are met:
     42  * 1. Redistributions of source code must retain the above copyright
     43  *    notice, this list of conditions and the following disclaimer.
     44  * 2. Redistributions in binary form must reproduce the above copyright
     45  *    notice, this list of conditions and the following disclaimer in the
     46  *    documentation and/or other materials provided with the distribution.
     47  *
     48  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     49  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     50  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     51  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     52  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     53  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     54  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     55  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     56  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     57  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     58  * POSSIBILITY OF SUCH DAMAGE.
     59  */
     60 
     61 #include <sys/cdefs.h>
     62 __RCSID("$NetBSD: symver.c,v 1.4 2013/05/09 15:38:14 christos Exp $");
     63 
     64 #include <sys/param.h>
     65 #include <sys/exec_elf.h>
     66 #include <string.h>
     67 
     68 #include "debug.h"
     69 #include "rtld.h"
     70 
     71 void
     72 _rtld_object_add_name(Obj_Entry *obj, const char *name)
     73 {
     74     Name_Entry *entry;
     75     size_t len;
     76 
     77     len = strlen(name);
     78     entry = xmalloc(sizeof(Name_Entry) + len);
     79 
     80     if (entry != NULL) {
     81 	strcpy(entry->name, name);
     82 	SIMPLEQ_INSERT_TAIL(&obj->names, entry, link);
     83     }
     84 }
     85 
     86 int
     87 _rtld_object_match_name(const Obj_Entry *obj, const char *name)
     88 {
     89 	Name_Entry *entry;
     90 
     91 	SIMPLEQ_FOREACH(entry, &obj->names, link) {
     92 		dbg(("name: %s, entry->name: %s", name, entry->name));
     93 		if (strcmp(name, entry->name) == 0)
     94 			return 1;
     95 	}
     96 	return 0;
     97 }
     98 
     99 #ifdef RTLD_LOADER
    100 static Obj_Entry *
    101 locate_dependency(const Obj_Entry *obj, const char *name)
    102 {
    103 	const Objlist_Entry *entry;
    104 	const Needed_Entry *needed;
    105 
    106 	SIMPLEQ_FOREACH(entry, &_rtld_list_main, link) {
    107 		if (_rtld_object_match_name(entry->obj, name))
    108 			return entry->obj;
    109 	}
    110 
    111 	for (needed = obj->needed; needed != NULL; needed = needed->next) {
    112 		dbg(("needed: name: %s, str: %s", name,
    113 		    &obj->strtab[needed->name]));
    114 		if (strcmp(name, &obj->strtab[needed->name]) == 0 ||
    115 		    (needed->obj != NULL && _rtld_object_match_name(needed->obj, name))) {
    116 			/*
    117 			 * If there is DT_NEEDED for the name we are looking
    118 			 * for, we are all set.  Note that object might not be
    119 			 * found if dependency was not loaded yet, so the
    120 			 * function can return NULL here.  This is expected
    121 			 * and handled properly by the caller.
    122 			 */
    123 			return needed->obj;
    124 		}
    125 	}
    126 
    127 	_rtld_error("%s: Unexpected inconsistency: dependency %s not found",
    128 	    obj->path, name);
    129 	return NULL;
    130 }
    131 
    132 static int
    133 check_object_provided_version(Obj_Entry *refobj, const Obj_Entry *depobj,
    134     const Elf_Vernaux *vna)
    135 {
    136 	const char *vername = &refobj->strtab[vna->vna_name];
    137 	const char *depstrtab = depobj->strtab;
    138 	const Elf_Verdef *vd = depobj->verdef;
    139 	const Elf_Word hash = vna->vna_hash;
    140 
    141 	if (vd == NULL) {
    142 		_rtld_error("%s: version %s required by %s not defined",
    143 		    depobj->path, vername, refobj->path);
    144 		return -1;
    145 	}
    146 
    147 	for (;; vd = (const Elf_Verdef *)((const char *)vd + vd->vd_next)) {
    148 		if (vd->vd_version != VER_DEF_CURRENT) {
    149 			_rtld_error(
    150 			    "%s: Unsupported version %d of Elf_Verdef entry",
    151 			    depobj->path, vd->vd_version);
    152 			return -1;
    153 		}
    154 		dbg(("hash: 0x%x, vd_hash: 0x%x", hash, vd->vd_hash));
    155 		if (hash == vd->vd_hash) {
    156 			const Elf_Verdaux *vda = (const Elf_Verdaux *)
    157 			    ((const char *)vd + vd->vd_aux);
    158 			dbg(("vername: %s, str: %s", vername,
    159 			    &depstrtab[vda->vda_name]));
    160 			if (strcmp(vername, &depstrtab[vda->vda_name]) == 0)
    161 				return 0;
    162 		}
    163 		if (vd->vd_next == 0)
    164 			break;
    165 	}
    166 	if (vna->vna_flags & VER_FLG_WEAK)
    167 		return 0;
    168 
    169 	_rtld_error("%s: version %s required by %s not found", depobj->path,
    170 	    vername, refobj->path);
    171 	return -1;
    172 }
    173 
    174 int
    175 _rtld_verify_object_versions(Obj_Entry *obj)
    176 {
    177 	const char *strtab = obj->strtab;
    178 	const Elf_Verneed *vn;
    179 	const Elf_Vernaux *vna;
    180 	const Elf_Verdef *vd;
    181 	const Elf_Verdaux *vda;
    182 	const Obj_Entry *depobj;
    183 	int maxvertab, vernum;
    184 
    185 	dbg(("obj->path: %s", obj->path));
    186 
    187 	/*
    188 	 * If we don't have string table or objects that have their version
    189 	 * requirements already checked, we must be ok.
    190 	 */
    191 	if (strtab == NULL || obj->vertab != NULL)
    192 		return 0;
    193 
    194 	maxvertab = 0;
    195 
    196 	/*
    197 	 * Walk over defined and required version records and figure out
    198 	 * max index used by any of them. Do very basic sanity checking
    199 	 * while there.
    200 	 */
    201 	for (vn = obj->verneed;
    202 	     vn != NULL;
    203 	     vn = (const Elf_Verneed *)((const char *)vn + vn->vn_next)) {
    204 
    205 		if (vn->vn_version != VER_NEED_CURRENT) {
    206 			_rtld_error(
    207 			    "%s: Unsupported version %d of Elf_Verneed entry",
    208 			    obj->path, vn->vn_version);
    209 			return -1;
    210 		}
    211 
    212 		dbg(("verneed: vn_file: %d, str: %s",
    213 		    vn->vn_file, &strtab[vn->vn_file]));
    214 		depobj = locate_dependency(obj, &strtab[vn->vn_file]);
    215 		assert(depobj != NULL);
    216 
    217 		for (vna = (const Elf_Vernaux *)((const char *)vn + vn->vn_aux);
    218 		     /*CONSTCOND*/1;
    219 		     vna = (const Elf_Vernaux *)((const char *)vna + vna->vna_next)) {
    220 
    221 			if (check_object_provided_version(obj, depobj, vna) == -1)
    222 				return -1;
    223 
    224 			vernum = VER_NEED_IDX(vna->vna_other);
    225 			if (vernum > maxvertab)
    226 				maxvertab = vernum;
    227 
    228 			if (vna->vna_next == 0) {
    229 				/* No more symbols. */
    230 				break;
    231 			}
    232 		}
    233 
    234 		if (vn->vn_next == 0) {
    235 			/* No more dependencies. */
    236 			break;
    237 		}
    238 	}
    239 
    240 	for (vd = obj->verdef;
    241 	     vd != NULL;
    242 	     vd = (const Elf_Verdef *)((const char *)vd + vd->vd_next)) {
    243 
    244 		if (vd->vd_version != VER_DEF_CURRENT) {
    245 			_rtld_error(
    246 			    "%s: Unsupported version %d of Elf_Verdef entry",
    247 			    obj->path, vd->vd_version);
    248 			return -1;
    249 		}
    250 
    251 		dbg(("verdef: vn_ndx: 0x%x", vd->vd_ndx));
    252 		vernum = VER_DEF_IDX(vd->vd_ndx);
    253 		if (vernum > maxvertab)
    254 			maxvertab = vernum;
    255 
    256 		if (vd->vd_next == 0) {
    257 			/* No more definitions. */
    258 			break;
    259 		}
    260 	}
    261 
    262 	dbg(("maxvertab: %d", maxvertab));
    263 	if (maxvertab == 0)
    264 		return 0;
    265 
    266 	/*
    267 	 * Store version information in array indexable by version index.
    268 	 * Verify that object version requirements are satisfied along the
    269 	 * way.
    270 	 */
    271 	obj->vertabnum = maxvertab + 1;
    272 	obj->vertab = (Ver_Entry *)xcalloc(obj->vertabnum * sizeof(Ver_Entry));
    273 
    274 	for (vn = obj->verneed;
    275 	     vn != NULL;
    276 	     vn = (const Elf_Verneed *)((const char *)vn + vn->vn_next)) {
    277 
    278 		for (vna = (const Elf_Vernaux *)((const char *)vn + vn->vn_aux);
    279 		     /*CONSTCOND*/1;
    280 		     vna = (const Elf_Vernaux *)((const char *)vna + vna->vna_next)) {
    281 
    282 			vernum = VER_NEED_IDX(vna->vna_other);
    283 			assert(vernum <= maxvertab);
    284 			obj->vertab[vernum].hash = vna->vna_hash;
    285 			obj->vertab[vernum].name = &strtab[vna->vna_name];
    286 			obj->vertab[vernum].file = &strtab[vn->vn_file];
    287 			obj->vertab[vernum].flags =
    288 			    (vna->vna_other & VER_NEED_HIDDEN)
    289 			      ? VER_INFO_HIDDEN : 0;
    290 			dbg(("verneed: vernum: %d, hash: 0x%x, name: %s, "
    291 			    "file: %s, flags: 0x%x", vernum,
    292 			    obj->vertab[vernum].hash, obj->vertab[vernum].name,
    293 			    obj->vertab[vernum].file,
    294 			    obj->vertab[vernum].flags));
    295 
    296 			if (vna->vna_next == 0) {
    297 				/* No more symbols. */
    298 				break;
    299 			}
    300 		}
    301 		if (vn->vn_next == 0) {
    302 			/* No more dependencies. */
    303 			break;
    304 		}
    305 	}
    306 
    307 	for (vd = obj->verdef;
    308 	     vd != NULL;
    309 	     vd = (const Elf_Verdef *)((const char *)vd + vd->vd_next)) {
    310 
    311 		if ((vd->vd_flags & VER_FLG_BASE) == 0) {
    312 			vernum = VER_DEF_IDX(vd->vd_ndx);
    313 			assert(vernum <= maxvertab);
    314 			vda = (const Elf_Verdaux *)
    315 			    ((const char *)vd + vd->vd_aux);
    316 			obj->vertab[vernum].hash = vd->vd_hash;
    317 			obj->vertab[vernum].name = &strtab[vda->vda_name];
    318 			obj->vertab[vernum].file = NULL;
    319 			obj->vertab[vernum].flags = 0;
    320 			dbg(("verdef: vernum: %d, hash: 0x%x, name: %s",
    321 			    vernum, obj->vertab[vernum].hash,
    322 			    obj->vertab[vernum].name));
    323 		}
    324 
    325 		if (vd->vd_next == 0) {
    326 			/* No more definitions. */
    327 			break;
    328 		}
    329 	}
    330 
    331 	return 0;
    332 }
    333 #endif
    334