kernel/elf: Use Deleters and get rid of gotos in elf_load_user_image.

Briefly tested: system boots and applications launch as before.
This commit is contained in:
Augustin Cavalier 2022-03-10 12:59:29 -05:00
parent 64a051399f
commit b6bfd9b749

View File

@ -37,6 +37,7 @@
#include <thread.h> #include <thread.h>
#include <runtime_loader.h> #include <runtime_loader.h>
#include <util/AutoLock.h> #include <util/AutoLock.h>
#include <StackOrHeapArray.h>
#include <vfs.h> #include <vfs.h>
#include <vm/vm.h> #include <vm/vm.h>
#include <vm/vm_types.h> #include <vm/vm_types.h>
@ -1826,21 +1827,16 @@ status_t
elf_load_user_image(const char *path, Team *team, uint32 flags, addr_t *entry) elf_load_user_image(const char *path, Team *team, uint32 flags, addr_t *entry)
{ {
elf_ehdr elfHeader; elf_ehdr elfHeader;
elf_phdr *programHeaders = NULL;
char baseName[B_OS_NAME_LENGTH]; char baseName[B_OS_NAME_LENGTH];
status_t status; status_t status;
ssize_t length; ssize_t length;
int fd;
int i;
addr_t delta = 0;
uint32 addressSpec = B_RANDOMIZED_BASE_ADDRESS;
area_id* mappedAreas = NULL;
TRACE(("elf_load: entry path '%s', team %p\n", path, team)); TRACE(("elf_load: entry path '%s', team %p\n", path, team));
fd = _kern_open(-1, path, O_RDONLY, 0); int fd = _kern_open(-1, path, O_RDONLY, 0);
if (fd < 0) if (fd < 0)
return fd; return fd;
FileDescriptorCloser fdCloser(fd);
struct stat st; struct stat st;
status = _kern_read_stat(fd, NULL, false, &st, sizeof(st)); status = _kern_read_stat(fd, NULL, false, &st, sizeof(st));
@ -1850,19 +1846,16 @@ elf_load_user_image(const char *path, Team *team, uint32 flags, addr_t *entry)
// read and verify the ELF header // read and verify the ELF header
length = _kern_read(fd, 0, &elfHeader, sizeof(elfHeader)); length = _kern_read(fd, 0, &elfHeader, sizeof(elfHeader));
if (length < B_OK) { if (length < B_OK)
status = length; return length;
goto error;
}
if (length != sizeof(elfHeader)) { if (length != sizeof(elfHeader)) {
// short read // short read
status = B_NOT_AN_EXECUTABLE; return B_NOT_AN_EXECUTABLE;
goto error;
} }
status = verify_eheader(&elfHeader); status = verify_eheader(&elfHeader);
if (status < B_OK) if (status < B_OK)
goto error; return status;
#ifdef ELF_LOAD_USER_IMAGE_TEST_EXECUTABLE #ifdef ELF_LOAD_USER_IMAGE_TEST_EXECUTABLE
if ((flags & ELF_LOAD_USER_IMAGE_TEST_EXECUTABLE) != 0) if ((flags & ELF_LOAD_USER_IMAGE_TEST_EXECUTABLE) != 0)
@ -1871,35 +1864,45 @@ elf_load_user_image(const char *path, Team *team, uint32 flags, addr_t *entry)
struct elf_image_info* image; struct elf_image_info* image;
image = create_image_struct(); image = create_image_struct();
if (image == NULL) { if (image == NULL)
status = B_NO_MEMORY; return B_NO_MEMORY;
goto error; CObjectDeleter<elf_image_info, void, delete_elf_image> imageDeleter(image);
}
struct ElfHeaderUnsetter {
ElfHeaderUnsetter(elf_image_info* image)
: fImage(image)
{
}
~ElfHeaderUnsetter()
{
fImage->elf_header = NULL;
}
elf_image_info* fImage;
} headerUnsetter(image);
image->elf_header = &elfHeader; image->elf_header = &elfHeader;
// read program header // read program header
programHeaders = (elf_phdr *)malloc( elf_phdr *programHeaders = (elf_phdr *)malloc(
elfHeader.e_phnum * elfHeader.e_phentsize); elfHeader.e_phnum * elfHeader.e_phentsize);
if (programHeaders == NULL) { if (programHeaders == NULL) {
dprintf("error allocating space for program headers\n"); dprintf("error allocating space for program headers\n");
status = B_NO_MEMORY; return B_NO_MEMORY;
goto error2;
} }
MemoryDeleter headersDeleter(programHeaders);
TRACE(("reading in program headers at 0x%lx, length 0x%x\n", TRACE(("reading in program headers at 0x%lx, length 0x%x\n",
elfHeader.e_phoff, elfHeader.e_phnum * elfHeader.e_phentsize)); elfHeader.e_phoff, elfHeader.e_phnum * elfHeader.e_phentsize));
length = _kern_read(fd, elfHeader.e_phoff, programHeaders, length = _kern_read(fd, elfHeader.e_phoff, programHeaders,
elfHeader.e_phnum * elfHeader.e_phentsize); elfHeader.e_phnum * elfHeader.e_phentsize);
if (length < B_OK) { if (length < B_OK) {
status = length;
dprintf("error reading in program headers\n"); dprintf("error reading in program headers\n");
goto error2; return length;
} }
if (length != elfHeader.e_phnum * elfHeader.e_phentsize) { if (length != elfHeader.e_phnum * elfHeader.e_phentsize) {
dprintf("short read while reading in program headers\n"); dprintf("short read while reading in program headers\n");
status = -1; return B_ERROR;
goto error2;
} }
// construct a nice name for the region we have to create below // construct a nice name for the region we have to create below
@ -1922,16 +1925,16 @@ elf_load_user_image(const char *path, Team *team, uint32 flags, addr_t *entry)
// map the program's segments into memory, initially with rw access // map the program's segments into memory, initially with rw access
// correct area protection will be set after relocation // correct area protection will be set after relocation
mappedAreas = (area_id*)malloc(sizeof(area_id) * elfHeader.e_phnum); BStackOrHeapArray<area_id, 8> mappedAreas(elfHeader.e_phnum);
if (mappedAreas == NULL) { if (!mappedAreas.IsValid())
status = B_NO_MEMORY; return B_NO_MEMORY;
goto error2;
}
extended_image_info imageInfo; extended_image_info imageInfo;
memset(&imageInfo, 0, sizeof(imageInfo)); memset(&imageInfo, 0, sizeof(imageInfo));
for (i = 0; i < elfHeader.e_phnum; i++) { addr_t delta = 0;
uint32 addressSpec = B_RANDOMIZED_BASE_ADDRESS;
for (int i = 0; i < elfHeader.e_phnum; i++) {
char regionName[B_OS_NAME_LENGTH]; char regionName[B_OS_NAME_LENGTH];
char *regionAddress; char *regionAddress;
char *originalRegionAddress; char *originalRegionAddress;
@ -1969,8 +1972,7 @@ elf_load_user_image(const char *path, Team *team, uint32 flags, addr_t *entry)
fd, ROUNDDOWN(programHeaders[i].p_offset, B_PAGE_SIZE)); fd, ROUNDDOWN(programHeaders[i].p_offset, B_PAGE_SIZE));
if (id < B_OK) { if (id < B_OK) {
dprintf("error mapping file data: %s!\n", strerror(id)); dprintf("error mapping file data: %s!\n", strerror(id));
status = B_NOT_AN_EXECUTABLE; return B_NOT_AN_EXECUTABLE;
goto error2;
} }
mappedAreas[i] = id; mappedAreas[i] = id;
@ -2010,8 +2012,7 @@ elf_load_user_image(const char *path, Team *team, uint32 flags, addr_t *entry)
&physicalRestrictions, (void**)&regionAddress); &physicalRestrictions, (void**)&regionAddress);
if (id < B_OK) { if (id < B_OK) {
dprintf("error allocating bss area: %s!\n", strerror(id)); dprintf("error allocating bss area: %s!\n", strerror(id));
status = B_NOT_AN_EXECUTABLE; return B_NOT_AN_EXECUTABLE;
goto error2;
} }
} }
} else { } else {
@ -2027,8 +2028,7 @@ elf_load_user_image(const char *path, Team *team, uint32 flags, addr_t *entry)
ROUNDDOWN(programHeaders[i].p_offset, B_PAGE_SIZE)); ROUNDDOWN(programHeaders[i].p_offset, B_PAGE_SIZE));
if (id < B_OK) { if (id < B_OK) {
dprintf("error mapping file text: %s!\n", strerror(id)); dprintf("error mapping file text: %s!\n", strerror(id));
status = B_NOT_AN_EXECUTABLE; return B_NOT_AN_EXECUTABLE;
goto error2;
} }
mappedAreas[i] = id; mappedAreas[i] = id;
@ -2054,17 +2054,21 @@ elf_load_user_image(const char *path, Team *team, uint32 flags, addr_t *entry)
set_ac(); set_ac();
status = elf_parse_dynamic_section(image); status = elf_parse_dynamic_section(image);
if (status != B_OK) if (status != B_OK) {
goto error2; clear_ac();
return status;
}
status = elf_relocate(image, image); status = elf_relocate(image, image);
if (status != B_OK) if (status != B_OK) {
goto error2; clear_ac();
return status;
}
clear_ac(); clear_ac();
// set correct area protection // set correct area protection
for (i = 0; i < elfHeader.e_phnum; i++) { for (int i = 0; i < elfHeader.e_phnum; i++) {
if (mappedAreas[i] == -1) if (mappedAreas[i] == -1)
continue; continue;
@ -2080,7 +2084,7 @@ elf_load_user_image(const char *path, Team *team, uint32 flags, addr_t *entry)
status = vm_set_area_protection(team->id, mappedAreas[i], protection, status = vm_set_area_protection(team->id, mappedAreas[i], protection,
true); true);
if (status != B_OK) if (status != B_OK)
goto error2; return status;
} }
// register the loaded image // register the loaded image
@ -2109,20 +2113,7 @@ elf_load_user_image(const char *path, Team *team, uint32 flags, addr_t *entry)
TRACE(("elf_load: done!\n")); TRACE(("elf_load: done!\n"));
*entry = elfHeader.e_entry + delta; *entry = elfHeader.e_entry + delta;
status = B_OK; return B_OK;
error2:
clear_ac();
free(mappedAreas);
image->elf_header = NULL;
delete_elf_image(image);
error:
free(programHeaders);
_kern_close(fd);
return status;
} }