Esempio n. 1
0
/* Return >0 if there is an ELF interpreter (i.e. it is a dynamically linked
 * executable) and we could extract it successfully.
 * Return 0 if there isn't one.
 * Return <0 on error.
 */
int elf_has_interpreter(char *exec_hdr,		/* executable header */
		int hdr_len, char *interp, int maxsz)
{
  Elf_Ehdr *hdr = NULL;
  Elf_Phdr *phdr = NULL;
  int e, i;

  if((e=elf_unpack(exec_hdr, hdr_len, &hdr, &phdr)) != OK) return 0;

  for (i = 0; i < hdr->e_phnum; i++) {
      switch (phdr[i].p_type) {
      case PT_INTERP:
      	  if(!interp) return 1;
      	  if(phdr[i].p_filesz >= maxsz)
	  	return -1;
	  if(phdr[i].p_offset + phdr[i].p_filesz >= hdr_len)
	  	return -1;
	  memcpy(interp, exec_hdr + phdr[i].p_offset, phdr[i].p_filesz);
	  interp[phdr[i].p_filesz] = '\0';
	  return 1;
      default:
	  continue;
      }
  }
  return 0;
}
Esempio n. 2
0
int libexec_load_elf(struct exec_info *execi)
{
	Elf_Ehdr *hdr = NULL;
	Elf_Phdr *phdr = NULL;
	int e, i = 0;
	int first = 1;
	vir_bytes startv = 0, stacklow;

	assert(execi != NULL);
	assert(execi->hdr != NULL);

	if((e=elf_unpack(execi->hdr, execi->hdr_len, &hdr, &phdr)) != OK) {
		return e;
	 }

	/* this function can load the dynamic linker, but that
	 * shouldn't require an interpreter itself.
	 */
	i = elf_has_interpreter(execi->hdr, execi->hdr_len, NULL, 0);
	if(i > 0) {
	      return ENOEXEC;
	}

	execi->stack_size = roundup(execi->stack_size, PAGE_SIZE);
	execi->stack_high = rounddown(execi->stack_high, PAGE_SIZE);
	stacklow = execi->stack_high - execi->stack_size;

	assert(execi->copymem);
	assert(execi->clearmem);
	assert(execi->allocmem_prealloc_cleared);
	assert(execi->allocmem_prealloc_junk);
	assert(execi->allocmem_ondemand);

	for (i = 0; i < hdr->e_phnum; i++) {
		Elf_Phdr *ph = &phdr[i];
		off_t file_limit = ph->p_offset + ph->p_filesz;
		/* sanity check binary before wiping out the target process */
		if(execi->filesize < file_limit) {
			return ENOEXEC;
		}
	}

	if(execi->clearproc) execi->clearproc(execi);

	for (i = 0; i < hdr->e_phnum; i++) {
		vir_bytes seg_membytes, page_offset, p_vaddr, vaddr;
		vir_bytes chunk, vfileend, vmemend;
		off_t foffset, fbytes;
		Elf_Phdr *ph = &phdr[i];
		int try_mmap = 1;
		u16_t clearend = 0;
		int pagechunk;
		int mmap_prot = PROT_READ;

		if(!(ph->p_flags & PF_R)) {
			printf("libexec: warning: unreadable segment\n");
		}

		if(ph->p_flags & PF_W) {
			mmap_prot |= PROT_WRITE;
#if ELF_DEBUG
			printf("libexec: adding PROT_WRITE\n");
#endif
		} else {
#if ELF_DEBUG
			printf("libexec: not adding PROT_WRITE\n");
#endif
		}

		if (ph->p_type != PT_LOAD || ph->p_memsz == 0) continue;

		if((ph->p_vaddr % PAGE_SIZE) != (ph->p_offset % PAGE_SIZE)) {
			printf("libexec: unaligned ELF program?\n");
			try_mmap = 0;
		}

		if(!execi->memmap) {
			try_mmap = 0;
		}

		foffset = ph->p_offset;
		fbytes = ph->p_filesz;
		vaddr = p_vaddr = ph->p_vaddr + execi->load_offset;
		seg_membytes = ph->p_memsz;

		page_offset = vaddr % PAGE_SIZE;
		vaddr -= page_offset;
		foffset -= page_offset;
		seg_membytes += page_offset;
		fbytes += page_offset;
		vfileend  = p_vaddr + ph->p_filesz;

		/* if there's usable memory after the file end, we have
		 * to tell VM to clear the memory part of the page when it's
		 * mapped in
		 */
		if((pagechunk = (vfileend % PAGE_SIZE))
			&& ph->p_filesz < ph->p_memsz) {
			clearend = PAGE_SIZE - pagechunk;
		}

		seg_membytes = roundup(seg_membytes, PAGE_SIZE);
		fbytes = roundup(fbytes, PAGE_SIZE);

		if(first || startv > vaddr) startv = vaddr;
		first = 0;

		if ((ph->p_flags & PF_X) != 0 && execi->text_size < seg_membytes)
			execi->text_size = seg_membytes;
		else
			execi->data_size = seg_membytes;

		if(try_mmap && execi->memmap(execi, vaddr, fbytes, foffset, clearend, mmap_prot) == OK) {
#if ELF_DEBUG
			printf("libexec: mmap 0x%lx-0x%lx done, clearend 0x%x\n",
				vaddr, vaddr+fbytes, clearend);
#endif

			if(seg_membytes > fbytes) {
				int rem_mem = seg_membytes - fbytes;;
				vir_bytes remstart = vaddr + fbytes;
				if(execi->allocmem_ondemand(execi,
					remstart, rem_mem) != OK) {
					printf("libexec: mmap extra mem failed\n");
					return ENOMEM;
				}
#if ELF_DEBUG
				else printf("libexec: allocated 0x%lx-0x%lx\n",

					remstart, remstart+rem_mem);
#endif
			}
		} else {
			/* make us some memory */
			if(execi->allocmem_prealloc_junk(execi, vaddr, seg_membytes) != OK) {
				if(execi->clearproc) execi->clearproc(execi);
				return ENOMEM;
			}

#if ELF_DEBUG
			printf("mmapped 0x%lx-0x%lx\n", vaddr, vaddr+seg_membytes);
#endif

			/* Copy executable section into it */
			if(execi->copymem(execi, ph->p_offset, p_vaddr, ph->p_filesz) != OK) {
				if(execi->clearproc) execi->clearproc(execi);
				return ENOMEM;
			}

#if ELF_DEBUG
			printf("copied 0x%lx-0x%lx\n", p_vaddr, p_vaddr+ph->p_filesz);
#endif

			/* Clear remaining bits */
			vmemend = vaddr + seg_membytes;
			if((chunk = p_vaddr - vaddr) > 0) {
#if ELF_DEBUG
				printf("start clearing 0x%lx-0x%lx\n", vaddr, vaddr+chunk);
#endif
				execi->clearmem(execi, vaddr, chunk);
			}
	
			if((chunk = vmemend - vfileend) > 0) {
#if ELF_DEBUG
				printf("end clearing 0x%lx-0x%lx\n", vfileend, vaddr+chunk);
#endif
				execi->clearmem(execi, vfileend, chunk);
			}
		}
	}

	/* Make it a stack */
	if(execi->allocmem_ondemand(execi, stacklow, execi->stack_size) != OK) {
		if(execi->clearproc) execi->clearproc(execi);
		return ENOMEM;
	}

#if ELF_DEBUG
	printf("stack mmapped 0x%lx-0x%lx\n", stacklow, stacklow+execi->stack_size);
#endif

	/* record entry point and lowest load vaddr for caller */
	execi->pc = hdr->e_entry + execi->load_offset;
	execi->load_base = startv;

	return OK;
}
Esempio n. 3
0
int libexec_load_elf(struct exec_info *execi)
{
	Elf_Ehdr *hdr = NULL;
	Elf_Phdr *phdr = NULL;
	int e, i = 0;
	int first = 1;
	vir_bytes startv = 0, stacklow;

	assert(execi != NULL);
	assert(execi->hdr != NULL);

	if((e=elf_unpack(execi->hdr, execi->hdr_len, &hdr, &phdr)) != OK) {
		printf("libexec_load_elf: elf_unpack failed\n");
		return e;
	 }

	/* this function can load the dynamic linker, but that
	 * shouldn't require an interpreter itself.
	 */
	i = elf_has_interpreter(execi->hdr, execi->hdr_len, NULL, 0);
	if(i > 0) {
	      return ENOEXEC;
	}

	execi->stack_size = roundup(execi->stack_size, PAGE_SIZE);
	execi->stack_high = rounddown(execi->stack_high, PAGE_SIZE);
	stacklow = execi->stack_high - execi->stack_size;

	assert(execi->copymem);
	assert(execi->clearmem);
	assert(execi->allocmem_prealloc);
	assert(execi->allocmem_ondemand);

	if(execi->clearproc) execi->clearproc(execi);

	for (i = 0; i < hdr->e_phnum; i++) {
		vir_bytes seg_membytes, page_offset, p_vaddr, vaddr;
		vir_bytes chunk, vfileend, vmemend;
		Elf_Phdr *ph = &phdr[i];
		if (ph->p_type != PT_LOAD || ph->p_memsz == 0) continue;
		vaddr = p_vaddr = ph->p_vaddr + execi->load_offset;
		seg_membytes = ph->p_memsz;
		page_offset = vaddr % PAGE_SIZE;
		vaddr -= page_offset;
		seg_membytes += page_offset;
		seg_membytes = roundup(seg_membytes, PAGE_SIZE);
		if(first || startv > vaddr) startv = vaddr;
		first = 0;

		/* make us some memory */
		if(execi->allocmem_prealloc(execi, vaddr, seg_membytes) != OK) {
			if(execi->clearproc) execi->clearproc(execi);
			return ENOMEM;
		}

#if ELF_DEBUG
		printf("mmapped 0x%lx-0x%lx\n", vaddr, vaddr+seg_membytes);
#endif

		/* Copy executable section into it */
		if(execi->copymem(execi, ph->p_offset, p_vaddr, ph->p_filesz) != OK) {
			if(execi->clearproc) execi->clearproc(execi);
			return ENOMEM;
		}

#if ELF_DEBUG
		printf("copied 0x%lx-0x%lx\n", p_vaddr, p_vaddr+ph->p_filesz);
#endif

		/* Clear remaining bits */
		vfileend  = p_vaddr + ph->p_filesz;
		vmemend = vaddr + seg_membytes;
		if((chunk = p_vaddr - vaddr) > 0) {
#if ELF_DEBUG
			printf("start clearing 0x%lx-0x%lx\n", vaddr, vaddr+chunk);
#endif
			execi->clearmem(execi, vaddr, chunk);
		}
		if((chunk = vmemend - vfileend) > 0) {
#if ELF_DEBUG
			printf("end clearing 0x%lx-0x%lx\n", vfileend, vaddr+chunk);
#endif
			execi->clearmem(execi, vfileend, chunk);
		}
	}

	/* Make it a stack */
	if(execi->allocmem_ondemand(execi, stacklow, execi->stack_size) != OK) {
		if(execi->clearproc) execi->clearproc(execi);
		return ENOMEM;
	}

#if ELF_DEBUG
	printf("stack mmapped 0x%lx-0x%lx\n", stacklow, stacklow+execi->stack_size);
#endif

	/* record entry point and lowest load vaddr for caller */
	execi->pc = hdr->e_entry + execi->load_offset;
	execi->load_base = startv;

	return OK;
}