1 /*
2  * strptr.c - implementation of the elf_strptr(3) function.
3  * Copyright (C) 1995 - 2007 Michael Riepe
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19 
20 #include <private.h>
21 
22 #ifndef lint
23 static const char rcsid[] = "@(#) $Id: strptr.c,v 1.12 2008/05/23 08:15:35 michael Exp $";
24 #endif /* lint */
25 
26 char*
elf_strptr(Elf * elf,size_t section,size_t offset)27 elf_strptr(Elf *elf, size_t section, size_t offset) {
28     Elf_Data *data;
29     Elf_Scn *scn;
30     size_t n;
31     char *s;
32 
33     if (!elf) {
34 	return NULL;
35     }
36     elf_assert(elf->e_magic == ELF_MAGIC);
37     if (!(scn = elf_getscn(elf, section))) {
38 	return NULL;
39     }
40     if (scn->s_index == SHN_UNDEF) {
41 	seterr(ERROR_NOSTRTAB);
42 	return NULL;
43     }
44     /*
45      * checking the section header is more appropriate
46      */
47     if (elf->e_class == ELFCLASS32) {
48 	if (scn->s_shdr32.sh_type != SHT_STRTAB) {
49 	    seterr(ERROR_NOSTRTAB);
50 	    return NULL;
51 	}
52     }
53 #if __LIBELF64
54     else if (elf->e_class == ELFCLASS64) {
55 	if (scn->s_shdr64.sh_type != SHT_STRTAB) {
56 	    seterr(ERROR_NOSTRTAB);
57 	    return NULL;
58 	}
59     }
60 #endif /* __LIBELF64 */
61     else if (valid_class(elf->e_class)) {
62 	seterr(ERROR_UNIMPLEMENTED);
63 	return NULL;
64     }
65     else {
66 	seterr(ERROR_UNKNOWN_CLASS);
67 	return NULL;
68     }
69     /*
70      * Find matching buffer
71      */
72     n = 0;
73     data = NULL;
74     if (elf->e_elf_flags & ELF_F_LAYOUT) {
75 	/*
76 	 * Programmer is responsible for d_off
77 	 * Note: buffers may be in any order!
78 	 */
79 	while ((data = elf_getdata(scn, data))) {
80 	    n = data->d_off;
81 	    if (offset >= n && offset - n < data->d_size) {
82 		/*
83 		 * Found it
84 		 */
85 		break;
86 	    }
87 	}
88     }
89     else {
90 	/*
91 	 * Calculate offsets myself
92 	 */
93 	while ((data = elf_getdata(scn, data))) {
94 	    if (data->d_align > 1) {
95 		n += data->d_align - 1;
96 		n -= n % data->d_align;
97 	    }
98 	    if (offset < n) {
99 		/*
100 		 * Invalid offset: points into a hole
101 		 */
102 		seterr(ERROR_BADSTROFF);
103 		return NULL;
104 	    }
105 	    if (offset - n < data->d_size) {
106 		/*
107 		 * Found it
108 		 */
109 		break;
110 	    }
111 	    n += data->d_size;
112 	}
113     }
114     if (data == NULL) {
115 	/*
116 	 * Not found
117 	 */
118 	seterr(ERROR_BADSTROFF);
119 	return NULL;
120     }
121     if (data->d_buf == NULL) {
122 	/*
123 	 * Buffer is NULL (usually the programmers' fault)
124 	 */
125 	seterr(ERROR_NULLBUF);
126 	return NULL;
127     }
128     offset -= n;
129     s = (char*)data->d_buf;
130     if (!(_elf_sanity_checks & SANITY_CHECK_STRPTR)) {
131 	return s + offset;
132     }
133     /*
134      * Perform extra sanity check
135      */
136     for (n = offset; n < data->d_size; n++) {
137 	if (s[n] == '\0') {
138 	    /*
139 	     * Return properly NUL terminated string
140 	     */
141 	    return s + offset;
142 	}
143     }
144     /*
145      * String is not NUL terminated
146      * Return error to avoid SEGV in application
147      */
148     seterr(ERROR_UNTERM);
149     return NULL;
150 }
151