Skip to content

Commit

Permalink
process/load: Add 64bit interpreter support
Browse files Browse the repository at this point in the history
JIRA: RTOS-664
  • Loading branch information
badochov committed Oct 6, 2024
1 parent 8c92309 commit 245decd
Showing 1 changed file with 203 additions and 3 deletions.
206 changes: 203 additions & 3 deletions proc/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,7 @@ int process_load32(vm_map_t *map, vm_object_t *o, off_t base, void *iehdr, size_
}


int process_load64(vm_map_t *map, vm_object_t *o, off_t base, void *iehdr, size_t size, size_t *ustacksz, hal_tls_t *tls, ptr_t *tbssAddr)
int process_load64(vm_map_t *map, vm_object_t *o, off_t base, void *iehdr, size_t size, size_t *ustacksz, hal_tls_t *tls, ptr_t *tbssAddr, struct auxInfo **auxData)
{
void *vaddr;
size_t memsz, filesz;
Expand All @@ -617,6 +617,16 @@ int process_load64(vm_map_t *map, vm_object_t *o, off_t base, void *iehdr, size_
return -ENOEXEC;
}

(*auxData)->a_type = AT_ENTRY;
(*auxData)->a_v = (u64)ehdr->e_entry;
(*auxData)++;
(*auxData)->a_type = AT_PHNUM;
(*auxData)->a_v = (u64)ehdr->e_phnum;
(*auxData)++;
(*auxData)->a_type = AT_PHENT;
(*auxData)->a_v = (u64)ehdr->e_phentsize;
(*auxData)++;

shdr = (void *)((char *)ehdr + ehdr->e_shoff);
shstrshdr = shdr + ehdr->e_shstrndx;
snameTab = (char *)ehdr + shstrshdr->sh_offset;
Expand All @@ -640,6 +650,12 @@ int process_load64(vm_map_t *map, vm_object_t *o, off_t base, void *iehdr, size_
*ustacksz = round_page(phdr->p_memsz);
}

if (phdr->p_type == PT_PHDR) {
(*auxData)->a_type = AT_PHDR;
(*auxData)->a_v = (u64)phdr->p_vaddr;
(*auxData)++;
}

if ((phdr->p_type != PT_LOAD) || (phdr->p_vaddr == 0)) {
continue;
}
Expand Down Expand Up @@ -685,6 +701,188 @@ int process_load64(vm_map_t *map, vm_object_t *o, off_t base, void *iehdr, size_
}


int process_getInterpreterPath64(const Elf64_Ehdr *ehdr, const char **interpreterPath)
{
const Elf64_Phdr *phdrs = (const void *)ehdr + ehdr->e_phoff;
Elf64_Half i;
Elf64_Word letter;

*interpreterPath = NULL;

for (i = 0; i < ehdr->e_phnum; i++) {
if (phdrs[i].p_type != PT_INTERP) {
continue;
}

if (phdrs[i].p_filesz == 0) {
return -EINVAL;
}

*interpreterPath = (const char *)ehdr + phdrs[i].p_offset;
/* Check that interpreter path is of specified length. */
for (letter = 0; letter < phdrs[i].p_filesz; letter++) {
if ((*interpreterPath)[letter] == '\0') {
break;
}
}
if (letter != (phdrs[i].p_filesz - 1)) {
return -EINVAL;
}
}

return EOK;
}


int process_doLoadInterpreter64(vm_map_t *map, vm_object_t *o, off_t base, void *iehdr, size_t size, void **baseAddr, void **interpreterEntry)
{
void *vaddr;
size_t memsz, filesz;
Elf64_Ehdr *ehdr = iehdr;
Elf64_Phdr *phdrs = (void *)ehdr + ehdr->e_phoff;
unsigned i, prot, flags;
Elf64_Off offs, misalign;
Elf64_Word al;
Elf64_Addr loadLow, loadHigh;
size_t loadSize;

if (process_validateElf64(iehdr, size) < 0) {
return -ENOEXEC;
}

/* Dynamic linker needs to be mapped in a contignous part of memory. */
/* Get lowest and highest loaded address to to obtain total size. */
loadLow = ~(Elf64_Addr)0;
loadHigh = 0;
for (i = 0; i < ehdr->e_phnum; i++) {
if (phdrs[i].p_type == PT_LOAD) {
loadLow = min(loadLow, phdrs[i].p_vaddr);
loadHigh = max(loadHigh, phdrs[i].p_vaddr + phdrs[i].p_memsz);
}
}

/* No loadable section found. */
if (loadHigh < loadLow) {
return -ENOEXEC;
}
/* Find a place in vm where interpreter will fit. */
loadSize = round_page(loadHigh - loadLow);
*baseAddr = vm_mmap(map, (void *)(ptr_t)loadLow, NULL, loadSize, PROT_USER, NULL, -1, MAP_NONE);
if ((*baseAddr) == NULL) {
return -ENOMEM;
}
if (vm_munmap(map, *baseAddr, loadSize) < 0) {
return -ENOMEM;
}

for (i = 0; i < ehdr->e_phnum; i++) {
if (phdrs[i].p_type != PT_LOAD) {
continue;
}

al = max(phdrs[i].p_align, 1);
vaddr = ((char *)*baseAddr) + ((phdrs[i].p_vaddr & ~(al - 1)) - loadLow);
offs = phdrs[i].p_offset & ~(al - 1);
misalign = phdrs[i].p_offset & (al - 1);
filesz = (phdrs[i].p_filesz != 0) ? (phdrs[i].p_filesz + misalign) : 0;
memsz = phdrs[i].p_memsz + misalign;

prot = PROT_USER;
flags = MAP_FIXED;

if ((phdrs[i].p_flags & PF_R) != 0) {
prot |= PROT_READ;
}

if ((phdrs[i].p_flags & PF_W) != 0) {
prot |= PROT_WRITE;
}

if ((phdrs[i].p_flags & PF_X) != 0) {
prot |= PROT_EXEC;
}

if (filesz != 0) {
if ((prot & PROT_WRITE) != 0) {
flags |= MAP_NEEDSCOPY;
}
if (vm_mmap(map, vaddr, NULL, round_page(filesz), prot, o, base + offs, flags) == NULL) {
return -ENOMEM;
}
}

if (filesz != memsz) {
if (round_page(memsz) != round_page(filesz)) {
if (vm_mmap(map, vaddr + round_page(filesz), NULL, round_page(memsz) - round_page(filesz), prot, NULL, -1, MAP_FIXED) == NULL) {
return -ENOMEM;
}
}
hal_memset(vaddr + filesz, 0, round_page((ptr_t)vaddr + memsz) - ((ptr_t)vaddr + filesz));
}
}

*interpreterEntry = ((char *)(*baseAddr) + (ehdr->e_entry - loadLow));

return EOK;
}


/* *interpreterEntry is changed only if interpreter is found and loaded properly. */
int process_loadInterpreter64(vm_map_t *map, vm_object_t *o, off_t base, const void *iehdr, size_t size, void **interpreterEntry, struct auxInfo **auxData, int *hasInterpreter)
{
const Elf64_Ehdr *ehdr = iehdr;
int err;
const char *interpreterPath;
oid_t interpOid;
vm_object_t *interpO;
off_t interpBase = 0;
void *interpIehdr;
size_t interpSize;
void *baseAddr;

err = process_getInterpreterPath64(ehdr, &interpreterPath);
if (err < 0) {
return err;
}
if (interpreterPath == NULL) {
return EOK;
}

/* Load interpreter. */
err = proc_lookup(interpreterPath, NULL, &interpOid);
if (err < 0) {
return err;
}

err = vm_objectGet(&interpO, interpOid);
if (err < 0) {
return err;
}
interpSize = round_page(interpO->size);
interpIehdr = vm_mmap(process_common.kmap, NULL, NULL, interpSize, PROT_READ, interpO, interpBase, MAP_NONE);
if (interpIehdr == NULL) {
vm_objectPut(interpO);
return -ENOMEM;
}
err = process_doLoadInterpreter64(map, interpO, interpBase, interpIehdr, interpSize, &baseAddr, interpreterEntry);

vm_munmap(process_common.kmap, interpIehdr, interpSize);
vm_objectPut(interpO);

if (err < 0) {
return err;
}

*hasInterpreter = 1;

(*auxData)->a_type = AT_BASE;
(*auxData)->a_v = (u64)(ptr_t)baseAddr;
(*auxData)++;

return EOK;
}


int process_getInterpreterPath32(const Elf32_Ehdr *ehdr, const char **interpreterPath)
{
const Elf32_Phdr *phdrs = (const void *)ehdr + ehdr->e_phoff;
Expand Down Expand Up @@ -901,8 +1099,10 @@ int process_load(process_t *process, vm_object_t *o, off_t base, size_t size, vo

case ELFCLASS64:
*entry = (void *)(ptr_t)ehdr->e_entry;
err = process_load64(map, o, base, ehdr, size, &ustacksz, &tlsNew, &tbssAddr);
/* FIXME: loading interpreter on 64 bit ELFs is not supported */
err = process_load64(map, o, base, ehdr, size, &ustacksz, &tlsNew, &tbssAddr, auxData);
if (err == 0) {
err = process_loadInterpreter64(map, o, base, ehdr, size, entry, auxData, &process->hasInterpreter);
}
break;
default:
err = -ENOEXEC;
Expand Down

0 comments on commit 245decd

Please sign in to comment.