recognize and execute dynamically linked executables
. generalize libexec slightly to get some more necessary information from ELF files, e.g. the interpreter . execute dynamically linked executables when exec()ed by VFS . switch to netbsd variant of elf32.h exclusively, solves some conflicting headers
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/exec_elf.h>
|
||||
|
||||
#ifdef __weak_alias
|
||||
__weak_alias(execve, _execve)
|
||||
@@ -23,6 +24,7 @@ int execve(const char *path, char * const *argv, char * const *envp)
|
||||
char **vp;
|
||||
char *sp;
|
||||
size_t argc;
|
||||
int vectors;
|
||||
size_t frame_size;
|
||||
size_t string_off;
|
||||
size_t n;
|
||||
@@ -55,9 +57,14 @@ int execve(const char *path, char * const *argv, char * const *envp)
|
||||
string_off+= sizeof(*ap);
|
||||
}
|
||||
|
||||
/* Add an argument count and two terminating nulls. */
|
||||
frame_size+= sizeof(argc) + sizeof(*ap) + sizeof(*ep);
|
||||
string_off+= sizeof(argc) + sizeof(*ap) + sizeof(*ep);
|
||||
/* Add an argument count, two terminating nulls and
|
||||
* space for the ELF aux vectors, that must come before
|
||||
* (i.e. at a higher address) then the strings.
|
||||
*/
|
||||
vectors = sizeof(argc) + sizeof(*ap) + sizeof(*ep) +
|
||||
sizeof(AuxInfo) * PMEF_AUXVECTORS;
|
||||
frame_size+= vectors;
|
||||
string_off+= vectors;
|
||||
|
||||
/* Align. */
|
||||
frame_size= (frame_size + sizeof(char *) - 1) & ~(sizeof(char *) - 1);
|
||||
@@ -100,15 +107,17 @@ int execve(const char *path, char * const *argv, char * const *envp)
|
||||
/* Padding. */
|
||||
while (sp < frame + frame_size) *sp++= 0;
|
||||
|
||||
/* Clear unused message fields */
|
||||
memset(&m, 0, sizeof(m));
|
||||
|
||||
/* We can finally make the system call. */
|
||||
m.m1_i1 = strlen(path) + 1;
|
||||
m.m1_i2 = frame_size;
|
||||
m.m1_p1 = (char *) __UNCONST(path);
|
||||
m.m1_p2 = frame;
|
||||
|
||||
/* Clear unused fields */
|
||||
m.m1_i3 = 0;
|
||||
m.m1_p3 = NULL;
|
||||
/* Tell PM/VFS we have left space for the aux vectors */
|
||||
m.PMEXEC_FLAGS = PMEF_AUXVECTORSPACE;
|
||||
|
||||
(void) _syscall(PM_PROC_NR, EXEC, &m);
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <libexec.h>
|
||||
#include <string.h>
|
||||
#include <machine/elf.h>
|
||||
|
||||
/* For verbose logging */
|
||||
#define ELF_DEBUG 0
|
||||
@@ -16,10 +18,63 @@
|
||||
|
||||
#define SECTOR_SIZE 512
|
||||
|
||||
static int __elfN(check_header)(const Elf_Ehdr *hdr);
|
||||
static int check_header(const Elf_Ehdr *hdr);
|
||||
|
||||
static int elf_sane(const Elf_Ehdr *hdr)
|
||||
{
|
||||
if (check_header(hdr) != OK) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if((hdr->e_type != ET_EXEC) && (hdr->e_type != ET_DYN)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((hdr->e_phoff > SECTOR_SIZE) ||
|
||||
(hdr->e_phoff + hdr->e_phentsize * hdr->e_phnum) > SECTOR_SIZE) {
|
||||
#if ELF_DEBUG
|
||||
printf("peculiar phoff\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int elf_ph_sane(const Elf_Phdr *phdr)
|
||||
{
|
||||
if (rounddown((uintptr_t)phdr, sizeof(Elf_Addr)) != (uintptr_t)phdr) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int elf_unpack(const char *exec_hdr,
|
||||
int hdr_len, const Elf_Ehdr **hdr, const Elf_Phdr **phdr)
|
||||
{
|
||||
*hdr = (const Elf_Ehdr *)exec_hdr;
|
||||
if(!elf_sane(*hdr)) {
|
||||
#if ELF_DEBUG
|
||||
printf("elf_sane failed\n");
|
||||
#endif
|
||||
return ENOEXEC;
|
||||
}
|
||||
*phdr = (const Elf_Phdr *)(exec_hdr + (*hdr)->e_phoff);
|
||||
if(!elf_ph_sane(*phdr)) {
|
||||
#if ELF_DEBUG
|
||||
printf("elf_ph_sane failed\n");
|
||||
#endif
|
||||
return ENOEXEC;
|
||||
}
|
||||
#if 0
|
||||
if((int)((*phdr) + (*hdr)->e_phnum) >= hdr_len) return ENOEXEC;
|
||||
#endif
|
||||
return OK;
|
||||
}
|
||||
|
||||
int read_header_elf(
|
||||
const char *exec_hdr, /* executable header */
|
||||
int hdr_len, /* significant bytes in exec_hdr */
|
||||
vir_bytes *text_vaddr, /* text virtual address */
|
||||
phys_bytes *text_paddr, /* text physical address */
|
||||
vir_bytes *text_filebytes, /* text segment size (in the file) */
|
||||
@@ -36,7 +91,7 @@ int read_header_elf(
|
||||
const Elf_Ehdr *hdr = NULL;
|
||||
const Elf_Phdr *phdr = NULL;
|
||||
unsigned long seg_filebytes, seg_membytes;
|
||||
int i = 0;
|
||||
int e, i = 0;
|
||||
|
||||
*text_vaddr = *text_paddr = 0;
|
||||
*text_filebytes = *text_membytes = 0;
|
||||
@@ -44,27 +99,12 @@ int read_header_elf(
|
||||
*data_filebytes = *data_membytes = 0;
|
||||
*pc = *text_offset = *data_offset = 0;
|
||||
|
||||
hdr = (const Elf_Ehdr *)exec_hdr;
|
||||
if (__elfN(check_header)(hdr) != OK || (hdr->e_type != ET_EXEC))
|
||||
{
|
||||
return ENOEXEC;
|
||||
}
|
||||
|
||||
if ((hdr->e_phoff > SECTOR_SIZE) ||
|
||||
(hdr->e_phoff + hdr->e_phentsize * hdr->e_phnum) > SECTOR_SIZE) {
|
||||
return ENOEXEC;
|
||||
}
|
||||
|
||||
phdr = (const Elf_Phdr *)(exec_hdr + hdr->e_phoff);
|
||||
if (
|
||||
#ifdef __NBSD_LIBC
|
||||
rounddown((uintptr_t)phdr, sizeof(Elf_Addr)) != (uintptr_t)phdr
|
||||
#else
|
||||
!_minix_aligned(hdr->e_phoff, Elf_Addr)
|
||||
if((e=elf_unpack(exec_hdr, hdr_len, &hdr, &phdr)) != OK) {
|
||||
#if ELF_DEBUG
|
||||
printf("elf_unpack failed\n");
|
||||
#endif
|
||||
) {
|
||||
return ENOEXEC;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
#if ELF_DEBUG
|
||||
printf("Program header file offset (phoff): %ld\n", hdr->e_phoff);
|
||||
@@ -124,7 +164,12 @@ int read_header_elf(
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int __elfN(check_header)(const Elf_Ehdr *hdr)
|
||||
#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \
|
||||
(ehdr).e_ident[EI_MAG1] == ELFMAG1 && \
|
||||
(ehdr).e_ident[EI_MAG2] == ELFMAG2 && \
|
||||
(ehdr).e_ident[EI_MAG3] == ELFMAG3)
|
||||
|
||||
static int check_header(const Elf_Ehdr *hdr)
|
||||
{
|
||||
if (!IS_ELF(*hdr) ||
|
||||
hdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
|
||||
@@ -135,3 +180,66 @@ static int __elfN(check_header)(const Elf_Ehdr *hdr)
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int elf_phdr(const char *exec_hdr, int hdr_len, vir_bytes *ret_phdr)
|
||||
{
|
||||
const Elf_Ehdr *hdr = NULL;
|
||||
const Elf_Phdr *phdr = NULL;
|
||||
int e, i, have_computed_phdr = 1;
|
||||
|
||||
if((e=elf_unpack(exec_hdr, hdr_len, &hdr, &phdr)) != OK) return e;
|
||||
|
||||
for (i = 0; i < hdr->e_phnum; i++) {
|
||||
switch (phdr[i].p_type) {
|
||||
case PT_LOAD:
|
||||
/* compute phdr based on this heuristic, to be used
|
||||
* if there is no PT_PHDR
|
||||
*/
|
||||
if(phdr[i].p_offset == 0) {
|
||||
*ret_phdr = phdr[i].p_vaddr + hdr->e_phoff;
|
||||
have_computed_phdr = 1;
|
||||
}
|
||||
break;
|
||||
case PT_PHDR:
|
||||
*ret_phdr = phdr[i].p_vaddr;
|
||||
return OK;
|
||||
default:
|
||||
break;;
|
||||
}
|
||||
}
|
||||
if(have_computed_phdr) return OK;
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
/* 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(const char *exec_hdr, /* executable header */
|
||||
int hdr_len, char *interp, int maxsz)
|
||||
{
|
||||
const Elf_Ehdr *hdr = NULL;
|
||||
const Elf_Phdr *phdr = NULL;
|
||||
int e, i;
|
||||
|
||||
if((e=elf_unpack(exec_hdr, hdr_len, &hdr, &phdr)) != OK) return e;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef _LIBEXEC_H_
|
||||
#define _LIBEXEC_H_ 1
|
||||
|
||||
#include <machine/elf.h>
|
||||
#include <sys/exec_elf.h>
|
||||
|
||||
/* a.out routines */
|
||||
int read_header_aout(const char *exec_hdr, size_t exec_len, int *sep_id,
|
||||
@@ -10,11 +10,14 @@ int read_header_aout(const char *exec_hdr, size_t exec_len, int *sep_id,
|
||||
int *hdrlenp);
|
||||
|
||||
/* ELF routines */
|
||||
int read_header_elf(const char *exec_hdr,
|
||||
int read_header_elf(const char *exec_hdr, int hdr_len,
|
||||
vir_bytes *text_vaddr, phys_bytes *text_paddr,
|
||||
vir_bytes *text_filebytes, vir_bytes *text_membytes,
|
||||
vir_bytes *data_vaddr, phys_bytes *data_paddr,
|
||||
vir_bytes *data_filebytes, vir_bytes *data_membytes,
|
||||
vir_bytes *pc, off_t *text_offset, off_t *data_offset);
|
||||
|
||||
int elf_has_interpreter(const char *exec_hdr, int hdr_len, char *interp, int maxsz);
|
||||
int elf_phdr(const char *exec_hdr, int hdr_len, vir_bytes *phdr);
|
||||
|
||||
#endif /* !_LIBEXEC_H_ */
|
||||
|
||||
Reference in New Issue
Block a user