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