imgact_gzip.c revision 3507
13332Sphk/* 23332Sphk * Parts of this file are not covered by: 33332Sphk * ---------------------------------------------------------------------------- 43332Sphk * "THE BEER-WARE LICENSE" (Revision 42): 53332Sphk * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you 63332Sphk * can do whatever you want with this stuff. If we meet some day, and you think 73332Sphk * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 83332Sphk * ---------------------------------------------------------------------------- 93332Sphk * 103507Scsgr * $Id: imgact_gzip.c,v 1.7 1994/10/07 22:26:51 csgr Exp $ 113332Sphk * 123332Sphk * This module handles execution of a.out files which have been run through 133332Sphk * "gzip -9". 143332Sphk * 153332Sphk * For now you need to use exactly this command to compress the binaries: 163332Sphk * 173332Sphk * gzip -9 -v < /bin/sh > /tmp/sh 183332Sphk * 193332Sphk * TODO: 203332Sphk * text-segments should be made R/O after being filled 213332Sphk * is the vm-stuff safe ? 223332Sphk * should handle the entire header of gzip'ed stuff. 233332Sphk * inflate isn't quite reentrant yet... 243332Sphk * error-handling is a mess... 253332Sphk * so is the rest... 263417Scsgr * tidy up unnecesary includes 273332Sphk */ 283332Sphk 293507Scsgr 303507Scsgr#include <sys/param.h> /* some header file needs this first foo! */ 313507Scsgr 323332Sphk#include <sys/exec.h> 333332Sphk#include <sys/imgact.h> 343332Sphk#include <sys/imgact_aout.h> 353507Scsgr#include <sys/inflate.h> 363332Sphk#include <sys/kernel.h> 373507Scsgr#include <sys/malloc.h> 383507Scsgr#include <sys/mman.h> 393507Scsgr#include <sys/resourcevar.h> 403332Sphk#include <sys/sysent.h> 413507Scsgr#include <sys/systm.h> 423332Sphk 433332Sphk#include <vm/vm.h> 443332Sphk#include <vm/vm_kern.h> 453332Sphk 463332Sphkextern struct sysentvec aout_sysvec; 473332Sphk 483332Sphkint 493332Sphkexec_gzip_imgact(iparams) 503332Sphk struct image_params *iparams; 513332Sphk{ 523332Sphk int error,error2=0; 533332Sphk u_char *p = (u_char *) iparams->image_header; 543332Sphk struct gzip *gz; 553417Scsgr struct gz_global gz_glbl; 563332Sphk 573348Sphk /* If these four are not OK, it isn't a gzip file */ 583348Sphk if (p[0] != 0x1f) return -1; /* 0 Simply magic */ 593348Sphk if (p[1] != 0x8b) return -1; /* 1 Simply magic */ 603348Sphk if (p[2] != 0x08) return -1; /* 2 Compression method */ 613348Sphk if (p[9] != 0x03) return -1; /* 9 OS compressed on */ 623332Sphk 633348Sphk /* If this one contains anything but a comment or a filename 643348Sphk * marker, we don't want to chew on it 653348Sphk */ 663348Sphk if (p[3] & ~(0x18)) return ENOEXEC; /* 3 Flags */ 673332Sphk 683348Sphk /* These are of no use to us */ 693348Sphk /* 4-7 Timestamp */ 703348Sphk /* 8 Extra flags */ 713348Sphk 723353Sphk gz = malloc(sizeof *gz,M_GZIP,M_NOWAIT); 733348Sphk if (!gz) 743332Sphk return ENOMEM; 753348Sphk bzero(gz,sizeof *gz); /* waste of time ? */ 763332Sphk 773417Scsgr gz->gz_slide = malloc(WSIZE,M_TEMP,M_NOWAIT); 783417Scsgr if (!gz->gz_slide) { 793353Sphk free(gz,M_GZIP); 803417Scsgr return ENOMEM; 813353Sphk } 823353Sphk 833332Sphk gz->ip = iparams; 843348Sphk gz->error = ENOEXEC; 853348Sphk gz->idx = 10; 863348Sphk 873348Sphk if (p[3] & 0x08) { /* skip a filename */ 883348Sphk while (p[gz->idx++]) 893348Sphk if (gz->idx >= PAGE_SIZE) 903348Sphk goto done; 913348Sphk } 923348Sphk 933348Sphk if (p[3] & 0x10) { /* skip a comment */ 943348Sphk while (p[gz->idx++]) 953348Sphk if (gz->idx >= PAGE_SIZE) 963348Sphk goto done; 973348Sphk } 983332Sphk 993332Sphk gz->len = gz->ip->attr->va_size; 1003332Sphk 1013348Sphk gz->error = 0; 1023348Sphk 1033417Scsgr error = inflate(gz, &gz_glbl); 1043348Sphk 1053332Sphk if (gz->inbuf) { 1063332Sphk error2 = 1073332Sphk vm_deallocate(kernel_map, (vm_offset_t)gz->inbuf, PAGE_SIZE); 1083332Sphk } 1093348Sphk 1103348Sphk if (gz->error || error || error2) { 1113348Sphk printf("Output=%lu ",gz->output); 1123348Sphk printf("Inflate_error=%d gz->error=%d error2=%d where=%d\n", 1133332Sphk error,gz->error,error2,gz->where); 1143348Sphk if (gz->error) 1153348Sphk goto done; 1163348Sphk if (error) { 1173348Sphk gz->error = ENOEXEC; 1183348Sphk goto done; 1193348Sphk } 1203348Sphk if (error2) { 1213348Sphk gz->error = error2; 1223348Sphk goto done; 1233348Sphk } 1243348Sphk } 1253332Sphk 1263348Sphk done: 1273332Sphk error = gz->error; 1283417Scsgr free(gz->gz_slide,M_TEMP); 1293353Sphk free(gz,M_GZIP); 1303332Sphk return error; 1313332Sphk} 1323332Sphk 1333332Sphkint 1343332Sphkdo_aout_hdr(struct gzip *gz) 1353332Sphk{ 1363332Sphk int error; 1373332Sphk struct vmspace *vmspace = gz->ip->proc->p_vmspace; 1383332Sphk u_long vmaddr; 1393332Sphk 1403332Sphk /* 1413332Sphk * Set file/virtual offset based on a.out variant. 1423332Sphk * We do two cases: host byte order and network byte order 1433332Sphk * (for NetBSD compatibility) 1443332Sphk */ 1453332Sphk switch ((int)(gz->a_out.a_magic & 0xffff)) { 1463332Sphk case ZMAGIC: 1473332Sphk gz->virtual_offset = 0; 1483332Sphk if (gz->a_out.a_text) { 1493332Sphk gz->file_offset = NBPG; 1503332Sphk } else { 1513332Sphk /* Bill's "screwball mode" */ 1523332Sphk gz->file_offset = 0; 1533332Sphk } 1543332Sphk break; 1553332Sphk case QMAGIC: 1563332Sphk gz->virtual_offset = NBPG; 1573332Sphk gz->file_offset = 0; 1583332Sphk break; 1593332Sphk default: 1603332Sphk /* NetBSD compatibility */ 1613332Sphk switch ((int)(ntohl(gz->a_out.a_magic) & 0xffff)) { 1623332Sphk case ZMAGIC: 1633332Sphk case QMAGIC: 1643332Sphk gz->virtual_offset = NBPG; 1653332Sphk gz->file_offset = 0; 1663332Sphk break; 1673332Sphk default: 1683332Sphk gz->where = __LINE__; 1693332Sphk return (-1); 1703332Sphk } 1713332Sphk } 1723332Sphk 1733332Sphk gz->bss_size = roundup(gz->a_out.a_bss, NBPG); 1743332Sphk 1753332Sphk /* 1763332Sphk * Check various fields in header for validity/bounds. 1773332Sphk */ 1783332Sphk if (/* entry point must lay with text region */ 1793332Sphk gz->a_out.a_entry < gz->virtual_offset || 1803332Sphk gz->a_out.a_entry >= gz->virtual_offset + gz->a_out.a_text || 1813332Sphk 1823332Sphk /* text and data size must each be page rounded */ 1833332Sphk gz->a_out.a_text % NBPG || 1843332Sphk gz->a_out.a_data % NBPG) { 1853332Sphk gz->where = __LINE__; 1863332Sphk return (-1); 1873332Sphk } 1883332Sphk 1893332Sphk /* 1903332Sphk * text/data/bss must not exceed limits 1913332Sphk */ 1923332Sphk if (/* text can't exceed maximum text size */ 1933332Sphk gz->a_out.a_text > MAXTSIZ || 1943332Sphk 1953332Sphk /* data + bss can't exceed maximum data size */ 1963332Sphk gz->a_out.a_data + gz->bss_size > MAXDSIZ || 1973332Sphk 1983332Sphk /* data + bss can't exceed rlimit */ 1993332Sphk gz->a_out.a_data + gz->bss_size > 2003332Sphk gz->ip->proc->p_rlimit[RLIMIT_DATA].rlim_cur) { 2013332Sphk gz->where = __LINE__; 2023332Sphk return (ENOMEM); 2033332Sphk } 2043332Sphk 2053348Sphk /* Find out how far we should go */ 2063348Sphk gz->file_end = gz->file_offset + gz->a_out.a_text + gz->a_out.a_data; 2073348Sphk 2083332Sphk /* copy in arguments and/or environment from old process */ 2093332Sphk error = exec_extract_strings(gz->ip); 2103332Sphk if (error) { 2113332Sphk gz->where = __LINE__; 2123332Sphk return (error); 2133332Sphk } 2143332Sphk 2153332Sphk /* 2163332Sphk * Destroy old process VM and create a new one (with a new stack) 2173332Sphk */ 2183332Sphk exec_new_vmspace(gz->ip); 2193332Sphk 2203332Sphk vmaddr = gz->virtual_offset; 2213332Sphk 2223332Sphk error = vm_mmap(&vmspace->vm_map, /* map */ 2233332Sphk &vmaddr, /* address */ 2243332Sphk gz->a_out.a_text, /* size */ 2253332Sphk VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_WRITE, /* protection */ 2263332Sphk VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_WRITE, 2273332Sphk MAP_ANON | MAP_FIXED, /* flags */ 2283332Sphk 0, /* vnode */ 2293332Sphk 0); /* offset */ 2303332Sphk 2313332Sphk if (error) { 2323332Sphk gz->where = __LINE__; 2333332Sphk return (error); 2343332Sphk } 2353332Sphk 2363332Sphk vmaddr = gz->virtual_offset + gz->a_out.a_text; 2373332Sphk 2383332Sphk /* 2393332Sphk * Map data read/write (if text is 0, assume text is in data area 2403332Sphk * [Bill's screwball mode]) 2413332Sphk */ 2423332Sphk 2433332Sphk error = vm_mmap(&vmspace->vm_map, 2443332Sphk &vmaddr, 2453332Sphk gz->a_out.a_data, 2463332Sphk VM_PROT_READ | VM_PROT_WRITE | (gz->a_out.a_text ? 0 : VM_PROT_EXECUTE), 2473332Sphk VM_PROT_ALL, MAP_ANON | MAP_FIXED, 2483332Sphk 0, 2493332Sphk 0); 2503332Sphk 2513332Sphk if (error) { 2523332Sphk gz->where = __LINE__; 2533332Sphk return (error); 2543332Sphk } 2553332Sphk 2563332Sphk /* 2573332Sphk * Allocate demand-zeroed area for uninitialized data 2583332Sphk * "bss" = 'block started by symbol' - named after the IBM 7090 2593332Sphk * instruction of the same name. 2603332Sphk */ 2613332Sphk vmaddr = gz->virtual_offset + gz->a_out.a_text + gz->a_out.a_data; 2623332Sphk error = vm_allocate(&vmspace->vm_map, &vmaddr, gz->bss_size, FALSE); 2633332Sphk if (error) { 2643332Sphk gz->where = __LINE__; 2653332Sphk return (error); 2663332Sphk } 2673332Sphk 2683332Sphk /* Fill in process VM information */ 2693332Sphk vmspace->vm_tsize = gz->a_out.a_text >> PAGE_SHIFT; 2703332Sphk vmspace->vm_dsize = (gz->a_out.a_data + gz->bss_size) >> PAGE_SHIFT; 2713332Sphk vmspace->vm_taddr = (caddr_t) gz->virtual_offset; 2723332Sphk vmspace->vm_daddr = (caddr_t) gz->virtual_offset + gz->a_out.a_text; 2733332Sphk 2743332Sphk /* Fill in image_params */ 2753332Sphk gz->ip->interpreted = 0; 2763332Sphk gz->ip->entry_addr = gz->a_out.a_entry; 2773332Sphk 2783332Sphk gz->ip->proc->p_sysent = &aout_sysvec; 2793348Sphk 2803332Sphk return 0; 2813332Sphk} 2823332Sphk 2833332Sphk/* 2843332Sphk * Tell kern_execve.c about it, with a little help from the linker. 2853332Sphk * Since `const' objects end up in the text segment, TEXT_SET is the 2863332Sphk * correct directive to use. 2873332Sphk */ 2883332Sphkstatic const struct execsw gzip_execsw = { exec_gzip_imgact, "gzip" }; 2893332SphkTEXT_SET(execsw_set, gzip_execsw); 2903332Sphk 291