Performance stats up front:
This improves pressure-vessel startup time on my test device by 10.1%
Improving the startup time from 9.71425 seconds to 8.7421 seconds.
Most filesystem based syscalls support a file descriptor version with an
*at suffix. This allows us to do these syscalls with pathnames that are
relative to the directory FD that is passed to the syscall.
This is pretty much exactly what we want when we are searching for files
inside of our rootfs. The only quirk ends up being that we are getting
passed absolute paths. This ends up being very simple to workaround by
stripping off the front '/' character. Doing this is just offsetting the
pointer passed to the syscall by one byte.
This does require having two temporary buffers of size PATH_MAX passed
to the handler since just like in the other implementation, we need to
keep the previous result around. The difference being now that we aren't
doing a bunch of std::string temporary manipulation and now we are
returning one of the passed in buffers back depending on the result.
This has been a long time coming. The C interface has been a thorn in
our side for no reason for a long time.
The purpose of this step is to remove the C interface without changing
behaviour as much as possible. This means that with this commit there
are still some bad practices but the remaining issues will be solved
with followup PRs.
Primarily, we still have a `DestroyContext(CTX)` static function which calls
the Context implementation's `DestroyContext` and does a raw C++ delete.
Follow up PR will remove that, but I didn't want to touch it yet since
it'll require checking to ensure the unique_ptr changes play nice with
our allocator hooking. Which this is already a huge PR without trying to
change behaviour.
When used in conjuction with #2345 this is a useful way to enable
libSegFault in applications using application profiles.
Very useful for applications and games that use launcher scripts that
set LD_PRELOAD to nothing prior to launch.
A user was wanting this.
VDSO behaves like a raw syscall which doesn't set errno.
posix tests are testing that errno is set correctly.
Our VDSO handlers weren't wired up to return errors from VDSO correctly.
To handle this we need to have different handlers depending on if the
syscall being used comes from glibc or true VDSO.
This wasn't being uncovered previously since CI wasn't running with VDSO
thunks enabled, but now that it is this needs to be handled or CI will
fail.
This fixes a bug where we are falling back down the default signal
delegator after a fatal error.
We need to reraise the event in the case that it didn't come from the
kernel.
Fixes backtrace crashing with incorrect signal when it tries to reraise
the signal that it handled using tgkill.
Fixes this file compiling on musl at least.
POLLREMOVE usage here is technically incorrect as it shouldn't be OR'd
with other flags.
But it is also additionally wrong here because the Linux kernel doesn't
even support this flag anymore, so it doesn't change behaviour.
Fixes#2356
In the case of the `-y` option being used, it will auto say "yes", but
when presented with the distro list this doesn't work. This happens when
used on a distro that doesn't have an exact match to what we provide.
Exposes a new option that when presented the distro list, auto select
the first option. Solving this issue when automating.
I made the assumption from some bad historical knowledge that the kernel
will canonicalize relative filenames and symlinks for applications that
execute through execve.
This turns out to not be true. In fact it passes pathname untouched to
the interpreter. So we need to do an additional fix up on relative paths
to ensure glibc doesn't break.
Fixes a major bug that breaks a bunch of games.
string::find() returns npos (-1) if the given character was not found, so
it can't be used to construct a string like this. Luckily, the use of
std::span allows this code to be written such that it's both correct and
simpler than before.
Somewhere during the refactoring/review process, failed to strip the
shebang prefix off of the arguments.
Causing shebang files to always fail as if the file never existed.
Fixes steam execution.
Fixes#2136
This is a fairly tricky edge case to support with FEX.
If execveat is used with AT_EMPTY_PATH then the application can pass an
FD to execve instead of a filename. This includes FDs that have been
deleted from the disk so the child process can't open it by filename
anymore.
To work around this limitation, we need to pass the FD to the new FEX
process and open it directly, similar to how binfmt_misc works with FDs.
The FD will get passed through environment variables, which the new
process will check for and then remove the variable from the
environment.
Lots of prickly edge cases to support here.
Without binfmt_misc:
- Passes the FD to FEXLoader directly.
- Requires duplicating the FD if it has O_CLOEXEC on the FD.
With binfmt_misc:
- Shebang file, pass directly to FEXLoader, just like without binfmt.
- x86 ELF Files, rely on the kernel's binfmt_misc support here.
- Unsupported ELF files, let kernel handle it through binfmt_misc
Argument handling:
- The application can pass in no arguments.
- Means our application configurations were failing to find a config
- Also various checks in the frontend were failing.
- If opened through an FD, find the symlink for that FD for the
application configuration instead.
Side note:
Fixed a performance issue in execve where when we were checking for file
format support. Either ELF or Shebang files, we were reading the /whole/
file upfront. We only need to read a header worth of ELF files, and only
257 bytes if it is potentially a shebang file. Should dramatically
reduce some application's execve times.
This is causing some heartburn with the hardlink.
- Removes some termux cmake list hacking.
- Removes the need to do post-install packaging fixups when hardlinks get dropped.
- Removes a custom uninstall target that was necessary before.
Fixes#2095
std::random_device can fail to find a random source and throw an assert
during initialization.
The constructor allows you to provide a token string to select an
explicit random source, but this is c++ library specific and will still
assert if the source isn't found. Also specific tokens are very much
target and library specific, so it is unsafe to use.
In the libstdc++ case, the default implementation will try to open
`/dev/urandom` which might not be available on all targets.
Instead of relying on this C++ object, use the `getrandom` syscall
directly to generate our RNG used in the ELFCodeLoader.
Resolves any sort of asserting case, blocks on RNG generation, and is
guaranteed to be available since this syscall has been available since a
very old kernel version.
On first FEXInterpreter execution, it is expected that `ConnectToServer`
will fail with `ECONNREFUSED` because FEXServer won't be running.
Skip printing this first messaage to stderr if configured.
If it is some other error message then ensure it is still printed.
`GetEmulatedPath` and `OpenAt` are called a /lot/ in applications.
std::filesystem::path handling here is quite heavy and costly for what
we are trying to achieve.
Remove this usage and instead use lstat, access, and readlink directly
which is a heck of a lot faster.
In particular this helps out pressure-vessel, shaving off launch times
by 1-2 seconds.
Going from ~22 seconds down to ~20 seconds.
`std::filesystem::exists` is particularly gnarly in how it checks to see
if the file exists.
It allocates memory, it creates lists, it splits things, then eventually
checking the status
Remove all this overhead to help out minorly for applications that
execve a lot.
Two changes here.
- Make the mount path follow server temp folder requirements.
- Will be mounted in `/tmp/` or `$XDG_RUNTIME_DIR/` now
- Switch the FEXServer socket to an "abstract" AF_UNIX socket.
- If the socket is in `/tmp/` then systemd will put the service in a
private `/tmp` folder that only exists for the service.
- If the socket is in `$XDG_RUNTIME_DIR` then pressure-vessel can't
chroot anymore since they make their own runtime directory.
- If it is in `$HOME/.fex-emu/` then it breaks usage where the
filesystem is a mount that doesn't support AF_UNIX like sshfs.
The only reasonable thing to do is to switch over to `abstract` sockets
which will work in all cases.
Tested with pressure-vessel and systemd and now it works in all
situations.