All pastes #1786544 Raw Edit

Stuff

public c v1 · immutable
#1786544 ·published 2010-02-04 00:25 UTC
rendered paste body
#define ELF_MAX_PH 32static int elfloader(vxproc *proc,              ssize_t (*readcb)(void*, off_t, void*, size_t),              void *cbdata,              const char *const *argv, const char *const *envp){	vxmem *mem;	int i;	size_t size;	ssize_t act;	struct Proghdr ph[ELF_MAX_PH];	vxmmap *mm;	static const char *null;	if (argv == NULL)		argv = &null;	if (envp == NULL)		envp = &null;	size = 4096;	// For "big mem" we need more than 1/2 GB, but 64-bit Linux	// has only about 1 GB of address space to give out with MAP_32BIT,	// and we've used up some of it for the vxemu structure.  	// Ask for (1<<30) - (1<<24), which should be close enough to 1GB	// to run the SPEC programs but leave enough for things like vxemu.	if (vx_elfbigmem)		size = (1<<30) - (1<<24);	mm = NULL;	if ((mem = vxmem_chunk_new(size)) == NULL)		return -1;	// Read and check the ELF header	struct Elf32 h;	act = readcb(cbdata, 0, &h, sizeof(h));	if (act < 0)		goto error;	if (act < sizeof(h)) {	noexec:		errno = ENOEXEC;		goto error;	}	if (ltoh32(h.e_magic) != ELF_MAGIC)		goto noexec;	// Read the program header table	off_t phoff = ltoh32(h.e_phoff);	size_t phnum = ltoh16(h.e_phnum);	if (phnum <= 0 || phnum > ELF_MAX_PH)	// arbitrary limit for security		goto noexec;	act = readcb(cbdata, phoff, ph, phnum * sizeof ph[0]);	if (act < 0)		goto error;	if (act < phnum * sizeof ph[0])		goto noexec;		// Load each program segment	size_t stackhi = VXMEMSIZE;	size_t addrhi = 0;	for (i = 0; i < phnum; i++) {		const struct Proghdr *p = &ph[i];		if (ltoh32(p->p_type) != ELF_PROG_LOAD)			continue;		// Validate the program segment		off_t offset = ltoh32(p->p_offset);		size_t filesz = ltoh32(p->p_filesz);		size_t va = ltoh32(p->p_va);		size_t memsz = ltoh32(p->p_memsz);		if (filesz > memsz)			goto noexec;		// Validate the memory page region the segment loads into		size_t memlo = VXPAGETRUNC(va);		size_t memhi = VXPAGEROUND(va + memsz);		if (memlo > VXMEMSIZE || memhi > VXMEMSIZE || memhi < memlo)			goto noexec;		// Make sure the VX process is big enough, and mapped		if (size < memhi) {			if (mm) {				vxmem_unmap(mem, mm);				mm = NULL;			}			if (vxmem_resize(mem, memhi) < 0)				goto error;			size = memhi;		}		if (mm == NULL) {			mm = vxmem_map(mem, 0);			if (mm == NULL)				goto error;		}		// Temporarily give ourselves write permissions		// on the segment in order to load it.		if (vxmem_setperm(mem, memlo, memhi - memlo,				VXPERM_READ | VXPERM_WRITE) < 0)			return -1;		// Load the segment.		// Any bss portion is already cleared automatically		// by virtue of the vxproc_clear() above.		act = readcb(cbdata, offset, mm->base + va, filesz);		if (act < 0)			return -1;		if (act < filesz)			goto noexec;		// Set permissions appropriately on the segment's pages		int flags = ltoh32(p->p_flags);		int perm = 0;		switch (flags & (ELF_PROG_FLAG_READ | ELF_PROG_FLAG_WRITE |				ELF_PROG_FLAG_EXEC)) {		case ELF_PROG_FLAG_READ:			perm = VXPERM_READ;			break;		case ELF_PROG_FLAG_READ | ELF_PROG_FLAG_WRITE:			perm = VXPERM_READ | VXPERM_WRITE;			break;		case ELF_PROG_FLAG_READ | ELF_PROG_FLAG_EXEC:			perm = VXPERM_READ | VXPERM_EXEC;			break;		default:			goto noexec;	// invalid perms		}		if (vxmem_setperm(mem, memlo, memhi - memlo, perm) < 0)			goto error;		// Find the lowest-used va, for locating the stack		if (va < stackhi)			stackhi = va;		// Find the highest va too		if (memhi > addrhi)			addrhi = memhi;	}	if (size > addrhi)		vxmem_setperm(mem, addrhi, size - addrhi, VXPERM_READ|VXPERM_WRITE);	if (mm == NULL) {		mm = vxmem_map(mem, 0);		if (mm == NULL)			goto error;	}	// Set up the process's stack,	// growing downward from the executable's base load address.	// Initially we enable read/write access on 64K of stack,	// but the process is free to change that if it wants a bigger stack.	stackhi = VXPAGETRUNC(stackhi);	if (stackhi < VX32_STACK)		goto noexec;	if (vxmem_setperm(mem, stackhi - VX32_STACK, VX32_STACK,			VXPERM_READ | VXPERM_WRITE) < 0)		goto error;	proc->cpu->reg[ESP] = stackhi;	// Push the argument and environment arrays on the stack.	uint32_t esp = stackhi;	uint32_t argc;	uint32_t envc;	argc = countargs(argv);	envc = countargs(envp);	uint32_t *argvenv = malloc((argc+1+envc+1)*sizeof argvenv[0]);	if (argv == NULL)		goto error;	if (copystrings(mm->base, &esp, envc, envp, argvenv+argc+1) < 0 ||	    copystrings(mm->base, &esp, argc, argv, argvenv) < 0) {		free(argvenv);		goto error;	}	if (copyptrs(mm->base, &esp, argc+1+envc+1, argvenv) < 0) {		free(argvenv);		goto error;	}		// Set up stack just like Linux: argc, then argv pointers begin, then env pointers.	esp -= 4;	*(uint32_t*)(mm->base+esp) = argc;	if (proc->mem)		vxmem_free(proc->mem);	proc->mem = mem;		// Set up the process's initial register state	for (i = 0; i < 8; i++)		proc->cpu->reg[i] = 0;	proc->cpu->reg[ESP] = esp;	proc->cpu->eflags = 0;	proc->cpu->eip = ltoh32(h.e_entry);	return 0;error:	if (mm)		vxmem_unmap(mem, mm);	vxmem_free(mem);	return -1;}