1 /* $NetBSD: symver.c,v 1.1 2011/06/25 05:45:12 nonaka 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.1 2011/06/25 05:45:12 nonaka 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 72 int 73 _rtld_object_match_name(const Obj_Entry *obj, const char *name) 74 { 75 Name_Entry *entry; 76 77 STAILQ_FOREACH(entry, &obj->names, link) { 78 dbg(("name: %s, entry->name: %s", name, entry->name)); 79 if (strcmp(name, entry->name) == 0) 80 return 1; 81 } 82 return 0; 83 } 84 85 static Obj_Entry * 86 locate_dependency(const Obj_Entry *obj, const char *name) 87 { 88 const Objlist_Entry *entry; 89 const Needed_Entry *needed; 90 91 SIMPLEQ_FOREACH(entry, &_rtld_list_main, link) { 92 if (_rtld_object_match_name(entry->obj, name)) 93 return entry->obj; 94 } 95 96 for (needed = obj->needed; needed != NULL; needed = needed->next) { 97 dbg(("needed: name: %s, str: %s", name, 98 &obj->strtab[needed->name])); 99 if (strcmp(name, &obj->strtab[needed->name]) == 0 || 100 (needed->obj != NULL && _rtld_object_match_name(needed->obj, name))) { 101 /* 102 * If there is DT_NEEDED for the name we are looking 103 * for, we are all set. Note that object might not be 104 * found if dependency was not loaded yet, so the 105 * function can return NULL here. This is expected 106 * and handled properly by the caller. 107 */ 108 return needed->obj; 109 } 110 } 111 112 _rtld_error("%s: Unexpected inconsistency: dependency %s not found", 113 obj->path, name); 114 return NULL; 115 } 116 117 static int 118 check_object_provided_version(Obj_Entry *refobj, const Obj_Entry *depobj, 119 const Elf_Vernaux *vna) 120 { 121 const char *vername = &refobj->strtab[vna->vna_name]; 122 const char *depstrtab = depobj->strtab; 123 const Elf_Verdef *vd = depobj->verdef; 124 const Elf_Word hash = vna->vna_hash; 125 126 if (vd == NULL) { 127 _rtld_error("%s: version %s required by %s not defined", 128 depobj->path, vername, refobj->path); 129 return -1; 130 } 131 132 for (;; vd = (const Elf_Verdef *)((const char *)vd + vd->vd_next)) { 133 if (vd->vd_version != VER_DEF_CURRENT) { 134 _rtld_error( 135 "%s: Unsupported version %d of Elf_Verdef entry", 136 depobj->path, vd->vd_version); 137 return -1; 138 } 139 dbg(("hash: 0x%x, vd_hash: 0x%x", hash, vd->vd_hash)); 140 if (hash == vd->vd_hash) { 141 const Elf_Verdaux *vda = (const Elf_Verdaux *) 142 ((const char *)vd + vd->vd_aux); 143 dbg(("vername: %s, str: %s", vername, 144 &depstrtab[vda->vda_name])); 145 if (strcmp(vername, &depstrtab[vda->vda_name]) == 0) 146 return 0; 147 } 148 if (vd->vd_next == 0) 149 break; 150 } 151 if (vna->vna_flags & VER_FLG_WEAK) 152 return 0; 153 154 _rtld_error("%s: version %s required by %s not found", depobj->path, 155 vername, refobj->path); 156 return -1; 157 } 158 159 int 160 _rtld_verify_object_versions(Obj_Entry *obj) 161 { 162 const char *strtab = obj->strtab; 163 const Elf_Verneed *vn; 164 const Elf_Vernaux *vna; 165 const Elf_Verdef *vd; 166 const Elf_Verdaux *vda; 167 const Obj_Entry *depobj; 168 int maxvertab, vernum; 169 170 dbg(("obj->path: %s", obj->path)); 171 172 /* 173 * If we don't have string table or objects that have their version 174 * requirements already checked, we must be ok. 175 */ 176 if (strtab == NULL || obj->vertab != NULL) 177 return 0; 178 179 maxvertab = 0; 180 181 /* 182 * Walk over defined and required version records and figure out 183 * max index used by any of them. Do very basic sanity checking 184 * while there. 185 */ 186 for (vn = obj->verneed; 187 vn != NULL; 188 vn = (const Elf_Verneed *)((const char *)vn + vn->vn_next)) { 189 190 if (vn->vn_version != VER_NEED_CURRENT) { 191 _rtld_error( 192 "%s: Unsupported version %d of Elf_Verneed entry", 193 obj->path, vn->vn_version); 194 return -1; 195 } 196 197 dbg(("verneed: vn_file: %d, str: %s", 198 vn->vn_file, &strtab[vn->vn_file])); 199 depobj = locate_dependency(obj, &strtab[vn->vn_file]); 200 assert(depobj != NULL); 201 202 for (vna = (const Elf_Vernaux *)((const char *)vn + vn->vn_aux); 203 /*CONSTCOND*/1; 204 vna = (const Elf_Vernaux *)((const char *)vna + vna->vna_next)) { 205 206 if (check_object_provided_version(obj, depobj, vna) == -1) 207 return -1; 208 209 vernum = VER_NEED_IDX(vna->vna_other); 210 if (vernum > maxvertab) 211 maxvertab = vernum; 212 213 if (vna->vna_next == 0) { 214 /* No more symbols. */ 215 break; 216 } 217 } 218 219 if (vn->vn_next == 0) { 220 /* No more dependencies. */ 221 break; 222 } 223 } 224 225 for (vd = obj->verdef; 226 vd != NULL; 227 vd = (const Elf_Verdef *)((const char *)vd + vd->vd_next)) { 228 229 if (vd->vd_version != VER_DEF_CURRENT) { 230 _rtld_error( 231 "%s: Unsupported version %d of Elf_Verdef entry", 232 obj->path, vd->vd_version); 233 return -1; 234 } 235 236 dbg(("verdef: vn_ndx: 0x%x", vd->vd_ndx)); 237 vernum = VER_DEF_IDX(vd->vd_ndx); 238 if (vernum > maxvertab) 239 maxvertab = vernum; 240 241 if (vd->vd_next == 0) { 242 /* No more definitions. */ 243 break; 244 } 245 } 246 247 dbg(("maxvertab: %d", maxvertab)); 248 if (maxvertab == 0) 249 return 0; 250 251 /* 252 * Store version information in array indexable by version index. 253 * Verify that object version requirements are satisfied along the 254 * way. 255 */ 256 obj->vertabnum = maxvertab + 1; 257 obj->vertab = (Ver_Entry *)xcalloc(obj->vertabnum * sizeof(Ver_Entry)); 258 259 for (vn = obj->verneed; 260 vn != NULL; 261 vn = (const Elf_Verneed *)((const char *)vn + vn->vn_next)) { 262 263 for (vna = (const Elf_Vernaux *)((const char *)vn + vn->vn_aux); 264 /*CONSTCOND*/1; 265 vna = (const Elf_Vernaux *)((const char *)vna + vna->vna_next)) { 266 267 vernum = VER_NEED_IDX(vna->vna_other); 268 assert(vernum <= maxvertab); 269 obj->vertab[vernum].hash = vna->vna_hash; 270 obj->vertab[vernum].name = &strtab[vna->vna_name]; 271 obj->vertab[vernum].file = &strtab[vn->vn_file]; 272 obj->vertab[vernum].flags = 273 (vna->vna_other & VER_NEED_HIDDEN) 274 ? VER_INFO_HIDDEN : 0; 275 dbg(("verneed: vernum: %d, hash: 0x%x, name: %s, " 276 "file: %s, flags: 0x%x", vernum, 277 obj->vertab[vernum].hash, obj->vertab[vernum].name, 278 obj->vertab[vernum].file, 279 obj->vertab[vernum].flags)); 280 281 if (vna->vna_next == 0) { 282 /* No more symbols. */ 283 break; 284 } 285 } 286 if (vn->vn_next == 0) { 287 /* No more dependencies. */ 288 break; 289 } 290 } 291 292 for (vd = obj->verdef; 293 vd != NULL; 294 vd = (const Elf_Verdef *)((const char *)vd + vd->vd_next)) { 295 296 if ((vd->vd_flags & VER_FLG_BASE) == 0) { 297 vernum = VER_DEF_IDX(vd->vd_ndx); 298 assert(vernum <= maxvertab); 299 vda = (const Elf_Verdaux *) 300 ((const char *)vd + vd->vd_aux); 301 obj->vertab[vernum].hash = vd->vd_hash; 302 obj->vertab[vernum].name = &strtab[vda->vda_name]; 303 obj->vertab[vernum].file = NULL; 304 obj->vertab[vernum].flags = 0; 305 dbg(("verdef: vernum: %d, hash: 0x%x, name: %s", 306 vernum, obj->vertab[vernum].hash, 307 obj->vertab[vernum].name)); 308 } 309 310 if (vd->vd_next == 0) { 311 /* No more definitions. */ 312 break; 313 } 314 } 315 316 return 0; 317 } 318