-
Notifications
You must be signed in to change notification settings - Fork 122
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
FEXLoader: Fixes newer wine versions and Fedora #4082
Conversation
231b3a0
to
996f4d9
Compare
Could you add some concrete examples of what this PR is aiming to fix? From the description it's a bit difficult to reconstruct what exactly the problematic cases here are. (As a general suggestion, please avoid mixing in rants about |
b5d1cbc
to
d9a8309
Compare
The concrete example is that FEX initially needs the path fully resolved to actually load the application, but then we need to strip off the rootfs prefix (And NOT reapply it!). This fixes the logic inside of FileManagement with proc/self and syscalls so Wine can properly execute its subprocess applications.
Removed the sentence. |
As discussed externally, this is what's going on: OverviewWhen launching programs contained in the RootFS, FEX could previously report invalid program names to the guest (via /proc/self/exe and argv[0]) by double-prepending the RootFS path. This could produce paths like /home/ryanh/.fex-emu/RootFS/Ubuntu_24_04/home/ryanh/.fex-emu/RootFS/Ubuntu_24_04/usr/bin/winecfg. This could break programs like Wine that read /proc/self/exe to determine their installation path. To resolve the issue, FEX now consistently strips away the RootFS prefix from executable paths reported to the guest through /proc/self/exe and argv[0]. Implementation detailsFixes come from multiple places.
|
FWIW I rebased #3831 on top of this (which replaces one of the two commits there) and it works as intended, plus Proton is now working fine again too (that was due to a regression in #3831, not this PR). wine does need the symlink resolution fixes at least on Fedora though, so this PR is not sufficient to fix it (the title is a bit confusing). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reasonable change overall, just some comments to polish the implementation a little.
Source/Tools/FEXLoader/FEXLoader.cpp
Outdated
if (Program.ProgramPath.starts_with(LDPath())) { | ||
Program.ProgramPath = Program.ProgramPath.substr(LDPath().size()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any chance this will result in a relative path? If not, how is it prevented? It would probably be undesirable behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LDPath will never be relative, if it is then it's a configuration error and should be handled elsewhere.
By that definition then ProgramPath will never be relative when it starts with LDPath.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a chance we accidentally strip one '/' off to many, though? For example, does it make a difference if the user configures the RootFS as "/home/user/rootfsfolder/" vs "/home/user/rootfsfolder"?
Another possible failure path: Can the program paths end up containing "..", escaping the RootFS?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To clarify, I'm not concerned about LDPath being relative, but about the result of calling substr()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another possible failure path: Can the program paths end up containing "..", escaping the RootFS?
Probably, but this doesn't change any behaviour around that anyway. It'll be broken before and it'll be broken afterwards.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Slightly changed the code doing some more thorough testing, to ensure the beginning /
isn't stripped off.
d9a8309
to
776df1a
Compare
RootFSRedirect(&Program.ProgramPath, LDPath()); | ||
InterpreterHandler(&Program.ProgramPath, LDPath(), &Args); | ||
if (Program.ProgramPath.starts_with(LDPath())) { | ||
// From this point on, ProgramPath needs to not have the LDPath prefixed on to it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's probably better to move towards RootFS long-term since that's what every other place referring to that setting calls it.
BTW, is ProgramPath used for anything else (other than /proc/self/exe
and argv[0]
) after this point? Is removing the prefix the right choice for all other uses as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's probably better to move towards RootFS long-term since that's what every other place referring to that setting calls it.
A follow-up PR can be done to rename the variable names from LDPath
to RootFS
, there's a couple of places that can be hit at once.
Additional followup PR should be to rename APP_FILENAME
to APP_FILEPATH
because it's not the filename but the fully qualified guest path. But that should be independent.
BTW, is ProgramPath used for anything else (other than
/proc/self/exe
andargv[0]
) after this point? Is removing the prefix the right choice for all other uses as well?
- It also gets passed to the ELFCodeLoader, but it correctly handles the rootfs prefixing as necessary.
- It gets passed to seccomp, but only for a log.
- It gets passed to gdbserver, but only for removing the executable from the segment map for some reason?
- Probably something to check on later, won't really affect this.
17aa5b0
to
7217614
Compare
Reworked a bit of this and now it's less frenetic. Adding unittests for the argument parsing and ensuring the ProgramPath is always absolute if prefixed with the rootfs path. Will be good to get this in before release. |
7217614
to
a4e5a4c
Compare
Split this out so we can unittest it. Adds a unittest to handle specific edge cases.
This was brought up by FEX-Emu#3831 but I finally got the courage to look at the hard problem. Although I'm only tackling half of the problem with this PR, which is that FEXLoader needs to strip the rootfs path from the executed path if it begins with the rootfs, plus some changes to the surrounding code. The primary concern here is that when an application has been executed under FEX, specifically through binfmt_misc, then FEX needs to prepend the full rootfs path otherwise Linux can't find the program. Additionally execveat with an FD will resolve a full path to the rootfs. So past FEX's initial setup, we need to strip off the rootfs path to provide an "absolute" path that is visible to the guest application later. Which is kind of funny since we have a `RootFSRedirect` function which did the exact opposite. This was due to legacy problems in the original ELFLoader that couldn't handle symlinks correctly, which has since been resolved, so that no longer needs to exist. There was also some weirdness in `GetApplicationNames` where the passed in argument list was modifying Args[0] and then saving the Program as well. Which I just got rid of. Also stopped passing in the arguments by value because....why did I write it like that? In InterpreterHandler we now need to check if we can open the path inside the rootfs or fallback without it. Plus I had to change the shebang handling so it stopped prefixing the rootfs AGAIN. Took the time to change the shebang handling there so it stops creating string copies and instead just generates views. Overall this fixes a fairly major flaw with how we were representing `/proc/self` to the application, which was breaking wine since it would prefix the rootfs multiple times, which was weird. It doesn't address the remaining problem in FEX-Emu#3831, which is that applications can still see some of the leaky abstractions with symlinks through the rootfs, but I want to get at least this step in.
a4e5a4c
to
fe5bc02
Compare
Making noise. |
This was brought up by #3831 but I finally got the courage to look at the hard problem.
Although I'm only tackling half of the problem with this PR, which is that FEXLoader needs to strip the rootfs path from the executed path if it begins with the rootfs, plus some changes to the surrounding code.
The primary concern here is that when an application has been executed under FEX, specifically through binfmt_misc, then FEX needs to prepend the full rootfs path otherwise Linux can't find the program. Additionally execveat with an FD will resolve a full path to the rootfs.
So past FEX's initial setup, we need to strip off the rootfs path to provide an "absolute" path that is visible to the guest application later. Which is kind of funny since we have a
RootFSRedirect
function which did the exact opposite. This was due to legacy problems in the original ELFLoader that couldn't handle symlinks correctly, which has since been resolved, so that no longer needs to exist.There was also some weirdness in
GetApplicationNames
where the passed in argument list was modifying Args[0] and then saving the Program as well. Which I just got rid of. Also stopped passing in the arguments by value because....why did I write it like that?In InterpreterHandler we now need to check if we can open the path inside the rootfs or fallback without it. Plus I had to change the shebang handling so it stopped prefixing the rootfs AGAIN. Took the time to change the shebang handling there so it stops creating string copies and instead just generates views.
Overall this fixes a fairly major flaw with how we were representing
/proc/self
to the application, which was breaking wine since it would prefix the rootfs multiple times, which was weird.It doesn't address the remaining problem in #3831, which is that applications can still see some of the leaky abstractions with symlinks through the rootfs, but I want to get at least this step in.