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