imgact_gzip.c revision 3417
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 289