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