We currently only supported Variant II which is used by x86-64.
Variant I is used by both AArch64 (when using the traditional
non-TLSDESC model) and RISC-V, although with small differences.
The TLS layout for Variant I is essentially flipped. The static TLS
blocks are after the thread pointer for Variant I, while on Variant II
they are before it.
Some code using ELF TLS already worked on AArch64 and RISC-V even though
we only support Variant II. This is because only the local-exec model
directly uses TLS offsets, other models use relocations or
__tls_get_addr().
This removes the allocate_tls syscall and adds an archctl option to set
the fs_base for the current thread on x86-64, since you can't set that
register from userspace. enter_thread_context loads the fs_base for the
next thread on each context switch.
This also moves tpidr_el0 (the thread pointer register on AArch64) to
the register state, so it gets properly saved/restored on context
switches.
The userspace TLS allocation code is kept pretty similar to the original
kernel TLS code, aside from a couple of style changes.
We also have to add a new argument "tls_pointer" to
SC_create_thread_params, as we otherwise can't prevent race conditions
between setting the thread pointer register and signal handling code
that might be triggered before the thread pointer was set, which could
use TLS.
These changes are compatible with clang-format 16 and will be mandatory
when we eventually bump clang-format version. So, since there are no
real downsides, let's commit them now.
This works by defining a set of weak symbols in dynamic linker whose
value would be provided by it. This has the same effect as preloading
library that magically knows right addresses of functions shared between
dynamic linker and LibC.
We were previously passing the same information by rewriting values
based on hardcoded library name, so the new approach seems a little
nicer to me.
This commit un-deprecates DeprecatedString, and repurposes it as a byte
string.
As the null state has already been removed, there are no other
particularly hairy blockers in repurposing this type as a byte string
(what it _really_ is).
This commit is auto-generated:
$ xs=$(ack -l \bDeprecatedString\b\|deprecated_string AK Userland \
Meta Ports Ladybird Tests Kernel)
$ perl -pie 's/\bDeprecatedString\b/ByteString/g;
s/deprecated_string/byte_string/g' $xs
$ clang-format --style=file -i \
$(git diff --name-only | grep \.cpp\|\.h)
$ gn format $(git ls-files '*.gn' '*.gni')
The dynamic loader can't reasonably run static-pie ELF. static-pie ELFs
might run executable code that invokes syscalls outside of the defined
syscall memory executable (code) region security measure we implement.
Known examples of static-pie ELF objects are ELF packers, and the actual
system-provided dynamic loader itself.
We currently don't call any DT_FINI_ARRAY functions, so change that.
The call to `_fini` in `exit` is unnecessary, as we now call the
function referenced by DT_FINI in `__call_fini_functions`.
The arguments are passed on registers, so if we pass only 3 defined
arguments then the fourth argument for the prctl syscall could have
garbage value within it.
To avoid possible bugs, always pass 3 arguments to a raw syscall prctl
call in addition to the prctl sub-option (the first argument).
Once LibC is installed to the sysroot and its conflicts with libc++
are resolved, including LibC headers in such a way will cause errors
with a modern LLVM-based toolchain.
This class had slightly confusing semantics and the added weirdness
doesn't seem worth it just so we can say "." instead of "->" when
iterating over a vector of NNRPs.
This patch replaces NonnullRefPtrVector<T> with Vector<NNRP<T>>.
Instead of using a special case of the annotate_mapping syscall, let's
introduce a new prctl option to disallow further annotations of Regions
as new syscall Region(s).
To further protect all virtual memory regions of the loaded libraries,
don't allow to mutate these regions both in changing their annotations
nor the protection bits.
This syscall will be used later on to ensure we can declare virtual
memory mappings as immutable (which means that the underlying Region is
basically immutable for both future annotations or changing the
protection bits of it).
We have a new, improved string type coming up in AK (OOM aware, no null
state), and while it's going to use UTF-8, the name UTF8String is a
mouthful - so let's free up the String name by renaming the existing
class.
Making the old one have an annoying name will hopefully also help with
quick adoption :^)
Employ the same hardening that glibc and the Linux kernel use for
generating stack guards: zero the first byte of the guard such that
if C-style string functions read out of bounds on the stack, we do
not overwrite or potentially leak the stack guard.
We used size_t, which is a type that is guarenteed to be large
enough to hold an array index, but uintptr_t is designed to be used
to hold pointer values, which is the case of stack guards.
Both users of this function now have to do their resolving separately
before anyways, so let's just drop the resolving part inside the
function and require absolute paths to be fed in instead.
Having two functions that are named the same and whose behavior
regarding "should probably get a full path" and "does explicitly not
require a full path" is quite confusing, especially since that
difference is dictated through the other passed arguments.
Even though this almost certainly wouldn't run properly even if we had
a working kernel for AARCH64 this at least lets us build all the
userland binaries.
This adds a "temporary promises for the dynamic-linker" flag ('-d')
to the "pledge" utility.
Example usage:
pledge -d -p "stdio rpath" id
Without the '-d' flag, id would crash because the dynamic linker
requires 'prot_exec'.
When this flag is used and the program to be run is dynamically linked,
"pledge" adds promises that are required by the dynamic linker
to the promise set provided by the user.
The dynamic linker will later "give up" the pledge promises it no
longer requires.
This commit moves the length calculations out to be directly on the
StringView users. This is an important step towards the goal of removing
StringView(char const*), as it moves the responsibility of calculating
the size of the string to the user of the StringView (which will prevent
naive uses causing OOB access).
Once again, QEMU creates threads while running its constructors, which
is a recipe for disaster if we switch out the stack guard while that is
already running in the background.
To solve that, move initialization to our LibC initialization stage,
which is before any actual external initialization code runs.
This commit has no behavior changes.
In particular, this does not fix any of the wrong uses of the previous
default parameter (which used to be 'false', meaning "only replace the
first occurence in the string"). It simply replaces the default uses by
String::replace(..., ReplaceMode::FirstOnly), leaving them incorrect.
Previously we would just tightly pack the different libraries' TLS
segments together, but that is incorrect, as they might require some
kind of minimum alignment for their TLS base address.
We now plumb the required TLS segment alignment down to the TLS block
linear allocator and align the base address down to the appropriate
alignment.
The original heuristic of "a library being in `s_global_objects` means
that it was fully initialized already" doesn't hold up anymore since we
changed the loading order. This was causing us to skip parts of the
initialization of dependency libraries when running dlopen (since it was
the only user of that setting).
Instead, set a flag after we run stage 4 (which is the "run the global
initializers" stage) and check that flag when determining unfinished
dependencies. This entirely replaces the `skip_global_objects` logic.
We previously trusted the `map` part in `map_library` too much, and
assumed that this would already lock in the binary at its final place.
However, the `map()` function of the loader was only called in
`load_main_library`, which ran only right before jumping to the
entrypoint.
Make our binary loading a bit more stable by actually mapping the binary
right after we read its information, and only do the linking right
before jumping to the entrypoint.
Using the main executable basename produces the wrong $ORIGIN processing
for libraries that are secondary dependencies of the main executable,
or dependencies of an object loaded via dlopen.
IFUNC is a GNU extension to the ELF standard that allows a function to
have multiple implementations. A resolver function has to be called at
load time to choose the right one to use. The PLT will contain the entry
to the resolved function, so branching and more indirect jumps can be
avoided at run-time.
This mechanism is usually used when a routine can be made faster using
CPU features that are available in only some models, and a fallback
implementation has to exist for others.
We will use this feature to have two separate memset implementations for
CPUs with and without ERMS (Enhanced REP MOVSB/STOSB) support.