xref: /illumos-gate/usr/src/cmd/file/elf_read.c (revision 9b8f1941)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
22 /*	  All Rights Reserved	*/
23 
24 
25 /*	Copyright (c) 1987, 1988 Microsoft Corporation	*/
26 /*	  All Rights Reserved	*/
27 
28 /*
29  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
30  * Use is subject to license terms.
31  */
32 
33 /*
34  * ELF files can exceed 2GB in size. A standard 32-bit program
35  * like 'file' cannot read past 2GB, and will be unable to see
36  * the ELF section headers that typically are at the end of the
37  * object. The simplest solution to this problem would be to make
38  * the 'file' command a 64-bit application. However, as a matter of
39  * policy, we do not want to require this. A simple command like
40  * 'file' should not carry such a requirement, especially as we
41  * support 32-bit only hardware.
42  *
43  * An alternative solution is to build this code as 32-bit
44  * large file aware. The usual way to do this is to define a pair
45  * of preprocessor definitions:
46  *
47  *	_LARGEFILE64_SOURCE
48  *		Map standard I/O routines to their largefile aware versions.
49  *
50  *	_FILE_OFFSET_BITS=64
51  *		Map off_t to off64_t
52  *
53  * The problem with this solution is that libelf is not large file capable,
54  * and the libelf header file will prevent compilation if
55  * _FILE_OFFSET_BITS is set to 64.
56  *
57  * So, the solution used in this code is to define _LARGEFILE64_SOURCE
58  * to get access to the 64-bit APIs, not to define _FILE_OFFSET_BITS, and to
59  * use our own types in place of off_t, and size_t. We read all the file
60  * data directly using pread64(), and avoid the use of libelf for anything
61  * other than the xlate functionality.
62  */
63 #define	_LARGEFILE64_SOURCE
64 #define	FILE_ELF_OFF_T	off64_t
65 #define	FILE_ELF_SIZE_T	uint64_t
66 
67 #include <ctype.h>
68 #include <unistd.h>
69 #include <fcntl.h>
70 #include <stdio.h>
71 #include <libelf.h>
72 #include <stdlib.h>
73 #include <limits.h>
74 #include <locale.h>
75 #include <string.h>
76 #include <errno.h>
77 #include <procfs.h>
78 #include <sys/param.h>
79 #include <sys/types.h>
80 #include <sys/stat.h>
81 #include <sys/elf.h>
82 #include <sys/link.h>
83 #include <elfcap.h>
84 #include "file.h"
85 #include "elf_read.h"
86 
87 extern const char *File;
88 
89 static int get_class(void);
90 static int get_version(void);
91 static int get_format(void);
92 static int process_shdr(Elf_Info *);
93 static int process_phdr(Elf_Info *);
94 static int file_xlatetom(Elf_Type, char *);
95 static int xlatetom_nhdr(Elf_Nhdr *);
96 static int get_phdr(Elf_Info *, int);
97 static int get_shdr(Elf_Info *, int);
98 
99 static Elf_Ehdr	EI_Ehdr;		/* Elf_Ehdr to be stored */
100 static Elf_Word	EI_Ehdr_shnum;		/* # section headers */
101 static Elf_Word	EI_Ehdr_phnum;		/* # program headers */
102 static Elf_Word	EI_Ehdr_shstrndx;	/* Index of section hdr string table */
103 static Elf_Shdr	EI_Shdr;		/* recent Elf_Shdr to be stored */
104 static Elf_Phdr	EI_Phdr;		/* recent Elf_Phdr to be stored */
105 
106 
107 static int
get_class(void)108 get_class(void)
109 {
110 	return (EI_Ehdr.e_ident[EI_CLASS]);
111 }
112 
113 static int
get_version(void)114 get_version(void)
115 {
116 	/* do as what libelf:_elf_config() does */
117 	return (EI_Ehdr.e_ident[EI_VERSION] ?
118 	    EI_Ehdr.e_ident[EI_VERSION] : 1);
119 }
120 
121 static int
get_format(void)122 get_format(void)
123 {
124 	return (EI_Ehdr.e_ident[EI_DATA]);
125 }
126 
127 /*
128  * file_xlatetom:	translate different headers from file
129  *			representation to memory representaion.
130  */
131 #define	HDRSZ 512
132 static int
file_xlatetom(Elf_Type type,char * hdr)133 file_xlatetom(Elf_Type type, char *hdr)
134 {
135 	Elf_Data src, dst;
136 	char *hbuf[HDRSZ];
137 	int version, format;
138 
139 	version = get_version();
140 	format = get_format();
141 
142 	/* will convert only these types */
143 	if (type != ELF_T_EHDR && type != ELF_T_PHDR &&
144 	    type != ELF_T_SHDR && type != ELF_T_WORD &&
145 	    type != ELF_T_CAP && type != ELF_T_DYN)
146 		return (ELF_READ_FAIL);
147 
148 	src.d_buf = (Elf_Void *)hdr;
149 	src.d_type = type;
150 	src.d_version = version;
151 
152 	dst.d_buf = (Elf_Void *)&hbuf;
153 	dst.d_version = EV_CURRENT;
154 
155 	src.d_size = elf_fsize(type, 1, version);
156 	dst.d_size = elf_fsize(type, 1, EV_CURRENT);
157 	if (elf_xlatetom(&dst, &src, format) == NULL)
158 		return (ELF_READ_FAIL);
159 
160 	(void) memcpy(hdr, &hbuf, dst.d_size);
161 	return (ELF_READ_OKAY);
162 }
163 
164 /*
165  * xlatetom_nhdr:	There is no routine to convert Note header
166  *			so we convert each field of this header.
167  */
168 static int
xlatetom_nhdr(Elf_Nhdr * nhdr)169 xlatetom_nhdr(Elf_Nhdr *nhdr)
170 {
171 	int r = ELF_READ_FAIL;
172 
173 	r |= file_xlatetom(ELF_T_WORD, (char *)&nhdr->n_namesz);
174 	r |= file_xlatetom(ELF_T_WORD, (char *)&nhdr->n_descsz);
175 	r |= file_xlatetom(ELF_T_WORD, (char *)&nhdr->n_type);
176 	return (r);
177 }
178 
179 /*
180  * elf_read:	reads elf header, program, section headers to
181  *		collect all information needed for file(1)
182  *		output and stores them in Elf_Info.
183  */
184 int
elf_read(int fd,Elf_Info * EI)185 elf_read(int fd, Elf_Info *EI)
186 {
187 	FILE_ELF_SIZE_T	size;
188 	int		ret = 1;
189 
190 	Elf_Ehdr *ehdr = &EI_Ehdr;
191 
192 	EI->elffd = fd;
193 	size = sizeof (Elf_Ehdr);
194 
195 	if (pread64(EI->elffd, (void*)ehdr, size, 0) != size)
196 		ret = 0;
197 
198 
199 	if (file_xlatetom(ELF_T_EHDR, (char *)ehdr) == ELF_READ_FAIL)
200 		ret = 0;
201 
202 	if (EI->file == NULL)
203 		return (ELF_READ_FAIL);
204 
205 	/*
206 	 * Extended section or program indexes in use? If so, special
207 	 * values in the ELF header redirect us to get the real values
208 	 * from shdr[0].
209 	 */
210 	EI_Ehdr_shnum = EI_Ehdr.e_shnum;
211 	EI_Ehdr_phnum = EI_Ehdr.e_phnum;
212 	EI_Ehdr_shstrndx = EI_Ehdr.e_shstrndx;
213 	if (((EI_Ehdr_shnum == 0) || (EI_Ehdr_phnum == PN_XNUM)) &&
214 	    (EI_Ehdr.e_shoff != 0)) {
215 		if (get_shdr(EI, 0) == ELF_READ_FAIL)
216 			return (ELF_READ_FAIL);
217 		if (EI_Ehdr_shnum == 0)
218 			EI_Ehdr_shnum = EI_Shdr.sh_size;
219 		if ((EI_Ehdr_phnum == PN_XNUM) && (EI_Shdr.sh_info != 0))
220 			EI_Ehdr_phnum = EI_Shdr.sh_info;
221 		if (EI_Ehdr_shstrndx == SHN_XINDEX)
222 			EI_Ehdr_shstrndx = EI_Shdr.sh_link;
223 	}
224 
225 	EI->type = ehdr->e_type;
226 	EI->machine = ehdr->e_machine;
227 	EI->flags = ehdr->e_flags;
228 
229 	if (ret == 0) {
230 		(void) fprintf(stderr, gettext("%s: %s: can't "
231 		    "read ELF header\n"), File, EI->file);
232 		return (ELF_READ_FAIL);
233 	}
234 	if (process_phdr(EI) == ELF_READ_FAIL)
235 		return (ELF_READ_FAIL);
236 
237 	/* We don't need section info for core files */
238 	if (ehdr->e_type != ET_CORE)
239 		if (process_shdr(EI) == ELF_READ_FAIL)
240 			return (ELF_READ_FAIL);
241 
242 	return (ELF_READ_OKAY);
243 }
244 
245 /*
246  * get_phdr:	reads program header of specified index.
247  */
248 static int
get_phdr(Elf_Info * EI,int inx)249 get_phdr(Elf_Info *EI, int inx)
250 {
251 	FILE_ELF_OFF_T	off = 0;
252 	FILE_ELF_SIZE_T	size;
253 
254 	if (inx >= EI_Ehdr_phnum)
255 		return (ELF_READ_FAIL);
256 
257 	size = sizeof (Elf_Phdr);
258 	off = (FILE_ELF_OFF_T)EI_Ehdr.e_phoff + (inx * size);
259 	if (pread64(EI->elffd, (void *)&EI_Phdr, size, off) != size)
260 		return (ELF_READ_FAIL);
261 
262 	if (file_xlatetom(ELF_T_PHDR, (char *)&EI_Phdr) == ELF_READ_FAIL)
263 		return (ELF_READ_FAIL);
264 
265 	return (ELF_READ_OKAY);
266 }
267 
268 /*
269  * get_shdr:	reads section header of specified index.
270  */
271 static int
get_shdr(Elf_Info * EI,int inx)272 get_shdr(Elf_Info *EI, int inx)
273 {
274 	FILE_ELF_OFF_T	off = 0;
275 	FILE_ELF_SIZE_T	size;
276 
277 	/*
278 	 * Prevent access to non-existent section headers.
279 	 *
280 	 * A value of 0 for e_shoff means that there is no section header
281 	 * array in the file. A value of 0 for e_shndx does not necessarily
282 	 * mean this - there can still be a 1-element section header array
283 	 * to support extended section or program header indexes that
284 	 * exceed the 16-bit fields used in the ELF header to represent them.
285 	 */
286 	if ((EI_Ehdr.e_shoff == 0) || ((inx > 0) && (inx >= EI_Ehdr_shnum)))
287 		return (ELF_READ_FAIL);
288 
289 	size = sizeof (Elf_Shdr);
290 	off = (FILE_ELF_OFF_T)EI_Ehdr.e_shoff + (inx * size);
291 
292 	if (pread64(EI->elffd, (void *)&EI_Shdr, size, off) != size)
293 		return (ELF_READ_FAIL);
294 
295 	if (file_xlatetom(ELF_T_SHDR, (char *)&EI_Shdr) == ELF_READ_FAIL)
296 		return (ELF_READ_FAIL);
297 
298 	return (ELF_READ_OKAY);
299 }
300 
301 /*
302  * process_phdr:	Read Program Headers and see if it is a core
303  *			file of either new or (pre-restructured /proc)
304  *			type, read the name of the file that dumped this
305  *			core, else see if this is a dynamically linked.
306  */
307 static int
process_phdr(Elf_Info * EI)308 process_phdr(Elf_Info *EI)
309 {
310 	register int inx;
311 
312 	Elf_Nhdr	Nhdr, *nhdr;	/* note header just read */
313 	Elf_Phdr	*phdr = &EI_Phdr;
314 
315 	FILE_ELF_SIZE_T	nsz, nmsz, dsz;
316 	FILE_ELF_OFF_T	offset;
317 	int	class;
318 	int	ntype;
319 	char	*psinfo, *fname;
320 
321 	nsz = sizeof (Elf_Nhdr);
322 	nhdr = &Nhdr;
323 	class = get_class();
324 	for (inx = 0; inx < EI_Ehdr_phnum; inx++) {
325 		if (get_phdr(EI, inx) == ELF_READ_FAIL)
326 			return (ELF_READ_FAIL);
327 
328 		/* read the note if it is a core */
329 		if (phdr->p_type == PT_NOTE &&
330 		    EI_Ehdr.e_type == ET_CORE) {
331 			/*
332 			 * If the next segment is also a note, use it instead.
333 			 */
334 			if (get_phdr(EI, inx+1) == ELF_READ_FAIL)
335 				return (ELF_READ_FAIL);
336 			if (phdr->p_type != PT_NOTE) {
337 				/* read the first phdr back */
338 				if (get_phdr(EI, inx) == ELF_READ_FAIL)
339 					return (ELF_READ_FAIL);
340 			}
341 			offset = phdr->p_offset;
342 			if (pread64(EI->elffd, (void *)nhdr, nsz, offset)
343 			    != nsz)
344 				return (ELF_READ_FAIL);
345 
346 			/* Translate the ELF note header */
347 			if (xlatetom_nhdr(nhdr) == ELF_READ_FAIL)
348 				return (ELF_READ_FAIL);
349 
350 			ntype = nhdr->n_type;
351 			nmsz = nhdr->n_namesz;
352 			dsz = nhdr->n_descsz;
353 
354 			offset += nsz + ((nmsz + 0x03) & ~0x3);
355 			if ((psinfo = malloc(dsz)) == NULL) {
356 				int err = errno;
357 				(void) fprintf(stderr, gettext("%s: malloc "
358 				    "failed: %s\n"), File, strerror(err));
359 				exit(1);
360 			}
361 			if (pread64(EI->elffd, psinfo, dsz, offset) != dsz)
362 				return (ELF_READ_FAIL);
363 			/*
364 			 * We want to print the string contained
365 			 * in psinfo->pr_fname[], where 'psinfo'
366 			 * is either an old NT_PRPSINFO structure
367 			 * or a new NT_PSINFO structure.
368 			 *
369 			 * Old core files have only type NT_PRPSINFO.
370 			 * New core files have type NT_PSINFO.
371 			 *
372 			 * These structures are also different by
373 			 * virtue of being contained in a core file
374 			 * of either 32-bit or 64-bit type.
375 			 *
376 			 * To further complicate matters, we ourself
377 			 * might be compiled either 32-bit or 64-bit.
378 			 *
379 			 * For these reason, we just *know* the offsets of
380 			 * pr_fname[] into the four different structures
381 			 * here, regardless of how we are compiled.
382 			 */
383 			if (class == ELFCLASS32) {
384 				/* 32-bit core file, 32-bit structures */
385 				if (ntype == NT_PSINFO)
386 					fname = psinfo + 88;
387 				else	/* old: NT_PRPSINFO */
388 					fname = psinfo + 84;
389 			} else if (class == ELFCLASS64) {
390 				/* 64-bit core file, 64-bit structures */
391 				if (ntype == NT_PSINFO)
392 					fname = psinfo + 136;
393 				else	/* old: NT_PRPSINFO */
394 					fname = psinfo + 120;
395 			}
396 			EI->core_type = (ntype == NT_PRPSINFO)?
397 			    EC_OLDCORE : EC_NEWCORE;
398 			(void) memcpy(EI->fname, fname, strlen(fname));
399 			free(psinfo);
400 		}
401 		if (phdr->p_type == PT_DYNAMIC) {
402 			EI->dynamic = B_TRUE;
403 		}
404 	}
405 	return (ELF_READ_OKAY);
406 }
407 
408 /*
409  * process_shdr:	Read Section Headers to attempt to get HW/SW
410  *			capabilities by looking at the SUNW_cap
411  *			section and set string in Elf_Info.
412  *			Also look for symbol tables and debug
413  *			information sections. Set the "stripped" field
414  *			in Elf_Info with corresponding flags.
415  */
416 static int
process_shdr(Elf_Info * EI)417 process_shdr(Elf_Info *EI)
418 {
419 	int		mac;
420 	int		i, idx;
421 	char		*strtab;
422 	size_t		strtab_sz;
423 	uint64_t	j;
424 	Elf_Shdr	*shdr = &EI_Shdr;
425 
426 	mac = EI_Ehdr.e_machine;
427 
428 	/* if there are no sections, return success anyway */
429 	if (EI_Ehdr.e_shoff == 0 && EI_Ehdr_shnum == 0)
430 		return (ELF_READ_OKAY);
431 
432 	/* read section names from String Section */
433 	if (get_shdr(EI, EI_Ehdr_shstrndx) == ELF_READ_FAIL)
434 		return (ELF_READ_FAIL);
435 
436 	if ((strtab = malloc(shdr->sh_size)) == NULL)
437 		return (ELF_READ_FAIL);
438 
439 	if (pread64(EI->elffd, strtab, shdr->sh_size, shdr->sh_offset)
440 	    != shdr->sh_size)
441 		return (ELF_READ_FAIL);
442 
443 	strtab_sz = shdr->sh_size;
444 
445 	/* read all the sections and process them */
446 	for (idx = 1, i = 0; i < EI_Ehdr_shnum; idx++, i++) {
447 		char *shnam;
448 
449 		if (get_shdr(EI, i) == ELF_READ_FAIL)
450 			return (ELF_READ_FAIL);
451 
452 		if (shdr->sh_type == SHT_NULL) {
453 			idx--;
454 			continue;
455 		}
456 
457 		if (shdr->sh_type == SHT_SUNW_cap) {
458 			char		capstr[128];
459 			Elf_Cap		Chdr;
460 			FILE_ELF_OFF_T	cap_off;
461 			FILE_ELF_SIZE_T	csize;
462 			uint64_t capn;
463 
464 			cap_off = shdr->sh_offset;
465 			csize = sizeof (Elf_Cap);
466 
467 			if (shdr->sh_size == 0 || shdr->sh_entsize == 0) {
468 				(void) fprintf(stderr, ELF_ERR_ELFCAP1,
469 				    File, EI->file);
470 				return (ELF_READ_FAIL);
471 			}
472 			capn = (shdr->sh_size / shdr->sh_entsize);
473 			for (j = 0; j < capn; j++) {
474 				/*
475 				 * read cap and xlate the values
476 				 */
477 				if ((pread64(EI->elffd, &Chdr, csize, cap_off)
478 				    != csize) ||
479 				    file_xlatetom(ELF_T_CAP, (char *)&Chdr)
480 				    == 0) {
481 					(void) fprintf(stderr, ELF_ERR_ELFCAP2,
482 					    File, EI->file);
483 					return (ELF_READ_FAIL);
484 				}
485 
486 				cap_off += csize;
487 
488 				/*
489 				 * Each capatibility group is terminated with
490 				 * CA_SUNW_NULL.  Groups other than the first
491 				 * represent symbol capabilities, and aren't
492 				 * interesting here.
493 				 */
494 				if (Chdr.c_tag == CA_SUNW_NULL)
495 					break;
496 
497 				(void) elfcap_tag_to_str(ELFCAP_STYLE_UC,
498 				    Chdr.c_tag, Chdr.c_un.c_val, capstr,
499 				    sizeof (capstr), ELFCAP_FMT_SNGSPACE,
500 				    mac);
501 
502 				if ((*EI->cap_str != '\0') && (*capstr != '\0'))
503 					(void) strlcat(EI->cap_str, " ",
504 					    sizeof (EI->cap_str));
505 
506 				(void) strlcat(EI->cap_str, capstr,
507 				    sizeof (EI->cap_str));
508 			}
509 		} else if (shdr->sh_type == SHT_DYNAMIC) {
510 			Elf_Dyn dyn;
511 			FILE_ELF_SIZE_T dsize;
512 			FILE_ELF_OFF_T doff;
513 			uint64_t dynn;
514 
515 			doff = shdr->sh_offset;
516 			dsize = sizeof (Elf_Dyn);
517 
518 			if (shdr->sh_size == 0 || shdr->sh_entsize == 0) {
519 				(void) fprintf(stderr, ELF_ERR_DYNAMIC1,
520 				    File, EI->file);
521 				return (ELF_READ_FAIL);
522 			}
523 
524 			dynn = (shdr->sh_size / shdr->sh_entsize);
525 			for (j = 0; j < dynn; j++) {
526 				if (pread64(EI->elffd, &dyn, dsize, doff)
527 				    != dsize ||
528 				    file_xlatetom(ELF_T_DYN, (char *)&dyn)
529 				    == 0) {
530 					(void) fprintf(stderr, ELF_ERR_DYNAMIC2,
531 					    File, EI->file);
532 					return (ELF_READ_FAIL);
533 				}
534 
535 				doff += dsize;
536 
537 				if ((dyn.d_tag == DT_SUNW_KMOD) &&
538 				    (dyn.d_un.d_val == 1)) {
539 					EI->kmod = B_TRUE;
540 				}
541 			}
542 		}
543 
544 		/*
545 		 * Definition time:
546 		 *	- "not stripped" means that an executable file
547 		 *	contains a Symbol Table (.symtab)
548 		 *	- "stripped" means that an executable file
549 		 *	does not contain a Symbol Table.
550 		 * When strip -l or strip -x is run, it strips the
551 		 * debugging information (.line section name (strip -l),
552 		 * .line, .debug*, .stabs*, .dwarf* section names
553 		 * and SHT_SUNW_DEBUGSTR and SHT_SUNW_DEBUG
554 		 * section types (strip -x), however the Symbol
555 		 * Table will still be present.
556 		 * Therefore, if
557 		 *	- No Symbol Table present, then report
558 		 *		"stripped"
559 		 *	- Symbol Table present with debugging
560 		 *	information (line number or debug section names,
561 		 *	or SHT_SUNW_DEBUGSTR or SHT_SUNW_DEBUG section
562 		 *	types) then report:
563 		 *		"not stripped"
564 		 *	- Symbol Table present with no debugging
565 		 *	information (line number or debug section names,
566 		 *	or SHT_SUNW_DEBUGSTR or SHT_SUNW_DEBUG section
567 		 *	types) then report:
568 		 *		"not stripped, no debugging information
569 		 *		available"
570 		 */
571 		if ((EI->stripped & E_NOSTRIP) == E_NOSTRIP)
572 			continue;
573 
574 		if (!(EI->stripped & E_SYMTAB) &&
575 		    (shdr->sh_type == SHT_SYMTAB)) {
576 			EI->stripped |= E_SYMTAB;
577 			continue;
578 		}
579 
580 		if (shdr->sh_name >= strtab_sz)
581 			shnam = NULL;
582 		else
583 			shnam = &strtab[shdr->sh_name];
584 
585 		if (!(EI->stripped & E_DBGINF) &&
586 		    ((shdr->sh_type == SHT_SUNW_DEBUG) ||
587 		    (shdr->sh_type == SHT_SUNW_DEBUGSTR) ||
588 		    (shnam != NULL && is_in_list(shnam)))) {
589 			EI->stripped |= E_DBGINF;
590 		}
591 	}
592 	free(strtab);
593 
594 	return (ELF_READ_OKAY);
595 }
596