1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 11:38:11 +00:00

LibELF: Perform verification of TLS data in dlopen

When loading a library at runtime with dlopen(), we now check that:
1. The library's TLS size does not overflow the size of the allocated
TLS block.
2. The Library's TLS data is all zeroed.

We check for both of these cases because we currently do not support
them correctly. When we do add support for them, we can remove these
checks.
This commit is contained in:
Itamar 2021-04-30 15:04:08 +03:00 committed by Andreas Kling
parent 101ac45c1a
commit 7bd796b7e3

View file

@ -43,6 +43,7 @@ using DlIteratePhdrFunction = int (*)(DlIteratePhdrCallbackFunction, void*);
static size_t s_current_tls_offset = 0;
static size_t s_total_tls_size = 0;
static size_t s_allocated_tls_block_size = 0;
static char** s_envp = nullptr;
static LibCExitFunction s_libc_exit = nullptr;
static __pthread_mutex_t s_loader_lock = __PTHREAD_MUTEX_INITIALIZER;
@ -176,6 +177,8 @@ static void allocate_tls()
void* master_tls = ::allocate_tls((char*)initial_tls_data.data(), initial_tls_data.size());
VERIFY(master_tls != (void*)-1);
dbgln_if(DYNAMIC_LOAD_DEBUG, "from userspace, master_tls: {:p}", master_tls);
s_allocated_tls_block_size = initial_tls_data.size();
}
static int __dl_iterate_phdr(DlIteratePhdrCallbackFunction callback, void* data)
@ -326,6 +329,35 @@ static Result<void, DlErrorMessage> __dlclose(void* handle)
return {};
}
static Optional<DlErrorMessage> verify_tls_for_dlopen(const DynamicLoader& loader)
{
if (loader.tls_size_of_current_object() == 0)
return {};
if (s_total_tls_size + loader.tls_size_of_current_object() > s_allocated_tls_block_size)
return DlErrorMessage("TLS size too large");
bool tls_data_is_all_zero = true;
loader.image().for_each_program_header([&loader, &tls_data_is_all_zero](ELF::Image::ProgramHeader program_header) {
if (program_header.type() != PT_TLS)
return IterationDecision::Continue;
auto* tls_data = (const u8*)loader.image().base_address() + program_header.offset();
for (size_t i = 0; i < program_header.size_in_image(); ++i) {
if (tls_data[i] != 0) {
tls_data_is_all_zero = false;
break;
}
}
return IterationDecision::Break;
});
if (tls_data_is_all_zero)
return {};
return DlErrorMessage("Using dlopen() with libraries that have non-zeroed TLS is currently not supported");
}
static Result<void*, DlErrorMessage> __dlopen(const char* filename, int flags)
{
// FIXME: RTLD_NOW and RTLD_LOCAL are not supported
@ -355,6 +387,9 @@ static Result<void*, DlErrorMessage> __dlopen(const char* filename, int flags)
return result1.error();
}
if (auto error = verify_tls_for_dlopen(result1.value()); error.has_value())
return error.value();
auto result2 = map_dependencies(library_name);
if (result2.is_error()) {
return result2.error();
@ -364,6 +399,8 @@ static Result<void*, DlErrorMessage> __dlopen(const char* filename, int flags)
if (result.is_error())
return result.error();
s_total_tls_size += result1.value()->tls_size_of_current_object();
auto object = s_global_objects.get(library_name);
if (!object.has_value())
return DlErrorMessage { "Could not load ELF object." };