1 /*- 2 * Copyright (c) 2006,2009,2010 Joseph Koshy 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS `AS IS' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 29 #include <assert.h> 30 #include <libelf.h> 31 #include <stdlib.h> 32 #include <string.h> 33 34 #include "_libelf.h" 35 #include "_libelf_ar.h" 36 37 ELFTC_VCSID("$Id: libelf_ar_util.c 2365 2011-12-29 04:36:44Z jkoshy $"); 38 39 /* 40 * Convert a string bounded by `start' and `start+sz' (exclusive) to a 41 * number in the specified base. 42 */ 43 int 44 _libelf_ar_get_number(const char *s, size_t sz, int base, size_t *ret) 45 { 46 int c, v; 47 size_t r; 48 const char *e; 49 50 assert(base <= 10); 51 52 e = s + sz; 53 54 /* skip leading blanks */ 55 for (;s < e && (c = *s) == ' '; s++) 56 ; 57 58 r = 0L; 59 for (;s < e; s++) { 60 if ((c = *s) == ' ') 61 break; 62 if (c < '0' || c > '9') 63 return (0); 64 v = c - '0'; 65 if (v >= base) /* Illegal digit. */ 66 break; 67 r *= base; 68 r += v; 69 } 70 71 *ret = r; 72 73 return (1); 74 } 75 76 /* 77 * Return the translated name for an archive member. 78 */ 79 char * 80 _libelf_ar_get_translated_name(const struct ar_hdr *arh, Elf *ar) 81 { 82 char c, *s; 83 size_t len, offset; 84 const char *buf, *p, *q, *r; 85 const size_t bufsize = sizeof(arh->ar_name); 86 87 assert(arh != NULL); 88 assert(ar->e_kind == ELF_K_AR); 89 assert((const char *) arh >= ar->e_rawfile && 90 (const char *) arh < ar->e_rawfile + ar->e_rawsize); 91 92 buf = arh->ar_name; 93 94 /* 95 * Check for extended naming. 96 * 97 * If the name matches the pattern "^/[0-9]+", it is an 98 * SVR4-style extended name. If the name matches the pattern 99 * "#1/[0-9]+", the entry uses BSD style extended naming. 100 */ 101 if (buf[0] == '/' && (c = buf[1]) >= '0' && c <= '9') { 102 /* 103 * The value in field ar_name is a decimal offset into 104 * the archive string table where the actual name 105 * resides. 106 */ 107 if (_libelf_ar_get_number(buf + 1, bufsize - 1, 10, 108 &offset) == 0) { 109 LIBELF_SET_ERROR(ARCHIVE, 0); 110 return (NULL); 111 } 112 113 if (offset > ar->e_u.e_ar.e_rawstrtabsz) { 114 LIBELF_SET_ERROR(ARCHIVE, 0); 115 return (NULL); 116 } 117 118 p = q = ar->e_u.e_ar.e_rawstrtab + offset; 119 r = ar->e_u.e_ar.e_rawstrtab + ar->e_u.e_ar.e_rawstrtabsz; 120 121 for (; p < r && *p != '/'; p++) 122 ; 123 len = p - q + 1; /* space for the trailing NUL */ 124 125 if ((s = malloc(len)) == NULL) { 126 LIBELF_SET_ERROR(RESOURCE, 0); 127 return (NULL); 128 } 129 130 (void) strncpy(s, q, len - 1); 131 s[len - 1] = '\0'; 132 133 return (s); 134 } else if (IS_EXTENDED_BSD_NAME(buf)) { 135 r = buf + LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE; 136 137 if (_libelf_ar_get_number(r, bufsize - 138 LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE, 10, 139 &len) == 0) { 140 LIBELF_SET_ERROR(ARCHIVE, 0); 141 return (NULL); 142 } 143 144 /* 145 * Allocate space for the file name plus a 146 * trailing NUL. 147 */ 148 if ((s = malloc(len + 1)) == NULL) { 149 LIBELF_SET_ERROR(RESOURCE, 0); 150 return (NULL); 151 } 152 153 /* 154 * The file name follows the archive header. 155 */ 156 q = (const char *) (arh + 1); 157 158 (void) strncpy(s, q, len); 159 s[len] = '\0'; 160 161 return (s); 162 } 163 164 /* 165 * A 'normal' name. 166 * 167 * Skip back over trailing blanks from the end of the field. 168 * In the SVR4 format, a '/' is used as a terminator for 169 * non-special names. 170 */ 171 for (q = buf + bufsize - 1; q >= buf && *q == ' '; --q) 172 ; 173 174 if (q >= buf) { 175 if (*q == '/') { 176 /* 177 * SVR4 style names: ignore the trailing 178 * character '/', but only if the name is not 179 * one of the special names "/" and "//". 180 */ 181 if (q > buf + 1 || 182 (q == (buf + 1) && *buf != '/')) 183 q--; 184 } 185 186 len = q - buf + 2; /* Add space for a trailing NUL. */ 187 } else { 188 /* The buffer only had blanks. */ 189 buf = ""; 190 len = 1; 191 } 192 193 if ((s = malloc(len)) == NULL) { 194 LIBELF_SET_ERROR(RESOURCE, 0); 195 return (NULL); 196 } 197 198 (void) strncpy(s, buf, len - 1); 199 s[len - 1] = '\0'; 200 201 return (s); 202 } 203 204 /* 205 * Return the raw name for an archive member, inclusive of any 206 * formatting characters. 207 */ 208 char * 209 _libelf_ar_get_raw_name(const struct ar_hdr *arh) 210 { 211 char *rawname; 212 const size_t namesz = sizeof(arh->ar_name); 213 214 if ((rawname = malloc(namesz + 1)) == NULL) { 215 LIBELF_SET_ERROR(RESOURCE, 0); 216 return (NULL); 217 } 218 219 (void) strncpy(rawname, arh->ar_name, namesz); 220 rawname[namesz] = '\0'; 221 return (rawname); 222 } 223 224 /* 225 * Open an 'ar' archive. 226 */ 227 Elf * 228 _libelf_ar_open(Elf *e, int reporterror) 229 { 230 size_t sz; 231 int scanahead; 232 char *s, *end; 233 struct ar_hdr arh; 234 235 _libelf_init_elf(e, ELF_K_AR); 236 237 e->e_u.e_ar.e_nchildren = 0; 238 e->e_u.e_ar.e_next = (off_t) -1; 239 240 /* 241 * Look for special members. 242 */ 243 244 s = e->e_rawfile + SARMAG; 245 end = e->e_rawfile + e->e_rawsize; 246 247 assert(e->e_rawsize > 0); 248 249 /* 250 * We use heuristics to determine the flavor of the archive we 251 * are examining. 252 * 253 * SVR4 flavor archives use the name "/ " and "// " for 254 * special members. 255 * 256 * In BSD flavor archives the symbol table, if present, is the 257 * first archive with name "__.SYMDEF". 258 */ 259 260 #define READ_AR_HEADER(S, ARH, SZ, END) \ 261 do { \ 262 if ((S) + sizeof((ARH)) > (END)) \ 263 goto error; \ 264 (void) memcpy(&(ARH), (S), sizeof((ARH))); \ 265 if ((ARH).ar_fmag[0] != '`' || (ARH).ar_fmag[1] != '\n') \ 266 goto error; \ 267 if (_libelf_ar_get_number((ARH).ar_size, \ 268 sizeof((ARH).ar_size), 10, &(SZ)) == 0) \ 269 goto error; \ 270 } while (0) 271 272 READ_AR_HEADER(s, arh, sz, end); 273 274 /* 275 * Handle special archive members for the SVR4 format. 276 */ 277 if (arh.ar_name[0] == '/') { 278 279 assert(sz > 0); 280 281 e->e_flags |= LIBELF_F_AR_VARIANT_SVR4; 282 283 scanahead = 0; 284 285 /* 286 * The symbol table (file name "/ ") always comes before the 287 * string table (file name "// "). 288 */ 289 if (arh.ar_name[1] == ' ') { 290 /* "/ " => symbol table. */ 291 scanahead = 1; /* The string table to follow. */ 292 293 s += sizeof(arh); 294 e->e_u.e_ar.e_rawsymtab = s; 295 e->e_u.e_ar.e_rawsymtabsz = sz; 296 297 sz = LIBELF_ADJUST_AR_SIZE(sz); 298 s += sz; 299 300 } else if (arh.ar_name[1] == '/' && arh.ar_name[2] == ' ') { 301 /* "// " => string table for long file names. */ 302 s += sizeof(arh); 303 e->e_u.e_ar.e_rawstrtab = s; 304 e->e_u.e_ar.e_rawstrtabsz = sz; 305 306 sz = LIBELF_ADJUST_AR_SIZE(sz); 307 s += sz; 308 } 309 310 /* 311 * If the string table hasn't been seen yet, look for 312 * it in the next member. 313 */ 314 if (scanahead) { 315 READ_AR_HEADER(s, arh, sz, end); 316 317 /* "// " => string table for long file names. */ 318 if (arh.ar_name[0] == '/' && arh.ar_name[1] == '/' && 319 arh.ar_name[2] == ' ') { 320 321 s += sizeof(arh); 322 323 e->e_u.e_ar.e_rawstrtab = s; 324 e->e_u.e_ar.e_rawstrtabsz = sz; 325 326 sz = LIBELF_ADJUST_AR_SIZE(sz); 327 s += sz; 328 } 329 } 330 } else if (strncmp(arh.ar_name, LIBELF_AR_BSD_SYMTAB_NAME, 331 sizeof(LIBELF_AR_BSD_SYMTAB_NAME) - 1) == 0) { 332 /* 333 * BSD style archive symbol table. 334 */ 335 s += sizeof(arh); 336 e->e_u.e_ar.e_rawsymtab = s; 337 e->e_u.e_ar.e_rawsymtabsz = sz; 338 339 sz = LIBELF_ADJUST_AR_SIZE(sz); 340 s += sz; 341 } 342 343 /* 344 * Update the 'next' offset, so that a subsequent elf_begin() 345 * works as expected. 346 */ 347 e->e_u.e_ar.e_next = (off_t) (s - e->e_rawfile); 348 349 return (e); 350 351 error: 352 if (!reporterror) { 353 e->e_kind = ELF_K_NONE; 354 return (e); 355 } 356 357 LIBELF_SET_ERROR(ARCHIVE, 0); 358 return (NULL); 359 } 360