Deleted Added
full compact
1/*
2 * Parts of this file are not covered by:
3 * ----------------------------------------------------------------------------
4 * "THE BEER-WARE LICENSE" (Revision 42):
5 * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
6 * can do whatever you want with this stuff. If we meet some day, and you think
7 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
8 * ----------------------------------------------------------------------------
9 *
10 * $Id: imgact_gzip.c,v 1.4 1994/10/04 06:51:42 phk Exp $
11 *
12 * This module handles execution of a.out files which have been run through
13 * "gzip -9".
14 *
15 * For now you need to use exactly this command to compress the binaries:
16 *
17 * gzip -9 -v < /bin/sh > /tmp/sh
18 *
19 * TODO:
20 * text-segments should be made R/O after being filled
21 * is the vm-stuff safe ?
22 * should handle the entire header of gzip'ed stuff.
23 * inflate isn't quite reentrant yet...
24 * error-handling is a mess...
25 * so is the rest...
26 * tidy up unnecesary includes
27 */
28
29#include <sys/param.h>
30#include <sys/systm.h>
31#include <sys/resourcevar.h>
32#include <sys/exec.h>
33#include <sys/inflate.h>
34#include <sys/mman.h>
35#include <sys/malloc.h>
36#include <sys/imgact.h>
37#include <sys/imgact_aout.h>
38#include <sys/kernel.h>
39#include <sys/sysent.h>
40
41#include <vm/vm.h>
42#include <vm/vm_kern.h>
43
44extern struct sysentvec aout_sysvec;
45
46int
47exec_gzip_imgact(iparams)
48 struct image_params *iparams;
49{
50 int error,error2=0;
51 u_char *p = (u_char *) iparams->image_header;
52 struct gzip *gz;
53 struct gz_global gz_glbl;
54
55 /* If these four are not OK, it isn't a gzip file */
56 if (p[0] != 0x1f) return -1; /* 0 Simply magic */
57 if (p[1] != 0x8b) return -1; /* 1 Simply magic */
58 if (p[2] != 0x08) return -1; /* 2 Compression method */
59 if (p[9] != 0x03) return -1; /* 9 OS compressed on */
60
61 /* If this one contains anything but a comment or a filename
62 * marker, we don't want to chew on it
63 */
64 if (p[3] & ~(0x18)) return ENOEXEC; /* 3 Flags */
65
66 /* These are of no use to us */
67 /* 4-7 Timestamp */
68 /* 8 Extra flags */
69
70 gz = malloc(sizeof *gz,M_GZIP,M_NOWAIT);
71 if (!gz)
72 return ENOMEM;
73 bzero(gz,sizeof *gz); /* waste of time ? */
74
75 gz->gz_slide = malloc(WSIZE,M_TEMP,M_NOWAIT);
76 if (!gz->gz_slide) {
77 free(gz,M_GZIP);
78 return ENOMEM;
79 }
80
81 gz->ip = iparams;
82 gz->error = ENOEXEC;
83 gz->idx = 10;
84
85 if (p[3] & 0x08) { /* skip a filename */
86 while (p[gz->idx++])
87 if (gz->idx >= PAGE_SIZE)
88 goto done;
89 }
90
91 if (p[3] & 0x10) { /* skip a comment */
92 while (p[gz->idx++])
93 if (gz->idx >= PAGE_SIZE)
94 goto done;
95 }
96
97 gz->len = gz->ip->attr->va_size;
98
99 gz->error = 0;
100
101 error = inflate(gz, &gz_glbl);
102
103 if (gz->inbuf) {
104 error2 =
105 vm_deallocate(kernel_map, (vm_offset_t)gz->inbuf, PAGE_SIZE);
106 }
107
108 if (gz->error || error || error2) {
109 printf("Output=%lu ",gz->output);
110 printf("Inflate_error=%d gz->error=%d error2=%d where=%d\n",
111 error,gz->error,error2,gz->where);
112 if (gz->error)
113 goto done;
114 if (error) {
115 gz->error = ENOEXEC;
116 goto done;
117 }
118 if (error2) {
119 gz->error = error2;
120 goto done;
121 }
122 }
123
124 done:
125 error = gz->error;
126 free(gz->gz_slide,M_TEMP);
127 free(gz,M_GZIP);
128 return error;
129}
130
131int
132do_aout_hdr(struct gzip *gz)
133{
134 int error;
135 struct vmspace *vmspace = gz->ip->proc->p_vmspace;
136 u_long vmaddr;
137
138 /*
139 * Set file/virtual offset based on a.out variant.
140 * We do two cases: host byte order and network byte order
141 * (for NetBSD compatibility)
142 */
143 switch ((int)(gz->a_out.a_magic & 0xffff)) {
144 case ZMAGIC:
145 gz->virtual_offset = 0;
146 if (gz->a_out.a_text) {
147 gz->file_offset = NBPG;
148 } else {
149 /* Bill's "screwball mode" */
150 gz->file_offset = 0;
151 }
152 break;
153 case QMAGIC:
154 gz->virtual_offset = NBPG;
155 gz->file_offset = 0;
156 break;
157 default:
158 /* NetBSD compatibility */
159 switch ((int)(ntohl(gz->a_out.a_magic) & 0xffff)) {
160 case ZMAGIC:
161 case QMAGIC:
162 gz->virtual_offset = NBPG;
163 gz->file_offset = 0;
164 break;
165 default:
166 gz->where = __LINE__;
167 return (-1);
168 }
169 }
170
171 gz->bss_size = roundup(gz->a_out.a_bss, NBPG);
172
173 /*
174 * Check various fields in header for validity/bounds.
175 */
176 if (/* entry point must lay with text region */
177 gz->a_out.a_entry < gz->virtual_offset ||
178 gz->a_out.a_entry >= gz->virtual_offset + gz->a_out.a_text ||
179
180 /* text and data size must each be page rounded */
181 gz->a_out.a_text % NBPG ||
182 gz->a_out.a_data % NBPG) {
183 gz->where = __LINE__;
184 return (-1);
185 }
186
187 /*
188 * text/data/bss must not exceed limits
189 */
190 if (/* text can't exceed maximum text size */
191 gz->a_out.a_text > MAXTSIZ ||
192
193 /* data + bss can't exceed maximum data size */
194 gz->a_out.a_data + gz->bss_size > MAXDSIZ ||
195
196 /* data + bss can't exceed rlimit */
197 gz->a_out.a_data + gz->bss_size >
198 gz->ip->proc->p_rlimit[RLIMIT_DATA].rlim_cur) {
199 gz->where = __LINE__;
200 return (ENOMEM);
201 }
202
203 /* Find out how far we should go */
204 gz->file_end = gz->file_offset + gz->a_out.a_text + gz->a_out.a_data;
205
206 /* copy in arguments and/or environment from old process */
207 error = exec_extract_strings(gz->ip);
208 if (error) {
209 gz->where = __LINE__;
210 return (error);
211 }
212
213 /*
214 * Destroy old process VM and create a new one (with a new stack)
215 */
216 exec_new_vmspace(gz->ip);
217
218 vmaddr = gz->virtual_offset;
219
220 error = vm_mmap(&vmspace->vm_map, /* map */
221 &vmaddr, /* address */
222 gz->a_out.a_text, /* size */
223 VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_WRITE, /* protection */
224 VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_WRITE,
225 MAP_ANON | MAP_FIXED, /* flags */
226 0, /* vnode */
227 0); /* offset */
228
229 if (error) {
230 gz->where = __LINE__;
231 return (error);
232 }
233
234 vmaddr = gz->virtual_offset + gz->a_out.a_text;
235
236 /*
237 * Map data read/write (if text is 0, assume text is in data area
238 * [Bill's screwball mode])
239 */
240
241 error = vm_mmap(&vmspace->vm_map,
242 &vmaddr,
243 gz->a_out.a_data,
244 VM_PROT_READ | VM_PROT_WRITE | (gz->a_out.a_text ? 0 : VM_PROT_EXECUTE),
245 VM_PROT_ALL, MAP_ANON | MAP_FIXED,
246 0,
247 0);
248
249 if (error) {
250 gz->where = __LINE__;
251 return (error);
252 }
253
254 /*
255 * Allocate demand-zeroed area for uninitialized data
256 * "bss" = 'block started by symbol' - named after the IBM 7090
257 * instruction of the same name.
258 */
259 vmaddr = gz->virtual_offset + gz->a_out.a_text + gz->a_out.a_data;
260 error = vm_allocate(&vmspace->vm_map, &vmaddr, gz->bss_size, FALSE);
261 if (error) {
262 gz->where = __LINE__;
263 return (error);
264 }
265
266 /* Fill in process VM information */
267 vmspace->vm_tsize = gz->a_out.a_text >> PAGE_SHIFT;
268 vmspace->vm_dsize = (gz->a_out.a_data + gz->bss_size) >> PAGE_SHIFT;
269 vmspace->vm_taddr = (caddr_t) gz->virtual_offset;
270 vmspace->vm_daddr = (caddr_t) gz->virtual_offset + gz->a_out.a_text;
271
272 /* Fill in image_params */
273 gz->ip->interpreted = 0;
274 gz->ip->entry_addr = gz->a_out.a_entry;
275
276 gz->ip->proc->p_sysent = &aout_sysvec;
277
278 return 0;
279}
280
281/*
282 * Tell kern_execve.c about it, with a little help from the linker.
283 * Since `const' objects end up in the text segment, TEXT_SET is the
284 * correct directive to use.
285 */
286static const struct execsw gzip_execsw = { exec_gzip_imgact, "gzip" };
287TEXT_SET(execsw_set, gzip_execsw);
288