1 /*- 2 * Copyright (c) 2006,2008-2011 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/types.h> 28 #include <sys/stat.h> 29 30 #include <assert.h> 31 #include <errno.h> 32 #include <libelf.h> 33 #include <stdlib.h> 34 #include <unistd.h> 35 36 #include "_libelf.h" 37 38 #if ELFTC_HAVE_MMAP 39 #include <sys/mman.h> 40 #endif 41 42 ELFTC_VCSID("$Id: libelf_open.c 3007 2014-03-22 08:10:14Z jkoshy $"); 43 44 #define _LIBELF_INITSIZE (64*1024) 45 46 /* 47 * Read from a device file, pipe or socket. 48 */ 49 static void * 50 _libelf_read_special_file(int fd, size_t *fsz) 51 { 52 ssize_t readsz; 53 size_t bufsz, datasz; 54 unsigned char *buf, *t; 55 56 datasz = 0; 57 readsz = 0; 58 bufsz = _LIBELF_INITSIZE; 59 if ((buf = malloc(bufsz)) == NULL) 60 goto resourceerror; 61 62 /* 63 * Read data from the file descriptor till we reach EOF, or 64 * till an error is encountered. 65 */ 66 do { 67 /* Check if we need to expand the data buffer. */ 68 if (datasz == bufsz) { 69 bufsz *= 2; 70 if ((t = realloc(buf, bufsz)) == NULL) 71 goto resourceerror; 72 buf = t; 73 } 74 75 do { 76 assert(bufsz - datasz > 0); 77 t = buf + datasz; 78 if ((readsz = read(fd, t, bufsz - datasz)) <= 0) 79 break; 80 datasz += (size_t) readsz; 81 } while (datasz < bufsz); 82 83 } while (readsz > 0); 84 85 if (readsz < 0) { 86 LIBELF_SET_ERROR(IO, errno); 87 goto error; 88 } 89 90 assert(readsz == 0); 91 92 /* 93 * Free up extra buffer space. 94 */ 95 if (bufsz > datasz) { 96 if (datasz > 0) { 97 if ((t = realloc(buf, datasz)) == NULL) 98 goto resourceerror; 99 buf = t; 100 } else { /* Zero bytes read. */ 101 LIBELF_SET_ERROR(ARGUMENT, 0); 102 free(buf); 103 buf = NULL; 104 } 105 } 106 107 *fsz = datasz; 108 return (buf); 109 110 resourceerror: 111 LIBELF_SET_ERROR(RESOURCE, 0); 112 error: 113 if (buf != NULL) 114 free(buf); 115 return (NULL); 116 } 117 118 /* 119 * Read the contents of the file referenced by the file descriptor 120 * 'fd'. 121 */ 122 123 Elf * 124 _libelf_open_object(int fd, Elf_Cmd c, int reporterror) 125 { 126 Elf *e; 127 void *m; 128 mode_t mode; 129 size_t fsize; 130 struct stat sb; 131 unsigned int flags; 132 133 assert(c == ELF_C_READ || c == ELF_C_RDWR || c == ELF_C_WRITE); 134 135 if (fstat(fd, &sb) < 0) { 136 LIBELF_SET_ERROR(IO, errno); 137 return (NULL); 138 } 139 140 mode = sb.st_mode; 141 fsize = (size_t) sb.st_size; 142 143 /* 144 * Reject unsupported file types. 145 */ 146 if (!S_ISREG(mode) && !S_ISCHR(mode) && !S_ISFIFO(mode) && 147 !S_ISSOCK(mode)) { 148 LIBELF_SET_ERROR(ARGUMENT, 0); 149 return (NULL); 150 } 151 152 /* 153 * For ELF_C_WRITE mode, allocate and return a descriptor. 154 */ 155 if (c == ELF_C_WRITE) { 156 if ((e = _libelf_allocate_elf()) != NULL) { 157 _libelf_init_elf(e, ELF_K_ELF); 158 e->e_byteorder = LIBELF_PRIVATE(byteorder); 159 e->e_fd = fd; 160 e->e_cmd = c; 161 if (!S_ISREG(mode)) 162 e->e_flags |= LIBELF_F_SPECIAL_FILE; 163 } 164 165 return (e); 166 } 167 168 169 /* 170 * ELF_C_READ and ELF_C_RDWR mode. 171 */ 172 m = NULL; 173 flags = 0; 174 if (S_ISREG(mode)) { 175 176 /* 177 * Reject zero length files. 178 */ 179 if (fsize == 0) { 180 LIBELF_SET_ERROR(ARGUMENT, 0); 181 return (NULL); 182 } 183 184 #if ELFTC_HAVE_MMAP 185 /* 186 * Always map regular files in with 'PROT_READ' 187 * permissions. 188 * 189 * For objects opened in ELF_C_RDWR mode, when 190 * elf_update(3) is called, we remove this mapping, 191 * write file data out using write(2), and map the new 192 * contents back. 193 */ 194 m = mmap(NULL, fsize, PROT_READ, MAP_PRIVATE, fd, (off_t) 0); 195 196 if (m == MAP_FAILED) 197 m = NULL; 198 else 199 flags = LIBELF_F_RAWFILE_MMAP; 200 #endif 201 202 /* 203 * Fallback to a read() if the call to mmap() failed, 204 * or if mmap() is not available. 205 */ 206 if (m == NULL) { 207 if ((m = malloc(fsize)) == NULL) { 208 LIBELF_SET_ERROR(RESOURCE, 0); 209 return (NULL); 210 } 211 212 if (read(fd, m, fsize) != (ssize_t) fsize) { 213 LIBELF_SET_ERROR(IO, errno); 214 free(m); 215 return (NULL); 216 } 217 218 flags = LIBELF_F_RAWFILE_MALLOC; 219 } 220 } else if ((m = _libelf_read_special_file(fd, &fsize)) != NULL) 221 flags = LIBELF_F_RAWFILE_MALLOC | LIBELF_F_SPECIAL_FILE; 222 else 223 return (NULL); 224 225 if ((e = _libelf_memory(m, fsize, reporterror)) == NULL) { 226 assert((flags & LIBELF_F_RAWFILE_MALLOC) || 227 (flags & LIBELF_F_RAWFILE_MMAP)); 228 if (flags & LIBELF_F_RAWFILE_MALLOC) 229 free(m); 230 #if ELFTC_HAVE_MMAP 231 else 232 (void) munmap(m, fsize); 233 #endif 234 return (NULL); 235 } 236 237 /* ar(1) archives aren't supported in RDWR mode. */ 238 if (c == ELF_C_RDWR && e->e_kind == ELF_K_AR) { 239 (void) elf_end(e); 240 LIBELF_SET_ERROR(ARGUMENT, 0); 241 return (NULL); 242 } 243 244 e->e_flags |= flags; 245 e->e_fd = fd; 246 e->e_cmd = c; 247 248 return (e); 249 } 250