NixOS 24.11 breaks appimage-based game

Hi, does anyone have any pointers about what might’ve changed in NixOS 24.11 (vs 24.05) to cause an appimage-based game (Runelite, a custom client for Runescape) to no longer run?

I don’t have very many details about why it’s not working, it just exits after loading a little bit without printing anything meaningful to the console, but I do have a flake that builds vms reproducing the before/after states.

Thanks in advance.

If you can easily repro this in a VM, please perform a first-parent bisect from branch-off 24.05 to your current revision. That will tell you exactly what changed to break this which will likely lead us to a fix.

https://wiki.nixos.org/wiki/Bisecting

Thanks for the quick reply and good idea!

I bisected it, and it turns out it’s broken by: Merge pull request #329652 from dragano/expose-appimage-var · NixOS/nixpkgs@19178a0 · GitHub

It seems that Runelite relaunches itself with different JVM arguments. It has 3 “launch modes” to do the relaunch with. Two of those are JVM and FORK. Before it was using JVM, and now it’s using fork due to a check for the APPIMAGE environment variable. I’m not sure why the fork mode doesn’t work in NixOS.

This isn’t the first time Runelite has not worked on NixOS, I think last time (November 2023 per my discord messages with the maintainer) they had just added the JVM mode and it switched to using that from an older “reflect” mode. At that time the JVM mode was not working on NixOS, but it appears to now. At that time, I used a command-line argument to force it back to using “reflect” mode, and now I think I have to do the same, again using reflect mode because they explicitly deny using JVM mode when the APPIMAGE environment variable is set, despite it actually working now. Presumably the JVM mode doesn’t work when everything’s in a single appimage file, but appimage-run extracts it so it does work.

I think the whole concept of appimage-run extracting the appimage files manually and running without the runtime is flawed. To be the most accurate, we should setup an FHS env and run appimages in that…

2 Likes

Interesting but that doesn’t sound like it would be wrong.

“relaunch” in what way? Re-exec its binary within the appimage or the entire appimage?

The latter case would imply recursive appimage-run which I don’t know whether it’s possible.

Please propose something better; I really mean it.

That’s essentially what appimage-run does.

We need to unpack because appimages would otherwise require FUSE and we can’t allow that to work within user namespaces such as FHSEnvs because it’s a SUID wrapper and that could be abused to allow abitrary privilege escalation.


Btw, is there any particular reason you’re attempting to use the appimage when we have packaged this from source?

Depends on the launch mode, the “fork” launch mode does attempt to re-exec the entire appimage, and fails. The other launch modes do more java-specific stuff that works.

Ah you’re right, I see that now.

I think the “something better” would be expanding the FHS to work with FUSE as well. But I’m not an expert on user namespaces, is there a description somewhere of the security issues when using SUID root binaries in a user namespace? I did find this lwn article about a similar sounding issue, but that has supposedly been fixed. It also describes the issue as being caused by the fact that the SUID binary would load attacker-controlled code, in my mind that could be worked around by completely statically linking fusermount, but again, not an expert. Potentially additional restrictions would need to be added to fusermount, like only mounting to ~/.cache and asserting that there are no root-owned files or suid files in the AppImage.

Oh, I didn’t realize we had this packaged. That makes a lot of this thread moot, though I’d still be interested to hear your thoughts on a secure, more accurate appimage runtime.

The issue is that those binaries may use checks that depend on root-relative paths. Take for instance sudo which looks at /etc/sudoers. In a user namespace, that path can be modified by an unprivileged user of course, so they could just allow themselves to escalate privileges.

Except you can’t become root anyway because you’re still in a user namespace.