xref: /freebsd/contrib/elftoolchain/libpe/libpe_dos.c (revision 0fe0fe112fa6cc220f14a1a9196b51fdc79edc72)
1*839529caSEd Maste /*-
2*839529caSEd Maste  * Copyright (c) 2015 Kai Wang
3*839529caSEd Maste  * All rights reserved.
4*839529caSEd Maste  *
5*839529caSEd Maste  * Redistribution and use in source and binary forms, with or without
6*839529caSEd Maste  * modification, are permitted provided that the following conditions
7*839529caSEd Maste  * are met:
8*839529caSEd Maste  * 1. Redistributions of source code must retain the above copyright
9*839529caSEd Maste  *    notice, this list of conditions and the following disclaimer.
10*839529caSEd Maste  * 2. Redistributions in binary form must reproduce the above copyright
11*839529caSEd Maste  *    notice, this list of conditions and the following disclaimer in the
12*839529caSEd Maste  *    documentation and/or other materials provided with the distribution.
13*839529caSEd Maste  *
14*839529caSEd Maste  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*839529caSEd Maste  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*839529caSEd Maste  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*839529caSEd Maste  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*839529caSEd Maste  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*839529caSEd Maste  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*839529caSEd Maste  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*839529caSEd Maste  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*839529caSEd Maste  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*839529caSEd Maste  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*839529caSEd Maste  * SUCH DAMAGE.
25*839529caSEd Maste  */
26*839529caSEd Maste 
27*839529caSEd Maste #include <sys/param.h>
28*839529caSEd Maste #include <sys/types.h>
29*839529caSEd Maste #include <assert.h>
30*839529caSEd Maste #include <errno.h>
31*839529caSEd Maste #include <stdlib.h>
32*839529caSEd Maste #include <string.h>
33*839529caSEd Maste #include <unistd.h>
34*839529caSEd Maste 
35*839529caSEd Maste #include "_libpe.h"
36*839529caSEd Maste 
37*839529caSEd Maste ELFTC_VCSID("$Id: libpe_dos.c 3312 2016-01-10 09:23:51Z kaiwang27 $");
38*839529caSEd Maste 
39*839529caSEd Maste int
libpe_parse_msdos_header(PE * pe,char * hdr)40*839529caSEd Maste libpe_parse_msdos_header(PE *pe, char *hdr)
41*839529caSEd Maste {
42*839529caSEd Maste 	PE_DosHdr *dh;
43*839529caSEd Maste 	char coff[sizeof(PE_CoffHdr)];
44*839529caSEd Maste 	uint32_t pe_magic;
45*839529caSEd Maste 	int i;
46*839529caSEd Maste 
47*839529caSEd Maste 	if ((pe->pe_stub = malloc(sizeof(PE_DosHdr))) == NULL) {
48*839529caSEd Maste 		errno = ENOMEM;
49*839529caSEd Maste 		return (-1);
50*839529caSEd Maste 	}
51*839529caSEd Maste 	memcpy(pe->pe_stub, hdr, sizeof(PE_DosHdr));
52*839529caSEd Maste 
53*839529caSEd Maste 	if ((dh = malloc(sizeof(*dh))) == NULL) {
54*839529caSEd Maste 		errno = ENOMEM;
55*839529caSEd Maste 		return (-1);
56*839529caSEd Maste 	}
57*839529caSEd Maste 	pe->pe_dh = dh;
58*839529caSEd Maste 
59*839529caSEd Maste 	/* Read the conventional MS-DOS EXE header. */
60*839529caSEd Maste 	memcpy(dh->dh_magic, hdr, 2);
61*839529caSEd Maste 	hdr += 2;
62*839529caSEd Maste 	PE_READ16(hdr, dh->dh_lastsize);
63*839529caSEd Maste 	PE_READ16(hdr, dh->dh_nblock);
64*839529caSEd Maste 	PE_READ16(hdr, dh->dh_nreloc);
65*839529caSEd Maste 	PE_READ16(hdr, dh->dh_hdrsize);
66*839529caSEd Maste 	PE_READ16(hdr, dh->dh_minalloc);
67*839529caSEd Maste 	PE_READ16(hdr, dh->dh_maxalloc);
68*839529caSEd Maste 	PE_READ16(hdr, dh->dh_ss);
69*839529caSEd Maste 	PE_READ16(hdr, dh->dh_sp);
70*839529caSEd Maste 	PE_READ16(hdr, dh->dh_checksum);
71*839529caSEd Maste 	PE_READ16(hdr, dh->dh_ip);
72*839529caSEd Maste 	PE_READ16(hdr, dh->dh_cs);
73*839529caSEd Maste 	PE_READ16(hdr, dh->dh_relocpos);
74*839529caSEd Maste 	PE_READ16(hdr, dh->dh_noverlay);
75*839529caSEd Maste 
76*839529caSEd Maste 	/* Do not continue if the EXE is not a PE/NE/... (new executable) */
77*839529caSEd Maste 	if (dh->dh_relocpos != 0x40) {
78*839529caSEd Maste 		pe->pe_flags |= LIBPE_F_BAD_DOS_HEADER;
79*839529caSEd Maste 		return (0);
80*839529caSEd Maste 	}
81*839529caSEd Maste 
82*839529caSEd Maste 	for (i = 0; i < 4; i++)
83*839529caSEd Maste 		PE_READ16(hdr, dh->dh_reserved1[i]);
84*839529caSEd Maste 	PE_READ16(hdr, dh->dh_oemid);
85*839529caSEd Maste 	PE_READ16(hdr, dh->dh_oeminfo);
86*839529caSEd Maste 	for (i = 0; i < 10; i++)
87*839529caSEd Maste 		PE_READ16(hdr, dh->dh_reserved2[i]);
88*839529caSEd Maste 	PE_READ32(hdr, dh->dh_lfanew);
89*839529caSEd Maste 
90*839529caSEd Maste 	/* Check if the e_lfanew pointer is valid. */
91*839529caSEd Maste 	if (dh->dh_lfanew > pe->pe_fsize - 4) {
92*839529caSEd Maste 		pe->pe_flags |= LIBPE_F_BAD_DOS_HEADER;
93*839529caSEd Maste 		return (0);
94*839529caSEd Maste 	}
95*839529caSEd Maste 
96*839529caSEd Maste 	if (dh->dh_lfanew < sizeof(PE_DosHdr) &&
97*839529caSEd Maste 	    (pe->pe_flags & LIBPE_F_SPECIAL_FILE)) {
98*839529caSEd Maste 		pe->pe_flags |= LIBPE_F_BAD_DOS_HEADER;
99*839529caSEd Maste 		return (0);
100*839529caSEd Maste 	}
101*839529caSEd Maste 
102*839529caSEd Maste 	if (dh->dh_lfanew > sizeof(PE_DosHdr)) {
103*839529caSEd Maste 		pe->pe_stub_ex = dh->dh_lfanew - sizeof(PE_DosHdr);
104*839529caSEd Maste 		if (pe->pe_flags & LIBPE_F_SPECIAL_FILE) {
105*839529caSEd Maste 			/* Read in DOS stub now. */
106*839529caSEd Maste 			if (libpe_read_msdos_stub(pe) < 0) {
107*839529caSEd Maste 				pe->pe_flags |= LIBPE_F_BAD_DOS_HEADER;
108*839529caSEd Maste 				return (0);
109*839529caSEd Maste 			}
110*839529caSEd Maste 		}
111*839529caSEd Maste 	}
112*839529caSEd Maste 
113*839529caSEd Maste 	if ((pe->pe_flags & LIBPE_F_SPECIAL_FILE) == 0) {
114*839529caSEd Maste 		/* Jump to the PE header. */
115*839529caSEd Maste 		if (lseek(pe->pe_fd, (off_t) dh->dh_lfanew, SEEK_SET) < 0) {
116*839529caSEd Maste 			pe->pe_flags |= LIBPE_F_BAD_PE_HEADER;
117*839529caSEd Maste 			return (0);
118*839529caSEd Maste 		}
119*839529caSEd Maste 	}
120*839529caSEd Maste 
121*839529caSEd Maste 	if (read(pe->pe_fd, &pe_magic, 4) != 4 ||
122*839529caSEd Maste 	    htole32(pe_magic) != PE_SIGNATURE) {
123*839529caSEd Maste 		pe->pe_flags |= LIBPE_F_BAD_PE_HEADER;
124*839529caSEd Maste 		return (0);
125*839529caSEd Maste 	}
126*839529caSEd Maste 
127*839529caSEd Maste 	if (read(pe->pe_fd, coff, sizeof(coff)) != (ssize_t) sizeof(coff)) {
128*839529caSEd Maste 		pe->pe_flags |= LIBPE_F_BAD_COFF_HEADER;
129*839529caSEd Maste 		return (0);
130*839529caSEd Maste 	}
131*839529caSEd Maste 
132*839529caSEd Maste 	return (libpe_parse_coff_header(pe, coff));
133*839529caSEd Maste }
134*839529caSEd Maste 
135*839529caSEd Maste int
libpe_read_msdos_stub(PE * pe)136*839529caSEd Maste libpe_read_msdos_stub(PE *pe)
137*839529caSEd Maste {
138*839529caSEd Maste 	void *m;
139*839529caSEd Maste 
140*839529caSEd Maste 	assert(pe->pe_stub_ex > 0 &&
141*839529caSEd Maste 	    (pe->pe_flags & LIBPE_F_LOAD_DOS_STUB) == 0);
142*839529caSEd Maste 
143*839529caSEd Maste 	if ((pe->pe_flags & LIBPE_F_SPECIAL_FILE) == 0) {
144*839529caSEd Maste 		if (lseek(pe->pe_fd, (off_t) sizeof(PE_DosHdr), SEEK_SET) <
145*839529caSEd Maste 		    0) {
146*839529caSEd Maste 			errno = EIO;
147*839529caSEd Maste 			goto fail;
148*839529caSEd Maste 		}
149*839529caSEd Maste 	}
150*839529caSEd Maste 
151*839529caSEd Maste 	if ((m = realloc(pe->pe_stub, sizeof(PE_DosHdr) + pe->pe_stub_ex)) ==
152*839529caSEd Maste 	    NULL) {
153*839529caSEd Maste 		errno = ENOMEM;
154*839529caSEd Maste 		goto fail;
155*839529caSEd Maste 	}
156*839529caSEd Maste 	pe->pe_stub = m;
157*839529caSEd Maste 
158*839529caSEd Maste 	if (read(pe->pe_fd, pe->pe_stub + sizeof(PE_DosHdr), pe->pe_stub_ex) !=
159*839529caSEd Maste 	    (ssize_t) pe->pe_stub_ex) {
160*839529caSEd Maste 		errno = EIO;
161*839529caSEd Maste 		goto fail;
162*839529caSEd Maste 	}
163*839529caSEd Maste 
164*839529caSEd Maste 	pe->pe_flags |= LIBPE_F_LOAD_DOS_STUB;
165*839529caSEd Maste 
166*839529caSEd Maste 	/* Search for the Rich header embedded just before the PE header. */
167*839529caSEd Maste 	(void) libpe_parse_rich_header(pe);
168*839529caSEd Maste 
169*839529caSEd Maste 	return (0);
170*839529caSEd Maste 
171*839529caSEd Maste fail:
172*839529caSEd Maste 	pe->pe_stub_ex = 0;
173*839529caSEd Maste 
174*839529caSEd Maste 	return (-1);
175*839529caSEd Maste }
176*839529caSEd Maste 
177*839529caSEd Maste /*
178*839529caSEd Maste  * The "standard" MS-DOS stub displaying "This program cannot be run in
179*839529caSEd Maste  * DOS mode".
180*839529caSEd Maste  */
181*839529caSEd Maste static const char msdos_stub[] = {
182*839529caSEd Maste     '\x0e','\x1f','\xba','\x0e','\x00','\xb4','\x09','\xcd',
183*839529caSEd Maste     '\x21','\xb8','\x01','\x4c','\xcd','\x21','\x54','\x68',
184*839529caSEd Maste     '\x69','\x73','\x20','\x70','\x72','\x6f','\x67','\x72',
185*839529caSEd Maste     '\x61','\x6d','\x20','\x63','\x61','\x6e','\x6e','\x6f',
186*839529caSEd Maste     '\x74','\x20','\x62','\x65','\x20','\x72','\x75','\x6e',
187*839529caSEd Maste     '\x20','\x69','\x6e','\x20','\x44','\x4f','\x53','\x20',
188*839529caSEd Maste     '\x6d','\x6f','\x64','\x65','\x2e','\x0d','\x0d','\x0a',
189*839529caSEd Maste     '\x24','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
190*839529caSEd Maste };
191*839529caSEd Maste 
192*839529caSEd Maste static void
init_dos_header(PE_DosHdr * dh)193*839529caSEd Maste init_dos_header(PE_DosHdr *dh)
194*839529caSEd Maste {
195*839529caSEd Maste 
196*839529caSEd Maste 	dh->dh_magic[0] = 'M';
197*839529caSEd Maste 	dh->dh_magic[1] = 'Z';
198*839529caSEd Maste 	dh->dh_lastsize = 144;
199*839529caSEd Maste 	dh->dh_nblock = 3;
200*839529caSEd Maste 	dh->dh_hdrsize = 4;
201*839529caSEd Maste 	dh->dh_maxalloc = 65535;
202*839529caSEd Maste 	dh->dh_sp = 184;
203*839529caSEd Maste 	dh->dh_relocpos = 0x40;
204*839529caSEd Maste 	dh->dh_lfanew = 0x80;
205*839529caSEd Maste }
206*839529caSEd Maste 
207*839529caSEd Maste off_t
libpe_write_msdos_stub(PE * pe,off_t off)208*839529caSEd Maste libpe_write_msdos_stub(PE *pe, off_t off)
209*839529caSEd Maste {
210*839529caSEd Maste 	PE_DosHdr *dh;
211*839529caSEd Maste 	char tmp[sizeof(PE_DosHdr)], *hdr;
212*839529caSEd Maste 	off_t d;
213*839529caSEd Maste 	int i, strip_rich;
214*839529caSEd Maste 
215*839529caSEd Maste 	strip_rich = 0;
216*839529caSEd Maste 
217*839529caSEd Maste 	if (pe->pe_cmd == PE_C_RDWR) {
218*839529caSEd Maste 		assert((pe->pe_flags & LIBPE_F_SPECIAL_FILE) == 0);
219*839529caSEd Maste 
220*839529caSEd Maste 		if (pe->pe_dh != NULL &&
221*839529caSEd Maste 		    (pe->pe_flags & PE_F_STRIP_DOS_STUB)) {
222*839529caSEd Maste 			/*
223*839529caSEd Maste 			 * If we strip MS-DOS stub, everything after it
224*839529caSEd Maste 			 * needs rewritten.
225*839529caSEd Maste 			 */
226*839529caSEd Maste 			pe->pe_flags |= LIBPE_F_BAD_PE_HEADER;
227*839529caSEd Maste 			goto done;
228*839529caSEd Maste 		}
229*839529caSEd Maste 
230*839529caSEd Maste 		/*
231*839529caSEd Maste 		 * lseek(2) to the PE signature if MS-DOS stub is not
232*839529caSEd Maste 		 * modified.
233*839529caSEd Maste 		 */
234*839529caSEd Maste 		if (pe->pe_dh != NULL &&
235*839529caSEd Maste 		    (pe->pe_flags & LIBPE_F_DIRTY_DOS_HEADER) == 0 &&
236*839529caSEd Maste 		    (pe->pe_flags & LIBPE_F_BAD_DOS_HEADER) == 0 &&
237*839529caSEd Maste 		    (pe->pe_flags & PE_F_STRIP_RICH_HEADER) == 0) {
238*839529caSEd Maste 			if (lseek(pe->pe_fd,
239*839529caSEd Maste 			    (off_t) (sizeof(PE_DosHdr) + pe->pe_stub_ex),
240*839529caSEd Maste 			    SEEK_CUR) < 0) {
241*839529caSEd Maste 				errno = EIO;
242*839529caSEd Maste 				return (-1);
243*839529caSEd Maste 			}
244*839529caSEd Maste 			off = sizeof(PE_DosHdr) + pe->pe_stub_ex;
245*839529caSEd Maste 			goto done;
246*839529caSEd Maste 		}
247*839529caSEd Maste 
248*839529caSEd Maste 		/* Check if we should strip the Rich header. */
249*839529caSEd Maste 		if (pe->pe_dh != NULL && pe->pe_stub_app == NULL &&
250*839529caSEd Maste 		    (pe->pe_flags & LIBPE_F_BAD_DOS_HEADER) == 0 &&
251*839529caSEd Maste 		    (pe->pe_flags & PE_F_STRIP_RICH_HEADER)) {
252*839529caSEd Maste 			if ((pe->pe_flags & LIBPE_F_LOAD_DOS_STUB) == 0) {
253*839529caSEd Maste 				(void) libpe_read_msdos_stub(pe);
254*839529caSEd Maste 				if (lseek(pe->pe_fd, off, SEEK_SET) < 0) {
255*839529caSEd Maste 					errno = EIO;
256*839529caSEd Maste 					return (-1);
257*839529caSEd Maste 				}
258*839529caSEd Maste 			}
259*839529caSEd Maste 			if (pe->pe_rh != NULL) {
260*839529caSEd Maste 				strip_rich = 1;
261*839529caSEd Maste 				pe->pe_flags |= LIBPE_F_DIRTY_DOS_HEADER;
262*839529caSEd Maste 			}
263*839529caSEd Maste 		}
264*839529caSEd Maste 
265*839529caSEd Maste 		/*
266*839529caSEd Maste 		 * If length of MS-DOS stub will change, Mark the PE
267*839529caSEd Maste 		 * signature is broken so that the PE signature and the
268*839529caSEd Maste 		 * headers follow it will be rewritten.
269*839529caSEd Maste 		 *
270*839529caSEd Maste 		 * The sections should be loaded now since the stub might
271*839529caSEd Maste 		 * overwrite the section data.
272*839529caSEd Maste 		 */
273*839529caSEd Maste 		if ((pe->pe_flags & LIBPE_F_BAD_DOS_HEADER) ||
274*839529caSEd Maste 		    (pe->pe_stub_app != NULL && pe->pe_stub_app_sz !=
275*839529caSEd Maste 			sizeof(PE_DosHdr) + pe->pe_stub_ex) || strip_rich) {
276*839529caSEd Maste 			if (libpe_load_all_sections(pe) < 0)
277*839529caSEd Maste 				return (-1);
278*839529caSEd Maste 			if (lseek(pe->pe_fd, off, SEEK_SET) < 0) {
279*839529caSEd Maste 				errno = EIO;
280*839529caSEd Maste 				return (-1);
281*839529caSEd Maste 			}
282*839529caSEd Maste 			pe->pe_flags |= LIBPE_F_BAD_PE_HEADER;
283*839529caSEd Maste 		}
284*839529caSEd Maste 	}
285*839529caSEd Maste 
286*839529caSEd Maste 	if (pe->pe_flags & PE_F_STRIP_DOS_STUB)
287*839529caSEd Maste 		goto done;
288*839529caSEd Maste 
289*839529caSEd Maste 	/* Always use application supplied MS-DOS stub, if exists. */
290*839529caSEd Maste 	if (pe->pe_stub_app != NULL && pe->pe_stub_app_sz > 0) {
291*839529caSEd Maste 		if (write(pe->pe_fd, pe->pe_stub_app, pe->pe_stub_app_sz) !=
292*839529caSEd Maste 		    (ssize_t) pe->pe_stub_app_sz) {
293*839529caSEd Maste 			errno = EIO;
294*839529caSEd Maste 			return (-1);
295*839529caSEd Maste 		}
296*839529caSEd Maste 		off = pe->pe_stub_app_sz;
297*839529caSEd Maste 		goto done;
298*839529caSEd Maste 	}
299*839529caSEd Maste 
300*839529caSEd Maste 	/*
301*839529caSEd Maste 	 * Write MS-DOS header.
302*839529caSEd Maste 	 */
303*839529caSEd Maste 
304*839529caSEd Maste 	if (pe->pe_dh == NULL) {
305*839529caSEd Maste 		if ((dh = calloc(1, sizeof(PE_DosHdr))) == NULL) {
306*839529caSEd Maste 			errno = ENOMEM;
307*839529caSEd Maste 			return (-1);
308*839529caSEd Maste 		}
309*839529caSEd Maste 		pe->pe_dh = dh;
310*839529caSEd Maste 
311*839529caSEd Maste 		init_dos_header(dh);
312*839529caSEd Maste 
313*839529caSEd Maste 		pe->pe_flags |= LIBPE_F_DIRTY_DOS_HEADER;
314*839529caSEd Maste 	} else
315*839529caSEd Maste 		dh = pe->pe_dh;
316*839529caSEd Maste 
317*839529caSEd Maste 	if (pe->pe_flags & LIBPE_F_BAD_DOS_HEADER)
318*839529caSEd Maste 		init_dos_header(dh);
319*839529caSEd Maste 
320*839529caSEd Maste 	if (strip_rich) {
321*839529caSEd Maste 		d = pe->pe_rh_start - pe->pe_stub;
322*839529caSEd Maste 		dh->dh_lfanew = roundup(d, 8);
323*839529caSEd Maste 	}
324*839529caSEd Maste 
325*839529caSEd Maste 	if ((pe->pe_flags & LIBPE_F_DIRTY_DOS_HEADER) ||
326*839529caSEd Maste 	    (pe->pe_flags & LIBPE_F_BAD_DOS_HEADER)) {
327*839529caSEd Maste 		memcpy(tmp, dh->dh_magic, 2);
328*839529caSEd Maste 		hdr = tmp + 2;
329*839529caSEd Maste 		PE_WRITE16(hdr, dh->dh_lastsize);
330*839529caSEd Maste 		PE_WRITE16(hdr, dh->dh_nblock);
331*839529caSEd Maste 		PE_WRITE16(hdr, dh->dh_nreloc);
332*839529caSEd Maste 		PE_WRITE16(hdr, dh->dh_hdrsize);
333*839529caSEd Maste 		PE_WRITE16(hdr, dh->dh_minalloc);
334*839529caSEd Maste 		PE_WRITE16(hdr, dh->dh_maxalloc);
335*839529caSEd Maste 		PE_WRITE16(hdr, dh->dh_ss);
336*839529caSEd Maste 		PE_WRITE16(hdr, dh->dh_sp);
337*839529caSEd Maste 		PE_WRITE16(hdr, dh->dh_checksum);
338*839529caSEd Maste 		PE_WRITE16(hdr, dh->dh_ip);
339*839529caSEd Maste 		PE_WRITE16(hdr, dh->dh_cs);
340*839529caSEd Maste 		PE_WRITE16(hdr, dh->dh_relocpos);
341*839529caSEd Maste 		PE_WRITE16(hdr, dh->dh_noverlay);
342*839529caSEd Maste 		for (i = 0; i < 4; i++)
343*839529caSEd Maste 			PE_WRITE16(hdr, dh->dh_reserved1[i]);
344*839529caSEd Maste 		PE_WRITE16(hdr, dh->dh_oemid);
345*839529caSEd Maste 		PE_WRITE16(hdr, dh->dh_oeminfo);
346*839529caSEd Maste 		for (i = 0; i < 10; i++)
347*839529caSEd Maste 			PE_WRITE16(hdr, dh->dh_reserved2[i]);
348*839529caSEd Maste 		PE_WRITE32(hdr, dh->dh_lfanew);
349*839529caSEd Maste 
350*839529caSEd Maste 		if (write(pe->pe_fd, tmp, sizeof(tmp)) !=
351*839529caSEd Maste 		    (ssize_t) sizeof(tmp)) {
352*839529caSEd Maste 			errno = EIO;
353*839529caSEd Maste 			return (-1);
354*839529caSEd Maste 		}
355*839529caSEd Maste 	} else {
356*839529caSEd Maste 		assert((pe->pe_flags & LIBPE_F_SPECIAL_FILE) == 0);
357*839529caSEd Maste 		if (lseek(pe->pe_fd, (off_t) sizeof(PE_DosHdr), SEEK_CUR) <
358*839529caSEd Maste 		    0) {
359*839529caSEd Maste 			errno = EIO;
360*839529caSEd Maste 			return (-1);
361*839529caSEd Maste 		}
362*839529caSEd Maste 	}
363*839529caSEd Maste 
364*839529caSEd Maste 	off = sizeof(PE_DosHdr);
365*839529caSEd Maste 
366*839529caSEd Maste 	/*
367*839529caSEd Maste 	 * Write the MS-DOS stub.
368*839529caSEd Maste 	 */
369*839529caSEd Maste 
370*839529caSEd Maste 	if (strip_rich) {
371*839529caSEd Maste 		assert((pe->pe_flags & LIBPE_F_SPECIAL_FILE) == 0);
372*839529caSEd Maste 		assert(pe->pe_stub != NULL && pe->pe_rh_start != NULL);
373*839529caSEd Maste 		d = pe->pe_rh_start - pe->pe_stub;
374*839529caSEd Maste 		if (lseek(pe->pe_fd, d, SEEK_SET) < 0) {
375*839529caSEd Maste 			errno = EIO;
376*839529caSEd Maste 			return (-1);
377*839529caSEd Maste 		}
378*839529caSEd Maste 		off = d;
379*839529caSEd Maste 		goto done;
380*839529caSEd Maste 	}
381*839529caSEd Maste 
382*839529caSEd Maste 	if (pe->pe_cmd == PE_C_RDWR) {
383*839529caSEd Maste 		if (lseek(pe->pe_fd, (off_t) pe->pe_stub_ex, SEEK_CUR) < 0) {
384*839529caSEd Maste 			errno = EIO;
385*839529caSEd Maste 			return (-1);
386*839529caSEd Maste 		}
387*839529caSEd Maste 		off += pe->pe_stub_ex;
388*839529caSEd Maste 		goto done;
389*839529caSEd Maste 	}
390*839529caSEd Maste 
391*839529caSEd Maste 	if (write(pe->pe_fd, msdos_stub, sizeof(msdos_stub)) !=
392*839529caSEd Maste 	    (ssize_t) sizeof(msdos_stub)) {
393*839529caSEd Maste 		errno = EIO;
394*839529caSEd Maste 		return (-1);
395*839529caSEd Maste 	}
396*839529caSEd Maste 	off += sizeof(msdos_stub);
397*839529caSEd Maste 
398*839529caSEd Maste done:
399*839529caSEd Maste 	pe->pe_flags &= ~LIBPE_F_DIRTY_DOS_HEADER;
400*839529caSEd Maste 	pe->pe_flags &= ~LIBPE_F_BAD_DOS_HEADER;
401*839529caSEd Maste 
402*839529caSEd Maste 	return (off);
403*839529caSEd Maste }
404