40#include <sys/lock.h> 41#include <vm/pmap.h> 42#include <vm/vm_map.h> 43#include <vm/vm_kern.h> 44#include <vm/vm_extern.h> 45 46struct imgact_gzip { 47 struct image_params *ip; 48 struct exec a_out; 49 int error; 50 int gotheader; 51 int where; 52 u_char *inbuf; 53 u_long offset; 54 u_long output; 55 u_long len; 56 int idx; 57 u_long virtual_offset, file_offset, file_end, bss_size; 58}; 59 60static int exec_gzip_imgact __P((struct image_params *imgp)); 61static int NextByte __P((void *vp)); 62static int do_aout_hdr __P((struct imgact_gzip *)); 63static int Flush __P((void *vp, u_char *, u_long siz)); 64 65static int 66exec_gzip_imgact(imgp) 67 struct image_params *imgp; 68{ 69 int error, error2 = 0; 70 const u_char *p = (const u_char *) imgp->image_header; 71 struct imgact_gzip igz; 72 struct inflate infl; 73 struct vmspace *vmspace; 74 75 /* If these four are not OK, it isn't a gzip file */ 76 if (p[0] != 0x1f) 77 return -1; /* 0 Simply magic */ 78 if (p[1] != 0x8b) 79 return -1; /* 1 Simply magic */ 80 if (p[2] != 0x08) 81 return -1; /* 2 Compression method */ 82 if (p[9] != 0x03) 83 return -1; /* 9 OS compressed on */ 84 85 /* 86 * If this one contains anything but a comment or a filename marker, 87 * we don't want to chew on it 88 */ 89 if (p[3] & ~(0x18)) 90 return ENOEXEC; /* 3 Flags */ 91 92 /* These are of no use to us */ 93 /* 4-7 Timestamp */ 94 /* 8 Extra flags */ 95 96 bzero(&igz, sizeof igz); 97 bzero(&infl, sizeof infl); 98 infl.gz_private = (void *) &igz; 99 infl.gz_input = NextByte; 100 infl.gz_output = Flush; 101 102 igz.ip = imgp; 103 igz.idx = 10; 104 105 if (p[3] & 0x08) { /* skip a filename */ 106 while (p[igz.idx++]) 107 if (igz.idx >= PAGE_SIZE) 108 return ENOEXEC; 109 } 110 if (p[3] & 0x10) { /* skip a comment */ 111 while (p[igz.idx++]) 112 if (igz.idx >= PAGE_SIZE) 113 return ENOEXEC; 114 } 115 igz.len = imgp->attr->va_size; 116 117 error = inflate(&infl); 118 119 /* 120 * The unzipped file may not even have been long enough to contain 121 * a header giving Flush() a chance to return error. Check for this. 122 */ 123 if ( !igz.gotheader ) 124 return ENOEXEC; 125 126 if ( !error ) { 127 vmspace = imgp->proc->p_vmspace; 128 error = vm_map_protect(&vmspace->vm_map, 129 (vm_offset_t) vmspace->vm_taddr, 130 (vm_offset_t) (vmspace->vm_taddr + 131 (vmspace->vm_tsize << PAGE_SHIFT)) , 132 VM_PROT_READ|VM_PROT_EXECUTE,0); 133 } 134 135 if (igz.inbuf) { 136 error2 = 137 vm_map_remove(kernel_map, (vm_offset_t) igz.inbuf, 138 (vm_offset_t) igz.inbuf + PAGE_SIZE); 139 } 140 if (igz.error || error || error2) { 141 printf("Output=%lu ", igz.output); 142 printf("Inflate_error=%d igz.error=%d error2=%d where=%d\n", 143 error, igz.error, error2, igz.where); 144 } 145 if (igz.error) 146 return igz.error; 147 if (error) 148 return ENOEXEC; 149 if (error2) 150 return error2; 151 return 0; 152} 153 154static int 155do_aout_hdr(struct imgact_gzip * gz) 156{ 157 int error; 158 struct vmspace *vmspace; 159 vm_offset_t vmaddr; 160 161 /* 162 * Set file/virtual offset based on a.out variant. We do two cases: 163 * host byte order and network byte order (for NetBSD compatibility) 164 */ 165 switch ((int) (gz->a_out.a_magic & 0xffff)) { 166 case ZMAGIC: 167 gz->virtual_offset = 0; 168 if (gz->a_out.a_text) { 169 gz->file_offset = PAGE_SIZE; 170 } else { 171 /* Bill's "screwball mode" */ 172 gz->file_offset = 0; 173 } 174 break; 175 case QMAGIC: 176 gz->virtual_offset = PAGE_SIZE; 177 gz->file_offset = 0; 178 break; 179 default: 180 /* NetBSD compatibility */ 181 switch ((int) (ntohl(gz->a_out.a_magic) & 0xffff)) { 182 case ZMAGIC: 183 case QMAGIC: 184 gz->virtual_offset = PAGE_SIZE; 185 gz->file_offset = 0; 186 break; 187 default: 188 gz->where = __LINE__; 189 return (-1); 190 } 191 } 192 193 gz->bss_size = roundup(gz->a_out.a_bss, PAGE_SIZE); 194 195 /* 196 * Check various fields in header for validity/bounds. 197 */ 198 if ( /* entry point must lay with text region */ 199 gz->a_out.a_entry < gz->virtual_offset || 200 gz->a_out.a_entry >= gz->virtual_offset + gz->a_out.a_text || 201 202 /* text and data size must each be page rounded */ 203 gz->a_out.a_text & PAGE_MASK || gz->a_out.a_data & PAGE_MASK) { 204 gz->where = __LINE__; 205 return (-1); 206 } 207 /* 208 * text/data/bss must not exceed limits 209 */ 210 if ( /* text can't exceed maximum text size */ 211 gz->a_out.a_text > MAXTSIZ || 212 213 /* data + bss can't exceed rlimit */ 214 gz->a_out.a_data + gz->bss_size > 215 gz->ip->proc->p_rlimit[RLIMIT_DATA].rlim_cur) { 216 gz->where = __LINE__; 217 return (ENOMEM); 218 } 219 /* Find out how far we should go */ 220 gz->file_end = gz->file_offset + gz->a_out.a_text + gz->a_out.a_data; 221 222 /* copy in arguments and/or environment from old process */ 223 error = exec_extract_strings(gz->ip); 224 if (error) { 225 gz->where = __LINE__; 226 return (error); 227 } 228 /* 229 * Destroy old process VM and create a new one (with a new stack) 230 */ 231 exec_new_vmspace(gz->ip); 232 233 vmspace = gz->ip->proc->p_vmspace; 234 235 vmaddr = gz->virtual_offset; 236 237 error = vm_mmap(&vmspace->vm_map, 238 &vmaddr, 239 gz->a_out.a_text + gz->a_out.a_data, 240 VM_PROT_ALL, VM_PROT_ALL, MAP_ANON | MAP_FIXED, 241 0, 242 0); 243 244 if (error) { 245 gz->where = __LINE__; 246 return (error); 247 } 248 249 if (gz->bss_size != 0) { 250 /* 251 * Allocate demand-zeroed area for uninitialized data. 252 * "bss" = 'block started by symbol' - named after the 253 * IBM 7090 instruction of the same name. 254 */ 255 vmaddr = gz->virtual_offset + gz->a_out.a_text + 256 gz->a_out.a_data; 257 error = vm_map_find(&vmspace->vm_map, 258 NULL, 259 0, 260 &vmaddr, 261 gz->bss_size, 262 FALSE, VM_PROT_ALL, VM_PROT_ALL, 0); 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) (uintptr_t) gz->virtual_offset; 272 vmspace->vm_daddr = (caddr_t) (uintptr_t) 273 (gz->virtual_offset + gz->a_out.a_text); 274 275 /* Fill in image_params */ 276 gz->ip->interpreted = 0; 277 gz->ip->entry_addr = gz->a_out.a_entry; 278 279 gz->ip->proc->p_sysent = &aout_sysvec; 280 281 return 0; 282} 283 284static int 285NextByte(void *vp) 286{ 287 int error; 288 struct imgact_gzip *igz = (struct imgact_gzip *) vp; 289 290 if (igz->idx >= igz->len) { 291 igz->where = __LINE__; 292 return GZ_EOF; 293 } 294 if (igz->inbuf && igz->idx < (igz->offset + PAGE_SIZE)) { 295 return igz->inbuf[(igz->idx++) - igz->offset]; 296 } 297 if (igz->inbuf) { 298 error = vm_map_remove(kernel_map, (vm_offset_t) igz->inbuf, 299 (vm_offset_t) igz->inbuf + PAGE_SIZE); 300 if (error) { 301 igz->where = __LINE__; 302 igz->error = error; 303 return GZ_EOF; 304 } 305 } 306 igz->offset = igz->idx & ~PAGE_MASK; 307 308 error = vm_mmap(kernel_map, /* map */ 309 (vm_offset_t *) & igz->inbuf, /* address */ 310 PAGE_SIZE, /* size */ 311 VM_PROT_READ, /* protection */ 312 VM_PROT_READ, /* max protection */ 313 0, /* flags */ 314 (caddr_t) igz->ip->vp, /* vnode */ 315 igz->offset); /* offset */ 316 if (error) { 317 igz->where = __LINE__; 318 igz->error = error; 319 return GZ_EOF; 320 } 321 return igz->inbuf[(igz->idx++) - igz->offset]; 322} 323 324static int 325Flush(void *vp, u_char * ptr, u_long siz) 326{ 327 struct imgact_gzip *gz = (struct imgact_gzip *) vp; 328 u_char *p = ptr, *q; 329 int i; 330 331 /* First, find a a.out-header */ 332 if (gz->output < sizeof gz->a_out) { 333 q = (u_char *) & gz->a_out; 334 i = min(siz, sizeof gz->a_out - gz->output); 335 bcopy(p, q + gz->output, i); 336 gz->output += i; 337 p += i; 338 siz -= i; 339 if (gz->output == sizeof gz->a_out) { 340 gz->gotheader = 1; 341 i = do_aout_hdr(gz); 342 if (i == -1) { 343 if (!gz->where) 344 gz->where = __LINE__; 345 gz->error = ENOEXEC; 346 return ENOEXEC; 347 } else if (i) { 348 gz->where = __LINE__; 349 gz->error = i; 350 return ENOEXEC; 351 } 352 if (gz->file_offset == 0) { 353 q = (u_char *) (uintptr_t) gz->virtual_offset; 354 copyout(&gz->a_out, q, sizeof gz->a_out); 355 } 356 } 357 } 358 /* Skip over zero-padded first PAGE if needed */ 359 if (gz->output < gz->file_offset && 360 gz->output + siz > gz->file_offset) { 361 i = min(siz, gz->file_offset - gz->output); 362 gz->output += i; 363 p += i; 364 siz -= i; 365 } 366 if (gz->output >= gz->file_offset && gz->output < gz->file_end) { 367 i = min(siz, gz->file_end - gz->output); 368 q = (u_char *) (uintptr_t) 369 (gz->virtual_offset + gz->output - gz->file_offset); 370 copyout(p, q, i); 371 gz->output += i; 372 p += i; 373 siz -= i; 374 } 375 gz->output += siz; 376 return 0; 377} 378 379 380/* 381 * Tell kern_execve.c about it, with a little help from the linker. 382 */ 383static struct execsw gzip_execsw = {exec_gzip_imgact, "gzip"}; 384EXEC_SET(execgzip, gzip_execsw);
| 39#include <sys/lock.h> 40#include <vm/pmap.h> 41#include <vm/vm_map.h> 42#include <vm/vm_kern.h> 43#include <vm/vm_extern.h> 44 45struct imgact_gzip { 46 struct image_params *ip; 47 struct exec a_out; 48 int error; 49 int gotheader; 50 int where; 51 u_char *inbuf; 52 u_long offset; 53 u_long output; 54 u_long len; 55 int idx; 56 u_long virtual_offset, file_offset, file_end, bss_size; 57}; 58 59static int exec_gzip_imgact __P((struct image_params *imgp)); 60static int NextByte __P((void *vp)); 61static int do_aout_hdr __P((struct imgact_gzip *)); 62static int Flush __P((void *vp, u_char *, u_long siz)); 63 64static int 65exec_gzip_imgact(imgp) 66 struct image_params *imgp; 67{ 68 int error, error2 = 0; 69 const u_char *p = (const u_char *) imgp->image_header; 70 struct imgact_gzip igz; 71 struct inflate infl; 72 struct vmspace *vmspace; 73 74 /* If these four are not OK, it isn't a gzip file */ 75 if (p[0] != 0x1f) 76 return -1; /* 0 Simply magic */ 77 if (p[1] != 0x8b) 78 return -1; /* 1 Simply magic */ 79 if (p[2] != 0x08) 80 return -1; /* 2 Compression method */ 81 if (p[9] != 0x03) 82 return -1; /* 9 OS compressed on */ 83 84 /* 85 * If this one contains anything but a comment or a filename marker, 86 * we don't want to chew on it 87 */ 88 if (p[3] & ~(0x18)) 89 return ENOEXEC; /* 3 Flags */ 90 91 /* These are of no use to us */ 92 /* 4-7 Timestamp */ 93 /* 8 Extra flags */ 94 95 bzero(&igz, sizeof igz); 96 bzero(&infl, sizeof infl); 97 infl.gz_private = (void *) &igz; 98 infl.gz_input = NextByte; 99 infl.gz_output = Flush; 100 101 igz.ip = imgp; 102 igz.idx = 10; 103 104 if (p[3] & 0x08) { /* skip a filename */ 105 while (p[igz.idx++]) 106 if (igz.idx >= PAGE_SIZE) 107 return ENOEXEC; 108 } 109 if (p[3] & 0x10) { /* skip a comment */ 110 while (p[igz.idx++]) 111 if (igz.idx >= PAGE_SIZE) 112 return ENOEXEC; 113 } 114 igz.len = imgp->attr->va_size; 115 116 error = inflate(&infl); 117 118 /* 119 * The unzipped file may not even have been long enough to contain 120 * a header giving Flush() a chance to return error. Check for this. 121 */ 122 if ( !igz.gotheader ) 123 return ENOEXEC; 124 125 if ( !error ) { 126 vmspace = imgp->proc->p_vmspace; 127 error = vm_map_protect(&vmspace->vm_map, 128 (vm_offset_t) vmspace->vm_taddr, 129 (vm_offset_t) (vmspace->vm_taddr + 130 (vmspace->vm_tsize << PAGE_SHIFT)) , 131 VM_PROT_READ|VM_PROT_EXECUTE,0); 132 } 133 134 if (igz.inbuf) { 135 error2 = 136 vm_map_remove(kernel_map, (vm_offset_t) igz.inbuf, 137 (vm_offset_t) igz.inbuf + PAGE_SIZE); 138 } 139 if (igz.error || error || error2) { 140 printf("Output=%lu ", igz.output); 141 printf("Inflate_error=%d igz.error=%d error2=%d where=%d\n", 142 error, igz.error, error2, igz.where); 143 } 144 if (igz.error) 145 return igz.error; 146 if (error) 147 return ENOEXEC; 148 if (error2) 149 return error2; 150 return 0; 151} 152 153static int 154do_aout_hdr(struct imgact_gzip * gz) 155{ 156 int error; 157 struct vmspace *vmspace; 158 vm_offset_t vmaddr; 159 160 /* 161 * Set file/virtual offset based on a.out variant. We do two cases: 162 * host byte order and network byte order (for NetBSD compatibility) 163 */ 164 switch ((int) (gz->a_out.a_magic & 0xffff)) { 165 case ZMAGIC: 166 gz->virtual_offset = 0; 167 if (gz->a_out.a_text) { 168 gz->file_offset = PAGE_SIZE; 169 } else { 170 /* Bill's "screwball mode" */ 171 gz->file_offset = 0; 172 } 173 break; 174 case QMAGIC: 175 gz->virtual_offset = PAGE_SIZE; 176 gz->file_offset = 0; 177 break; 178 default: 179 /* NetBSD compatibility */ 180 switch ((int) (ntohl(gz->a_out.a_magic) & 0xffff)) { 181 case ZMAGIC: 182 case QMAGIC: 183 gz->virtual_offset = PAGE_SIZE; 184 gz->file_offset = 0; 185 break; 186 default: 187 gz->where = __LINE__; 188 return (-1); 189 } 190 } 191 192 gz->bss_size = roundup(gz->a_out.a_bss, PAGE_SIZE); 193 194 /* 195 * Check various fields in header for validity/bounds. 196 */ 197 if ( /* entry point must lay with text region */ 198 gz->a_out.a_entry < gz->virtual_offset || 199 gz->a_out.a_entry >= gz->virtual_offset + gz->a_out.a_text || 200 201 /* text and data size must each be page rounded */ 202 gz->a_out.a_text & PAGE_MASK || gz->a_out.a_data & PAGE_MASK) { 203 gz->where = __LINE__; 204 return (-1); 205 } 206 /* 207 * text/data/bss must not exceed limits 208 */ 209 if ( /* text can't exceed maximum text size */ 210 gz->a_out.a_text > MAXTSIZ || 211 212 /* data + bss can't exceed rlimit */ 213 gz->a_out.a_data + gz->bss_size > 214 gz->ip->proc->p_rlimit[RLIMIT_DATA].rlim_cur) { 215 gz->where = __LINE__; 216 return (ENOMEM); 217 } 218 /* Find out how far we should go */ 219 gz->file_end = gz->file_offset + gz->a_out.a_text + gz->a_out.a_data; 220 221 /* copy in arguments and/or environment from old process */ 222 error = exec_extract_strings(gz->ip); 223 if (error) { 224 gz->where = __LINE__; 225 return (error); 226 } 227 /* 228 * Destroy old process VM and create a new one (with a new stack) 229 */ 230 exec_new_vmspace(gz->ip); 231 232 vmspace = gz->ip->proc->p_vmspace; 233 234 vmaddr = gz->virtual_offset; 235 236 error = vm_mmap(&vmspace->vm_map, 237 &vmaddr, 238 gz->a_out.a_text + gz->a_out.a_data, 239 VM_PROT_ALL, VM_PROT_ALL, MAP_ANON | MAP_FIXED, 240 0, 241 0); 242 243 if (error) { 244 gz->where = __LINE__; 245 return (error); 246 } 247 248 if (gz->bss_size != 0) { 249 /* 250 * Allocate demand-zeroed area for uninitialized data. 251 * "bss" = 'block started by symbol' - named after the 252 * IBM 7090 instruction of the same name. 253 */ 254 vmaddr = gz->virtual_offset + gz->a_out.a_text + 255 gz->a_out.a_data; 256 error = vm_map_find(&vmspace->vm_map, 257 NULL, 258 0, 259 &vmaddr, 260 gz->bss_size, 261 FALSE, VM_PROT_ALL, VM_PROT_ALL, 0); 262 if (error) { 263 gz->where = __LINE__; 264 return (error); 265 } 266 } 267 /* Fill in process VM information */ 268 vmspace->vm_tsize = gz->a_out.a_text >> PAGE_SHIFT; 269 vmspace->vm_dsize = (gz->a_out.a_data + gz->bss_size) >> PAGE_SHIFT; 270 vmspace->vm_taddr = (caddr_t) (uintptr_t) gz->virtual_offset; 271 vmspace->vm_daddr = (caddr_t) (uintptr_t) 272 (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 283static int 284NextByte(void *vp) 285{ 286 int error; 287 struct imgact_gzip *igz = (struct imgact_gzip *) vp; 288 289 if (igz->idx >= igz->len) { 290 igz->where = __LINE__; 291 return GZ_EOF; 292 } 293 if (igz->inbuf && igz->idx < (igz->offset + PAGE_SIZE)) { 294 return igz->inbuf[(igz->idx++) - igz->offset]; 295 } 296 if (igz->inbuf) { 297 error = vm_map_remove(kernel_map, (vm_offset_t) igz->inbuf, 298 (vm_offset_t) igz->inbuf + PAGE_SIZE); 299 if (error) { 300 igz->where = __LINE__; 301 igz->error = error; 302 return GZ_EOF; 303 } 304 } 305 igz->offset = igz->idx & ~PAGE_MASK; 306 307 error = vm_mmap(kernel_map, /* map */ 308 (vm_offset_t *) & igz->inbuf, /* address */ 309 PAGE_SIZE, /* size */ 310 VM_PROT_READ, /* protection */ 311 VM_PROT_READ, /* max protection */ 312 0, /* flags */ 313 (caddr_t) igz->ip->vp, /* vnode */ 314 igz->offset); /* offset */ 315 if (error) { 316 igz->where = __LINE__; 317 igz->error = error; 318 return GZ_EOF; 319 } 320 return igz->inbuf[(igz->idx++) - igz->offset]; 321} 322 323static int 324Flush(void *vp, u_char * ptr, u_long siz) 325{ 326 struct imgact_gzip *gz = (struct imgact_gzip *) vp; 327 u_char *p = ptr, *q; 328 int i; 329 330 /* First, find a a.out-header */ 331 if (gz->output < sizeof gz->a_out) { 332 q = (u_char *) & gz->a_out; 333 i = min(siz, sizeof gz->a_out - gz->output); 334 bcopy(p, q + gz->output, i); 335 gz->output += i; 336 p += i; 337 siz -= i; 338 if (gz->output == sizeof gz->a_out) { 339 gz->gotheader = 1; 340 i = do_aout_hdr(gz); 341 if (i == -1) { 342 if (!gz->where) 343 gz->where = __LINE__; 344 gz->error = ENOEXEC; 345 return ENOEXEC; 346 } else if (i) { 347 gz->where = __LINE__; 348 gz->error = i; 349 return ENOEXEC; 350 } 351 if (gz->file_offset == 0) { 352 q = (u_char *) (uintptr_t) gz->virtual_offset; 353 copyout(&gz->a_out, q, sizeof gz->a_out); 354 } 355 } 356 } 357 /* Skip over zero-padded first PAGE if needed */ 358 if (gz->output < gz->file_offset && 359 gz->output + siz > gz->file_offset) { 360 i = min(siz, gz->file_offset - gz->output); 361 gz->output += i; 362 p += i; 363 siz -= i; 364 } 365 if (gz->output >= gz->file_offset && gz->output < gz->file_end) { 366 i = min(siz, gz->file_end - gz->output); 367 q = (u_char *) (uintptr_t) 368 (gz->virtual_offset + gz->output - gz->file_offset); 369 copyout(p, q, i); 370 gz->output += i; 371 p += i; 372 siz -= i; 373 } 374 gz->output += siz; 375 return 0; 376} 377 378 379/* 380 * Tell kern_execve.c about it, with a little help from the linker. 381 */ 382static struct execsw gzip_execsw = {exec_gzip_imgact, "gzip"}; 383EXEC_SET(execgzip, gzip_execsw);
|