Skip to content

Commit

Permalink
rtdl: Return null from dlopen in case of invalid file
Browse files Browse the repository at this point in the history
  • Loading branch information
Qwinci committed Feb 16, 2024
1 parent 9e43aeb commit f3d190c
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 43 deletions.
9 changes: 5 additions & 4 deletions options/elf/include/elf.h
Original file line number Diff line number Diff line change
Expand Up @@ -572,12 +572,13 @@ typedef struct {
#define EM_PPC64 21
#define EM_S390 22
#define EM_ARM 40
#define EM_SH 42
#define EM_SPARCV9 43
#define EM_SH 42
#define EM_SPARCV9 43
#define EM_IA_64 50
#define EM_X86_64 62
#define EM_BLACKFIN 106
#define EM_AARCH64 183
#define EM_BLACKFIN 106
#define EM_AARCH64 183
#define EM_RISCV 243

/* Linux notes this value as being interim; however applications are using this (Qt6), so we define it here. */
#define EM_ALPHA 0x9026
Expand Down
3 changes: 2 additions & 1 deletion options/rtdl/aarch64/elf.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

#include <elf.h>

#define ELF_CLASS 64
#define ELF_CLASS ELFCLASS64
#define ELF_MACHINE EM_AARCH64

using elf_ehdr = Elf64_Ehdr;
using elf_phdr = Elf64_Phdr;
Expand Down
83 changes: 56 additions & 27 deletions options/rtdl/generic/linker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,23 +64,23 @@ size_t tlsMaxAlignment = 16;
// part of the global scope is considered for symbol resolution.
uint64_t rtsCounter = 2;

void seekOrDie(int fd, int64_t offset) {
bool trySeek(int fd, int64_t offset) {
off_t noff;
if(mlibc::sys_seek(fd, offset, SEEK_SET, &noff))
__ensure(!"sys_seek() failed");
return mlibc::sys_seek(fd, offset, SEEK_SET, &noff) == 0;
}

void readExactlyOrDie(int fd, void *data, size_t length) {
bool tryReadExactly(int fd, void *data, size_t length) {
size_t offset = 0;
while(offset < length) {
ssize_t chunk;
if(mlibc::sys_read(fd, reinterpret_cast<char *>(data) + offset,
length - offset, &chunk))
__ensure(!"sys_read() failed");
return false;
__ensure(chunk > 0);
offset += chunk;
}
__ensure(offset == length);
return true;
}

void closeOrDie(int fd) {
Expand Down Expand Up @@ -157,7 +157,7 @@ SharedObject *ObjectRepository::injectStaticObject(frg::string_view name,
return object;
}

SharedObject *ObjectRepository::requestObjectWithName(frg::string_view name,
frg::expected<LinkerError, SharedObject *> ObjectRepository::requestObjectWithName(frg::string_view name,
SharedObject *origin, Scope *localScope, bool createScope, uint64_t rts) {
if (auto obj = findLoadedObject(name))
return obj;
Expand Down Expand Up @@ -258,8 +258,12 @@ SharedObject *ObjectRepository::requestObjectWithName(frg::string_view name,
auto object = frg::construct<SharedObject>(getAllocator(),
name.data(), std::move(chosenPath), false, localScope, rts);

_fetchFromFile(object, fd);
auto result = _fetchFromFile(object, fd);
closeOrDie(fd);
if(!result) {
frg::destruct(getAllocator(), object);
return result.error();
}

_parseDynamic(object);

Expand All @@ -269,7 +273,7 @@ SharedObject *ObjectRepository::requestObjectWithName(frg::string_view name,
return object;
}

SharedObject *ObjectRepository::requestObjectAtPath(frg::string_view path,
frg::expected<LinkerError, SharedObject *> ObjectRepository::requestObjectAtPath(frg::string_view path,
Scope *localScope, bool createScope, uint64_t rts) {
// TODO: Support SONAME correctly.
auto lastSlash = path.find_last('/') + 1;
Expand All @@ -295,10 +299,16 @@ SharedObject *ObjectRepository::requestObjectAtPath(frg::string_view path,
frg::string<MemoryAllocator> no_prefix(getAllocator(), path);

int fd;
if(mlibc::sys_open((no_prefix + '\0').data(), O_RDONLY, 0, &fd))
return nullptr; // TODO: Free the SharedObject.
_fetchFromFile(object, fd);
if(mlibc::sys_open((no_prefix + '\0').data(), O_RDONLY, 0, &fd)) {
frg::destruct(getAllocator(), object);
return LinkerError::notFound;
}
auto result = _fetchFromFile(object, fd);
closeOrDie(fd);
if(!result) {
frg::destruct(getAllocator(), object);
return result.error();
}

_parseDynamic(object);

Expand Down Expand Up @@ -401,23 +411,38 @@ void ObjectRepository::_fetchFromPhdrs(SharedObject *object, void *phdr_pointer,
}


void ObjectRepository::_fetchFromFile(SharedObject *object, int fd) {
frg::expected<LinkerError, void> ObjectRepository::_fetchFromFile(SharedObject *object, int fd) {
__ensure(!object->isMainObject);

// read the elf file header
elf_ehdr ehdr;
readExactlyOrDie(fd, &ehdr, sizeof(elf_ehdr));
if(!tryReadExactly(fd, &ehdr, sizeof(elf_ehdr)))
return LinkerError::fileTooShort;

if(ehdr.e_ident[0] != 0x7F
|| ehdr.e_ident[1] != 'E'
|| ehdr.e_ident[2] != 'L'
|| ehdr.e_ident[3] != 'F')
return LinkerError::notElf;

__ensure(ehdr.e_ident[0] == 0x7F
&& ehdr.e_ident[1] == 'E'
&& ehdr.e_ident[2] == 'L'
&& ehdr.e_ident[3] == 'F');
__ensure(ehdr.e_type == ET_EXEC || ehdr.e_type == ET_DYN);
if((ehdr.e_type != ET_EXEC && ehdr.e_type != ET_DYN)
|| ehdr.e_machine != ELF_MACHINE
|| ehdr.e_ident[EI_CLASS] != ELF_CLASS)
return LinkerError::wrongElfType;

// read the elf program headers
auto phdr_buffer = (char *)getAllocator().allocate(ehdr.e_phnum * ehdr.e_phentsize);
seekOrDie(fd, ehdr.e_phoff);
readExactlyOrDie(fd, phdr_buffer, ehdr.e_phnum * ehdr.e_phentsize);
if(!phdr_buffer)
return LinkerError::outOfMemory;

if(!trySeek(fd, ehdr.e_phoff)) {
getAllocator().deallocate(phdr_buffer, ehdr.e_phnum * ehdr.e_phentsize);
return LinkerError::invalidProgramHeader;
}
if(!tryReadExactly(fd, phdr_buffer, ehdr.e_phnum * ehdr.e_phentsize)) {
getAllocator().deallocate(phdr_buffer, ehdr.e_phnum * ehdr.e_phentsize);
return LinkerError::invalidProgramHeader;
}

object->phdrPointer = phdr_buffer;
object->phdrCount = ehdr.e_phnum;
Expand Down Expand Up @@ -448,11 +473,13 @@ void ObjectRepository::_fetchFromFile(SharedObject *object, int fd) {
if (mlibc::sys_vm_map(nullptr,
highest_address - object->baseAddress, PROT_NONE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0, &mappedAddr)) {
mlibc::panicLogger() << "sys_vm_map failed when allocating address space for DSO \""
mlibc::infoLogger() << "sys_vm_map failed when allocating address space for DSO \""
<< object->name << "\""
<< ", base " << (void *)object->baseAddress
<< ", requested " << (highest_address - object->baseAddress) << " bytes"
<< frg::endlog;
getAllocator().deallocate(phdr_buffer, ehdr.e_phnum * ehdr.e_phentsize);
return LinkerError::outOfMemory;
}

object->baseAddress = reinterpret_cast<uintptr_t>(mappedAddr);
Expand Down Expand Up @@ -522,9 +549,9 @@ void ObjectRepository::_fetchFromFile(SharedObject *object, int fd) {
MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0, &map_pointer))
__ensure(!"sys_vm_map failed");

seekOrDie(fd, phdr->p_offset);
readExactlyOrDie(fd, reinterpret_cast<char *>(map_address) + misalign,
phdr->p_filesz);
__ensure(trySeek(fd, phdr->p_offset));
__ensure(tryReadExactly(fd, reinterpret_cast<char *>(map_address) + misalign,
phdr->p_filesz));
#endif
// Take care of removing superfluous permissions.
if(mlibc::sys_vm_protect && ((prot & PROT_WRITE) == 0))
Expand All @@ -551,6 +578,8 @@ void ObjectRepository::_fetchFromFile(SharedObject *object, int fd) {
<< frg::hex_fmt(phdr->p_type) << " in DSO " << object->name << frg::endlog;
}
}

return frg::success;
}

// --------------------------------------------------------
Expand Down Expand Up @@ -685,9 +714,9 @@ void ObjectRepository::_parseDynamic(SharedObject *object) {
object->preInitArraySize = dynamic->d_un.d_val;
break;
case DT_DEBUG:
#if ELF_CLASS == 32
#if ELF_CLASS == ELFCLASS32
dynamic->d_un.d_val = reinterpret_cast<Elf32_Word>(&globalDebugInterface);
#elif ELF_CLASS == 64
#elif ELF_CLASS == ELFCLASS64
dynamic->d_un.d_val = reinterpret_cast<Elf64_Xword>(&globalDebugInterface);
#endif
break;
Expand Down Expand Up @@ -743,7 +772,7 @@ void ObjectRepository::_discoverDependencies(SharedObject *object,
object, localScope, false, rts);
if(!library)
mlibc::panicLogger() << "Could not satisfy dependency " << library_str << frg::endlog;
object->dependencies.push(library);
object->dependencies.push(library.value());
}
}

Expand Down
17 changes: 14 additions & 3 deletions options/rtdl/generic/linker.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <frg/optional.hpp>
#include <frg/string.hpp>
#include <frg/vector.hpp>
#include <frg/expected.hpp>
#include <mlibc/allocator.hpp>
#include <mlibc/tcb.hpp>

Expand All @@ -21,6 +22,16 @@ enum class TlsModel {
dynamic
};

enum class LinkerError {
success,
notFound,
fileTooShort,
notElf,
wrongElfType,
outOfMemory,
invalidProgramHeader
};

// --------------------------------------------------------
// ObjectRepository
// --------------------------------------------------------
Expand Down Expand Up @@ -48,10 +59,10 @@ struct ObjectRepository {
size_t phdr_entry_size, size_t num_phdrs, void *entry_pointer,
uint64_t rts);

SharedObject *requestObjectWithName(frg::string_view name,
frg::expected<LinkerError, SharedObject *> requestObjectWithName(frg::string_view name,
SharedObject *origin, Scope *localScope, bool createScope, uint64_t rts);

SharedObject *requestObjectAtPath(frg::string_view path,
frg::expected<LinkerError, SharedObject *> requestObjectAtPath(frg::string_view path,
Scope *localScope, bool createScope, uint64_t rts);

SharedObject *findCaller(void *address);
Expand All @@ -65,7 +76,7 @@ struct ObjectRepository {
void _fetchFromPhdrs(SharedObject *object, void *phdr_pointer,
size_t phdr_entry_size, size_t num_phdrs, void *entry_pointer);

void _fetchFromFile(SharedObject *object, int fd);
frg::expected<LinkerError, void> _fetchFromFile(SharedObject *object, int fd);

void _parseDynamic(SharedObject *object);

Expand Down
31 changes: 26 additions & 5 deletions options/rtdl/generic/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ extern "C" void *lazyRelocate(SharedObject *object, unsigned int rel_index) {
auto symbol_index = ELF_R_SYM(reloc->r_info);

__ensure(type == R_X86_64_JUMP_SLOT);
__ensure(ELF_CLASS == 64);
__ensure(ELF_CLASS == ELFCLASS64);

auto symbol = (elf_sym *)(object->baseAddress + object->symbolTableOffset
+ symbol_index * sizeof(elf_sym));
Expand Down Expand Up @@ -543,6 +543,7 @@ void *__dlapi_open(const char *file, int flags, void *returnAddress) {
bool isGlobal = flags & RTLD_GLOBAL;
Scope *newScope = isGlobal ? globalScope.get() : nullptr;

frg::expected<LinkerError, SharedObject *> objectResult;
if (frg::string_view{file}.find_first('/') == size_t(-1)) {
// In order to know which RUNPATH / RPATH to process, we must find the calling object.
SharedObject *origin = initialRepository->findCaller(returnAddress);
Expand All @@ -551,15 +552,35 @@ void *__dlapi_open(const char *file, int flags, void *returnAddress) {
<< "(ra = " << returnAddress << ")" << frg::endlog;
}

object = initialRepository->requestObjectWithName(file, origin, newScope, !isGlobal, rts);
objectResult = initialRepository->requestObjectWithName(file, origin, newScope, !isGlobal, rts);
} else {
object = initialRepository->requestObjectAtPath(file, newScope, !isGlobal, rts);
objectResult = initialRepository->requestObjectAtPath(file, newScope, !isGlobal, rts);
}

if(!object) {
lastError = "Cannot locate requested DSO";
if(!objectResult) {
switch (objectResult.error()) {
case LinkerError::notFound:
lastError = "Cannot locate requested DSO";
break;
case LinkerError::fileTooShort:
lastError = "File too short";
break;
case LinkerError::notElf:
lastError = "File is not an ELF file";
break;
case LinkerError::wrongElfType:
lastError = "File has wrong ELF type";
break;
case LinkerError::outOfMemory:
lastError = "Out of memory";
break;
case LinkerError::invalidProgramHeader:
lastError = "File has invalid program header";
break;
}
return nullptr;
}
object = objectResult.value();

Loader linker{object->localScope, nullptr, false, rts};
linker.linkObjects(object);
Expand Down
3 changes: 2 additions & 1 deletion options/rtdl/riscv64/elf.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

#include <elf.h>

#define ELF_CLASS 64
#define ELF_CLASS ELFCLASS64
#define ELF_MACHINE EM_RISCV

using elf_ehdr = Elf64_Ehdr;
using elf_phdr = Elf64_Phdr;
Expand Down
3 changes: 2 additions & 1 deletion options/rtdl/x86/elf.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

#include <elf.h>

#define ELF_CLASS 32
#define ELF_CLASS ELFCLASS32
#define ELF_MACHINE EM_386

using elf_ehdr = Elf32_Ehdr;
using elf_phdr = Elf32_Phdr;
Expand Down
3 changes: 2 additions & 1 deletion options/rtdl/x86_64/elf.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

#include <elf.h>

#define ELF_CLASS 64
#define ELF_CLASS ELFCLASS64
#define ELF_MACHINE EM_X86_64

using elf_ehdr = Elf64_Ehdr;
using elf_phdr = Elf64_Phdr;
Expand Down

0 comments on commit f3d190c

Please sign in to comment.