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 3157 2015-02-15 21:42:02Z emaste $"); 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 *src, size_t sz, unsigned int base, 45 size_t *ret) 46 { 47 size_t r; 48 unsigned int c, v; 49 const unsigned char *e, *s; 50 51 assert(base <= 10); 52 53 s = (const unsigned char *) src; 54 e = s + sz; 55 56 /* skip leading blanks */ 57 for (;s < e && (c = *s) == ' '; s++) 58 ; 59 60 r = 0L; 61 for (;s < e; s++) { 62 if ((c = *s) == ' ') 63 break; 64 if (c < '0' || c > '9') 65 return (0); 66 v = c - '0'; 67 if (v >= base) /* Illegal digit. */ 68 break; 69 r *= base; 70 r += v; 71 } 72 73 *ret = r; 74 75 return (1); 76 } 77 78 /* 79 * Return the translated name for an archive member. 80 */ 81 char * 82 _libelf_ar_get_translated_name(const struct ar_hdr *arh, Elf *ar) 83 { 84 char *s; 85 unsigned char c; 86 size_t len, offset; 87 const unsigned char *buf, *p, *q, *r; 88 const size_t bufsize = sizeof(arh->ar_name); 89 90 assert(arh != NULL); 91 assert(ar->e_kind == ELF_K_AR); 92 assert((const unsigned char *) arh >= ar->e_rawfile && 93 (const unsigned char *) arh < ar->e_rawfile + ar->e_rawsize); 94 95 buf = (const unsigned char *) arh->ar_name; 96 97 /* 98 * Check for extended naming. 99 * 100 * If the name matches the pattern "^/[0-9]+", it is an 101 * SVR4-style extended name. If the name matches the pattern 102 * "#1/[0-9]+", the entry uses BSD style extended naming. 103 */ 104 if (buf[0] == '/' && (c = buf[1]) >= '0' && c <= '9') { 105 /* 106 * The value in field ar_name is a decimal offset into 107 * the archive string table where the actual name 108 * resides. 109 */ 110 if (_libelf_ar_get_number((const char *) (buf + 1), 111 bufsize - 1, 10, &offset) == 0) { 112 LIBELF_SET_ERROR(ARCHIVE, 0); 113 return (NULL); 114 } 115 116 if (offset > ar->e_u.e_ar.e_rawstrtabsz) { 117 LIBELF_SET_ERROR(ARCHIVE, 0); 118 return (NULL); 119 } 120 121 p = q = ar->e_u.e_ar.e_rawstrtab + offset; 122 r = ar->e_u.e_ar.e_rawstrtab + ar->e_u.e_ar.e_rawstrtabsz; 123 124 for (; p < r && *p != '/'; p++) 125 ; 126 len = (size_t) (p - q + 1); /* space for the trailing NUL */ 127 128 if ((s = malloc(len)) == NULL) { 129 LIBELF_SET_ERROR(RESOURCE, 0); 130 return (NULL); 131 } 132 133 (void) strncpy(s, (const char *) q, len - 1); 134 s[len - 1] = '\0'; 135 136 return (s); 137 } else if (IS_EXTENDED_BSD_NAME(buf)) { 138 r = buf + LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE; 139 140 if (_libelf_ar_get_number((const char *) r, bufsize - 141 LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE, 10, 142 &len) == 0) { 143 LIBELF_SET_ERROR(ARCHIVE, 0); 144 return (NULL); 145 } 146 147 /* 148 * Allocate space for the file name plus a 149 * trailing NUL. 150 */ 151 if ((s = malloc(len + 1)) == NULL) { 152 LIBELF_SET_ERROR(RESOURCE, 0); 153 return (NULL); 154 } 155 156 /* 157 * The file name follows the archive header. 158 */ 159 q = (const unsigned char *) (arh + 1); 160 161 (void) strncpy(s, (const char *) q, len); 162 s[len] = '\0'; 163 164 return (s); 165 } 166 167 /* 168 * A 'normal' name. 169 * 170 * Skip back over trailing blanks from the end of the field. 171 * In the SVR4 format, a '/' is used as a terminator for 172 * non-special names. 173 */ 174 for (q = buf + bufsize - 1; q >= buf && *q == ' '; --q) 175 ; 176 177 if (q >= buf) { 178 if (*q == '/') { 179 /* 180 * SVR4 style names: ignore the trailing 181 * character '/', but only if the name is not 182 * one of the special names "/" and "//". 183 */ 184 if (q > buf + 1 || 185 (q == (buf + 1) && *buf != '/')) 186 q--; 187 } 188 189 len = (size_t) (q - buf + 2); /* Space for a trailing NUL. */ 190 } else { 191 /* The buffer only had blanks. */ 192 buf = (const unsigned char *) ""; 193 len = 1; 194 } 195 196 if ((s = malloc(len)) == NULL) { 197 LIBELF_SET_ERROR(RESOURCE, 0); 198 return (NULL); 199 } 200 201 (void) strncpy(s, (const char *) buf, len - 1); 202 s[len - 1] = '\0'; 203 204 return (s); 205 } 206 207 /* 208 * Return the raw name for an archive member, inclusive of any 209 * formatting characters. 210 */ 211 char * 212 _libelf_ar_get_raw_name(const struct ar_hdr *arh) 213 { 214 char *rawname; 215 const size_t namesz = sizeof(arh->ar_name); 216 217 if ((rawname = malloc(namesz + 1)) == NULL) { 218 LIBELF_SET_ERROR(RESOURCE, 0); 219 return (NULL); 220 } 221 222 (void) strncpy(rawname, arh->ar_name, namesz); 223 rawname[namesz] = '\0'; 224 return (rawname); 225 } 226 227 /* 228 * Open an 'ar' archive. 229 */ 230 Elf * 231 _libelf_ar_open(Elf *e, int reporterror) 232 { 233 size_t sz; 234 int scanahead; 235 struct ar_hdr arh; 236 unsigned char *s, *end; 237 238 _libelf_init_elf(e, ELF_K_AR); 239 240 e->e_u.e_ar.e_nchildren = 0; 241 e->e_u.e_ar.e_next = (off_t) -1; 242 243 /* 244 * Look for special members. 245 */ 246 247 s = e->e_rawfile + SARMAG; 248 end = e->e_rawfile + e->e_rawsize; 249 250 assert(e->e_rawsize > 0); 251 252 /* 253 * We use heuristics to determine the flavor of the archive we 254 * are examining. 255 * 256 * SVR4 flavor archives use the name "/ " and "// " for 257 * special members. 258 * 259 * In BSD flavor archives the symbol table, if present, is the 260 * first archive with name "__.SYMDEF". 261 */ 262 263 #define READ_AR_HEADER(S, ARH, SZ, END) \ 264 do { \ 265 if ((S) + sizeof((ARH)) > (END)) \ 266 goto error; \ 267 (void) memcpy(&(ARH), (S), sizeof((ARH))); \ 268 if ((ARH).ar_fmag[0] != '`' || (ARH).ar_fmag[1] != '\n') \ 269 goto error; \ 270 if (_libelf_ar_get_number((char *) (ARH).ar_size, \ 271 sizeof((ARH).ar_size), 10, &(SZ)) == 0) \ 272 goto error; \ 273 } while (0) 274 275 READ_AR_HEADER(s, arh, sz, end); 276 277 /* 278 * Handle special archive members for the SVR4 format. 279 */ 280 if (arh.ar_name[0] == '/') { 281 if (sz == 0) 282 goto error; 283 284 e->e_flags |= LIBELF_F_AR_VARIANT_SVR4; 285 286 scanahead = 0; 287 288 /* 289 * The symbol table (file name "/ ") always comes before the 290 * string table (file name "// "). 291 */ 292 if (arh.ar_name[1] == ' ') { 293 /* "/ " => symbol table. */ 294 scanahead = 1; /* The string table to follow. */ 295 296 s += sizeof(arh); 297 e->e_u.e_ar.e_rawsymtab = s; 298 e->e_u.e_ar.e_rawsymtabsz = sz; 299 300 sz = LIBELF_ADJUST_AR_SIZE(sz); 301 s += sz; 302 303 } else if (arh.ar_name[1] == '/' && arh.ar_name[2] == ' ') { 304 /* "// " => string table for long file names. */ 305 s += sizeof(arh); 306 e->e_u.e_ar.e_rawstrtab = s; 307 e->e_u.e_ar.e_rawstrtabsz = sz; 308 309 sz = LIBELF_ADJUST_AR_SIZE(sz); 310 s += sz; 311 } 312 313 /* 314 * If the string table hasn't been seen yet, look for 315 * it in the next member. 316 */ 317 if (scanahead) { 318 READ_AR_HEADER(s, arh, sz, end); 319 320 /* "// " => string table for long file names. */ 321 if (arh.ar_name[0] == '/' && arh.ar_name[1] == '/' && 322 arh.ar_name[2] == ' ') { 323 324 s += sizeof(arh); 325 326 e->e_u.e_ar.e_rawstrtab = s; 327 e->e_u.e_ar.e_rawstrtabsz = sz; 328 329 sz = LIBELF_ADJUST_AR_SIZE(sz); 330 s += sz; 331 } 332 } 333 } else if (strncmp(arh.ar_name, LIBELF_AR_BSD_SYMTAB_NAME, 334 sizeof(LIBELF_AR_BSD_SYMTAB_NAME) - 1) == 0) { 335 /* 336 * BSD style archive symbol table. 337 */ 338 s += sizeof(arh); 339 e->e_u.e_ar.e_rawsymtab = s; 340 e->e_u.e_ar.e_rawsymtabsz = sz; 341 342 sz = LIBELF_ADJUST_AR_SIZE(sz); 343 s += sz; 344 } 345 346 /* 347 * Update the 'next' offset, so that a subsequent elf_begin() 348 * works as expected. 349 */ 350 e->e_u.e_ar.e_next = (off_t) (s - e->e_rawfile); 351 352 return (e); 353 354 error: 355 if (!reporterror) { 356 e->e_kind = ELF_K_NONE; 357 return (e); 358 } 359 360 LIBELF_SET_ERROR(ARCHIVE, 0); 361 return (NULL); 362 } 363