12de3b87aSKai Wang /*-
22de3b87aSKai Wang * Copyright (c) 2006,2008-2011 Joseph Koshy
32de3b87aSKai Wang * All rights reserved.
42de3b87aSKai Wang *
52de3b87aSKai Wang * Redistribution and use in source and binary forms, with or without
62de3b87aSKai Wang * modification, are permitted provided that the following conditions
72de3b87aSKai Wang * are met:
82de3b87aSKai Wang * 1. Redistributions of source code must retain the above copyright
92de3b87aSKai Wang * notice, this list of conditions and the following disclaimer.
102de3b87aSKai Wang * 2. Redistributions in binary form must reproduce the above copyright
112de3b87aSKai Wang * notice, this list of conditions and the following disclaimer in the
122de3b87aSKai Wang * documentation and/or other materials provided with the distribution.
132de3b87aSKai Wang *
142de3b87aSKai Wang * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
152de3b87aSKai Wang * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
162de3b87aSKai Wang * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
172de3b87aSKai Wang * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
182de3b87aSKai Wang * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
192de3b87aSKai Wang * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
202de3b87aSKai Wang * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
212de3b87aSKai Wang * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
222de3b87aSKai Wang * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
232de3b87aSKai Wang * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
242de3b87aSKai Wang * SUCH DAMAGE.
252de3b87aSKai Wang */
262de3b87aSKai Wang
272de3b87aSKai Wang #include <sys/types.h>
282de3b87aSKai Wang #include <sys/stat.h>
292de3b87aSKai Wang
302de3b87aSKai Wang #include <assert.h>
312de3b87aSKai Wang #include <errno.h>
322de3b87aSKai Wang #include <libelf.h>
332de3b87aSKai Wang #include <stdlib.h>
342de3b87aSKai Wang #include <unistd.h>
352de3b87aSKai Wang
362de3b87aSKai Wang #include "_libelf.h"
372de3b87aSKai Wang
382de3b87aSKai Wang #if ELFTC_HAVE_MMAP
392de3b87aSKai Wang #include <sys/mman.h>
402de3b87aSKai Wang #endif
412de3b87aSKai Wang
42*cf781b2eSEd Maste ELFTC_VCSID("$Id: libelf_open.c 3007 2014-03-22 08:10:14Z jkoshy $");
432de3b87aSKai Wang
442de3b87aSKai Wang #define _LIBELF_INITSIZE (64*1024)
452de3b87aSKai Wang
462de3b87aSKai Wang /*
472de3b87aSKai Wang * Read from a device file, pipe or socket.
482de3b87aSKai Wang */
492de3b87aSKai Wang static void *
_libelf_read_special_file(int fd,size_t * fsz)502de3b87aSKai Wang _libelf_read_special_file(int fd, size_t *fsz)
512de3b87aSKai Wang {
522de3b87aSKai Wang ssize_t readsz;
532de3b87aSKai Wang size_t bufsz, datasz;
542de3b87aSKai Wang unsigned char *buf, *t;
552de3b87aSKai Wang
562de3b87aSKai Wang datasz = 0;
572de3b87aSKai Wang readsz = 0;
582de3b87aSKai Wang bufsz = _LIBELF_INITSIZE;
592de3b87aSKai Wang if ((buf = malloc(bufsz)) == NULL)
602de3b87aSKai Wang goto resourceerror;
612de3b87aSKai Wang
622de3b87aSKai Wang /*
632de3b87aSKai Wang * Read data from the file descriptor till we reach EOF, or
642de3b87aSKai Wang * till an error is encountered.
652de3b87aSKai Wang */
662de3b87aSKai Wang do {
672de3b87aSKai Wang /* Check if we need to expand the data buffer. */
682de3b87aSKai Wang if (datasz == bufsz) {
692de3b87aSKai Wang bufsz *= 2;
702de3b87aSKai Wang if ((t = realloc(buf, bufsz)) == NULL)
712de3b87aSKai Wang goto resourceerror;
722de3b87aSKai Wang buf = t;
732de3b87aSKai Wang }
742de3b87aSKai Wang
752de3b87aSKai Wang do {
76*cf781b2eSEd Maste assert(bufsz - datasz > 0);
772de3b87aSKai Wang t = buf + datasz;
78*cf781b2eSEd Maste if ((readsz = read(fd, t, bufsz - datasz)) <= 0)
792de3b87aSKai Wang break;
80*cf781b2eSEd Maste datasz += (size_t) readsz;
812de3b87aSKai Wang } while (datasz < bufsz);
822de3b87aSKai Wang
832de3b87aSKai Wang } while (readsz > 0);
842de3b87aSKai Wang
852de3b87aSKai Wang if (readsz < 0) {
862de3b87aSKai Wang LIBELF_SET_ERROR(IO, errno);
872de3b87aSKai Wang goto error;
882de3b87aSKai Wang }
892de3b87aSKai Wang
902de3b87aSKai Wang assert(readsz == 0);
912de3b87aSKai Wang
922de3b87aSKai Wang /*
932de3b87aSKai Wang * Free up extra buffer space.
942de3b87aSKai Wang */
952de3b87aSKai Wang if (bufsz > datasz) {
962de3b87aSKai Wang if (datasz > 0) {
972de3b87aSKai Wang if ((t = realloc(buf, datasz)) == NULL)
982de3b87aSKai Wang goto resourceerror;
992de3b87aSKai Wang buf = t;
1002de3b87aSKai Wang } else { /* Zero bytes read. */
1012de3b87aSKai Wang LIBELF_SET_ERROR(ARGUMENT, 0);
1022de3b87aSKai Wang free(buf);
1032de3b87aSKai Wang buf = NULL;
1042de3b87aSKai Wang }
1052de3b87aSKai Wang }
1062de3b87aSKai Wang
1072de3b87aSKai Wang *fsz = datasz;
1082de3b87aSKai Wang return (buf);
1092de3b87aSKai Wang
1102de3b87aSKai Wang resourceerror:
1112de3b87aSKai Wang LIBELF_SET_ERROR(RESOURCE, 0);
1122de3b87aSKai Wang error:
1132de3b87aSKai Wang if (buf != NULL)
1142de3b87aSKai Wang free(buf);
1152de3b87aSKai Wang return (NULL);
1162de3b87aSKai Wang }
1172de3b87aSKai Wang
1182de3b87aSKai Wang /*
1192de3b87aSKai Wang * Read the contents of the file referenced by the file descriptor
1202de3b87aSKai Wang * 'fd'.
1212de3b87aSKai Wang */
1222de3b87aSKai Wang
1232de3b87aSKai Wang Elf *
_libelf_open_object(int fd,Elf_Cmd c,int reporterror)1242de3b87aSKai Wang _libelf_open_object(int fd, Elf_Cmd c, int reporterror)
1252de3b87aSKai Wang {
1262de3b87aSKai Wang Elf *e;
1272de3b87aSKai Wang void *m;
1282de3b87aSKai Wang mode_t mode;
1292de3b87aSKai Wang size_t fsize;
1302de3b87aSKai Wang struct stat sb;
1312de3b87aSKai Wang unsigned int flags;
1322de3b87aSKai Wang
1332de3b87aSKai Wang assert(c == ELF_C_READ || c == ELF_C_RDWR || c == ELF_C_WRITE);
1342de3b87aSKai Wang
1352de3b87aSKai Wang if (fstat(fd, &sb) < 0) {
1362de3b87aSKai Wang LIBELF_SET_ERROR(IO, errno);
1372de3b87aSKai Wang return (NULL);
1382de3b87aSKai Wang }
1392de3b87aSKai Wang
1402de3b87aSKai Wang mode = sb.st_mode;
1412de3b87aSKai Wang fsize = (size_t) sb.st_size;
1422de3b87aSKai Wang
1432de3b87aSKai Wang /*
1442de3b87aSKai Wang * Reject unsupported file types.
1452de3b87aSKai Wang */
1462de3b87aSKai Wang if (!S_ISREG(mode) && !S_ISCHR(mode) && !S_ISFIFO(mode) &&
1472de3b87aSKai Wang !S_ISSOCK(mode)) {
1482de3b87aSKai Wang LIBELF_SET_ERROR(ARGUMENT, 0);
1492de3b87aSKai Wang return (NULL);
1502de3b87aSKai Wang }
1512de3b87aSKai Wang
1522de3b87aSKai Wang /*
1532de3b87aSKai Wang * For ELF_C_WRITE mode, allocate and return a descriptor.
1542de3b87aSKai Wang */
1552de3b87aSKai Wang if (c == ELF_C_WRITE) {
1562de3b87aSKai Wang if ((e = _libelf_allocate_elf()) != NULL) {
1572de3b87aSKai Wang _libelf_init_elf(e, ELF_K_ELF);
1582de3b87aSKai Wang e->e_byteorder = LIBELF_PRIVATE(byteorder);
1592de3b87aSKai Wang e->e_fd = fd;
1602de3b87aSKai Wang e->e_cmd = c;
1612de3b87aSKai Wang if (!S_ISREG(mode))
1622de3b87aSKai Wang e->e_flags |= LIBELF_F_SPECIAL_FILE;
1632de3b87aSKai Wang }
1642de3b87aSKai Wang
1652de3b87aSKai Wang return (e);
1662de3b87aSKai Wang }
1672de3b87aSKai Wang
1682de3b87aSKai Wang
1692de3b87aSKai Wang /*
1702de3b87aSKai Wang * ELF_C_READ and ELF_C_RDWR mode.
1712de3b87aSKai Wang */
1722de3b87aSKai Wang m = NULL;
1732de3b87aSKai Wang flags = 0;
1742de3b87aSKai Wang if (S_ISREG(mode)) {
1752de3b87aSKai Wang
1762de3b87aSKai Wang /*
1772de3b87aSKai Wang * Reject zero length files.
1782de3b87aSKai Wang */
1792de3b87aSKai Wang if (fsize == 0) {
1802de3b87aSKai Wang LIBELF_SET_ERROR(ARGUMENT, 0);
1812de3b87aSKai Wang return (NULL);
1822de3b87aSKai Wang }
1832de3b87aSKai Wang
1842de3b87aSKai Wang #if ELFTC_HAVE_MMAP
1852de3b87aSKai Wang /*
1862de3b87aSKai Wang * Always map regular files in with 'PROT_READ'
1872de3b87aSKai Wang * permissions.
1882de3b87aSKai Wang *
1892de3b87aSKai Wang * For objects opened in ELF_C_RDWR mode, when
1902de3b87aSKai Wang * elf_update(3) is called, we remove this mapping,
1912de3b87aSKai Wang * write file data out using write(2), and map the new
1922de3b87aSKai Wang * contents back.
1932de3b87aSKai Wang */
1942de3b87aSKai Wang m = mmap(NULL, fsize, PROT_READ, MAP_PRIVATE, fd, (off_t) 0);
1952de3b87aSKai Wang
1962de3b87aSKai Wang if (m == MAP_FAILED)
1972de3b87aSKai Wang m = NULL;
1982de3b87aSKai Wang else
1992de3b87aSKai Wang flags = LIBELF_F_RAWFILE_MMAP;
2002de3b87aSKai Wang #endif
2012de3b87aSKai Wang
2022de3b87aSKai Wang /*
2032de3b87aSKai Wang * Fallback to a read() if the call to mmap() failed,
2042de3b87aSKai Wang * or if mmap() is not available.
2052de3b87aSKai Wang */
2062de3b87aSKai Wang if (m == NULL) {
2072de3b87aSKai Wang if ((m = malloc(fsize)) == NULL) {
2082de3b87aSKai Wang LIBELF_SET_ERROR(RESOURCE, 0);
2092de3b87aSKai Wang return (NULL);
2102de3b87aSKai Wang }
2112de3b87aSKai Wang
2122de3b87aSKai Wang if (read(fd, m, fsize) != (ssize_t) fsize) {
2132de3b87aSKai Wang LIBELF_SET_ERROR(IO, errno);
2142de3b87aSKai Wang free(m);
2152de3b87aSKai Wang return (NULL);
2162de3b87aSKai Wang }
2172de3b87aSKai Wang
2182de3b87aSKai Wang flags = LIBELF_F_RAWFILE_MALLOC;
2192de3b87aSKai Wang }
2202de3b87aSKai Wang } else if ((m = _libelf_read_special_file(fd, &fsize)) != NULL)
2212de3b87aSKai Wang flags = LIBELF_F_RAWFILE_MALLOC | LIBELF_F_SPECIAL_FILE;
2222de3b87aSKai Wang else
2232de3b87aSKai Wang return (NULL);
2242de3b87aSKai Wang
2252de3b87aSKai Wang if ((e = _libelf_memory(m, fsize, reporterror)) == NULL) {
2262de3b87aSKai Wang assert((flags & LIBELF_F_RAWFILE_MALLOC) ||
2272de3b87aSKai Wang (flags & LIBELF_F_RAWFILE_MMAP));
2282de3b87aSKai Wang if (flags & LIBELF_F_RAWFILE_MALLOC)
2292de3b87aSKai Wang free(m);
2302de3b87aSKai Wang #if ELFTC_HAVE_MMAP
2312de3b87aSKai Wang else
2322de3b87aSKai Wang (void) munmap(m, fsize);
2332de3b87aSKai Wang #endif
2342de3b87aSKai Wang return (NULL);
2352de3b87aSKai Wang }
2362de3b87aSKai Wang
2372de3b87aSKai Wang /* ar(1) archives aren't supported in RDWR mode. */
2382de3b87aSKai Wang if (c == ELF_C_RDWR && e->e_kind == ELF_K_AR) {
2392de3b87aSKai Wang (void) elf_end(e);
2402de3b87aSKai Wang LIBELF_SET_ERROR(ARGUMENT, 0);
2412de3b87aSKai Wang return (NULL);
2422de3b87aSKai Wang }
2432de3b87aSKai Wang
2442de3b87aSKai Wang e->e_flags |= flags;
2452de3b87aSKai Wang e->e_fd = fd;
2462de3b87aSKai Wang e->e_cmd = c;
2472de3b87aSKai Wang
2482de3b87aSKai Wang return (e);
2492de3b87aSKai Wang }
250