1/* $NetBSD: symver.c,v 1.3 2013/05/07 13:01:07 christos Exp $ */ 2 3/*- 4 * Copyright 1996, 1997, 1998, 1999, 2000 John D. Polstra. 5 * Copyright 2003 Alexander Kabaev <kan@FreeBSD.ORG>. 6 * Copyright 2009, 2010, 2011 Konstantin Belousov <kib@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.3 2013/05/07 13:01:07 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 71void 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 86int 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 100static Obj_Entry * 101locate_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 132static int 133check_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 174int 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