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