1 /* $NetBSD: libelf_open.c,v 1.5 2024/03/03 17:37:34 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2006,2008-2011 Joseph Koshy 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #if HAVE_NBTOOL_CONFIG_H 30 # include "nbtool_config.h" 31 #endif 32 33 #include <sys/cdefs.h> 34 #include <sys/types.h> 35 #include <sys/stat.h> 36 37 #include <assert.h> 38 #include <errno.h> 39 #include <libelf.h> 40 #include <stdlib.h> 41 #include <unistd.h> 42 43 #include "_libelf.h" 44 45 #if ELFTC_HAVE_MMAP 46 #include <sys/mman.h> 47 #endif 48 49 __RCSID("$NetBSD: libelf_open.c,v 1.5 2024/03/03 17:37:34 christos Exp $"); 50 ELFTC_VCSID("Id: libelf_open.c 3977 2022-05-01 06:45:34Z jkoshy"); 51 52 #define _LIBELF_INITSIZE (64*1024) 53 54 /* 55 * Read from a device file, pipe or socket. 56 */ 57 static void * 58 _libelf_read_special_file(int fd, size_t *fsz) 59 { 60 ssize_t readsz; 61 size_t bufsz, datasz; 62 unsigned char *buf, *t; 63 64 datasz = 0; 65 readsz = 0; 66 bufsz = _LIBELF_INITSIZE; 67 if ((buf = malloc(bufsz)) == NULL) 68 goto resourceerror; 69 70 /* 71 * Read data from the file descriptor till we reach EOF, or 72 * till an error is encountered. 73 */ 74 do { 75 /* Check if we need to expand the data buffer. */ 76 if (datasz == bufsz) { 77 bufsz *= 2; 78 if ((t = realloc(buf, bufsz)) == NULL) 79 goto resourceerror; 80 buf = t; 81 } 82 83 do { 84 assert(bufsz - datasz > 0); 85 t = buf + datasz; 86 if ((readsz = read(fd, t, bufsz - datasz)) <= 0) 87 break; 88 datasz += (size_t) readsz; 89 } while (datasz < bufsz); 90 91 } while (readsz > 0); 92 93 if (readsz < 0) { 94 LIBELF_SET_ERROR(IO, errno); 95 goto error; 96 } 97 98 assert(readsz == 0); 99 100 /* 101 * Free up extra buffer space. 102 */ 103 if (bufsz > datasz) { 104 if (datasz > 0) { 105 if ((t = realloc(buf, datasz)) == NULL) 106 goto resourceerror; 107 buf = t; 108 } else { /* Zero bytes read. */ 109 LIBELF_SET_ERROR(ARGUMENT, 0); 110 free(buf); 111 buf = NULL; 112 } 113 } 114 115 *fsz = datasz; 116 return (buf); 117 118 resourceerror: 119 LIBELF_SET_ERROR(RESOURCE, 0); 120 error: 121 if (buf != NULL) 122 free(buf); 123 return (NULL); 124 } 125 126 /* 127 * Read the contents of the file referenced by the file descriptor 128 * 'fd'. 129 */ 130 131 Elf * 132 _libelf_open_object(int fd, Elf_Cmd c, int reporterror) 133 { 134 Elf *e; 135 void *m; 136 mode_t mode; 137 size_t fsize; 138 struct stat sb; 139 unsigned int flags; 140 141 assert(c == ELF_C_READ || c == ELF_C_RDWR || c == ELF_C_WRITE); 142 143 if (fstat(fd, &sb) < 0) { 144 LIBELF_SET_ERROR(IO, errno); 145 return (NULL); 146 } 147 148 mode = sb.st_mode; 149 fsize = (size_t) sb.st_size; 150 151 /* 152 * Reject unsupported file types. 153 */ 154 if (!S_ISREG(mode) && !S_ISCHR(mode) && !S_ISFIFO(mode) && 155 !S_ISSOCK(mode)) { 156 LIBELF_SET_ERROR(ARGUMENT, 0); 157 return (NULL); 158 } 159 160 /* 161 * For ELF_C_WRITE mode, allocate and return a descriptor. 162 */ 163 if (c == ELF_C_WRITE) { 164 if ((e = _libelf_allocate_elf()) != NULL) { 165 _libelf_init_elf(e, ELF_K_ELF); 166 e->e_byteorder = LIBELF_PRIVATE(byteorder); 167 e->e_fd = fd; 168 e->e_cmd = c; 169 if (!S_ISREG(mode)) 170 e->e_flags |= LIBELF_F_SPECIAL_FILE; 171 } 172 173 return (e); 174 } 175 176 177 /* 178 * ELF_C_READ and ELF_C_RDWR mode. 179 */ 180 m = NULL; 181 flags = 0; 182 if (S_ISREG(mode)) { 183 184 /* 185 * Reject zero length files. 186 */ 187 if (fsize == 0) { 188 LIBELF_SET_ERROR(ARGUMENT, 0); 189 return (NULL); 190 } 191 192 #if ELFTC_HAVE_MMAP 193 /* 194 * Always map regular files in with 'PROT_READ' 195 * permissions. 196 * 197 * For objects opened in ELF_C_RDWR mode, when 198 * elf_update(3) is called, we remove this mapping, 199 * write file data out using write(2), and map the new 200 * contents back. 201 */ 202 m = mmap(NULL, fsize, PROT_READ, MAP_PRIVATE, fd, (off_t) 0); 203 204 if (m == MAP_FAILED) 205 m = NULL; 206 else 207 flags = LIBELF_F_RAWFILE_MMAP; 208 #endif 209 210 /* 211 * Fallback to a read() if the call to mmap() failed, 212 * or if mmap() is not available. 213 */ 214 if (m == NULL) { 215 if ((m = malloc(fsize)) == NULL) { 216 LIBELF_SET_ERROR(RESOURCE, 0); 217 return (NULL); 218 } 219 220 if (read(fd, m, fsize) != (ssize_t) fsize) { 221 LIBELF_SET_ERROR(IO, errno); 222 free(m); 223 return (NULL); 224 } 225 226 flags = LIBELF_F_RAWFILE_MALLOC; 227 } 228 } else if ((m = _libelf_read_special_file(fd, &fsize)) != NULL) 229 flags = LIBELF_F_RAWFILE_MALLOC | LIBELF_F_SPECIAL_FILE; 230 else 231 return (NULL); 232 233 if ((e = _libelf_memory(m, fsize, reporterror)) == NULL) { 234 assert((flags & LIBELF_F_RAWFILE_MALLOC) || 235 (flags & LIBELF_F_RAWFILE_MMAP)); 236 if (flags & LIBELF_F_RAWFILE_MALLOC) 237 free(m); 238 #if ELFTC_HAVE_MMAP 239 else 240 (void) munmap(m, fsize); 241 #endif 242 return (NULL); 243 } 244 245 /* ar(1) archives aren't supported in RDWR mode. */ 246 if (c == ELF_C_RDWR && e->e_kind == ELF_K_AR) { 247 (void) elf_end(e); 248 LIBELF_SET_ERROR(ARGUMENT, 0); 249 return (NULL); 250 } 251 252 e->e_flags |= flags; 253 e->e_fd = fd; 254 e->e_cmd = c; 255 256 return (e); 257 } 258