AppImageCrafters / appimage-builder

GNU/Linux packaging solution using the AppImage format
MIT License
309 stars 58 forks source link

AppImage built with webkit2gtk dependencies cannot start on non-Ubuntu distributions #175

Open k-kirill opened 2 years ago

k-kirill commented 2 years ago

The issue is described in eneshecan/whatsapp-for-linux#160. Here is just the error:

<13>Jan 21 23:42:13 whatsapp-for-linux[7682]: ** (whatsapp-for-linux:7676): ERROR **: 23:42:13.184: Unable to spawn a new child process: Failed to execute child process “/usr/lib/x86_64-linux-gnu/webkit2gtk-4.0/WebKitNetworkProcess” (No such file or directory)

This is a fix for the issue in another framework that supports building AppImage binaries: tauri-apps/tauri#2940

Thanks!

azubieta commented 2 years ago

We have runtime path mappings in appimage-builder, you could try to use them to fix the issue. In case of success please let me know to add it to the gtk helper.

path mappings reference: https://appimage-builder.readthedocs.io/en/latest/reference/version_1.html#runtime

AlexTMjugador commented 1 year ago

I'm developing an application that depends on WebKitGTK and I've stumbled upon this issue. Setting path mappings does like this in the recipe file does not work:

    path_mappings:
      - /usr/lib/x86_64-linux-gnu/webkit2gtk-4.0:$APPDIR/usr/lib/x86_64-linux-gnu/webkit2gtk-4.0

After reading the AppRun and WebKitGTK source code, in addition to testing on my Linux box by breaking WebKitGTK on purpose by running sudo mv /usr/lib/x86_64-linux-gnu/webkit2gtk-4.0/WebKitWebProcess /usr/lib/x86_64-linux-gnu/webkit2gtk-4.0/.WebKitWebProcess (this is a terrible thing to do, please don't copy and paste this command), I've arrived at the following conclusions:

    // Warning: we want GIO to be able to spawn with posix_spawn() rather than fork()/exec(), in
    // order to better accommodate applications that use a huge amount of memory or address space
    // in the UI process, like Eclipse. This means we must use GSubprocess in a manner that follows
    // the rules documented in g_spawn_async_with_pipes_and_fds() for choosing between posix_spawn()
    // (optimized/ideal codepath) vs. fork()/exec() (fallback codepath). As of GLib 2.74, the rules
    // relevant to GSubprocess are (a) must inherit fds, (b) must not search path from envp, and (c)
    // must not use a child setup fuction.
    //
    // Please keep this comment in sync with the duplicate comment in XDGDBusProxy::launch.
    GRefPtr<GSubprocessLauncher> launcher = adoptGRef(g_subprocess_launcher_new(G_SUBPROCESS_FLAGS_INHERIT_FDS));
    g_subprocess_launcher_take_fd(launcher.get(), socketPair.client, socketPair.client);

(From the webkitgtk-2.38.2 release, file WebKit/UIProcess/Launcher/glib/ProcessLauncherGLib.cpp)

I don't know what the rationale of the WebKitGTK team was to lock down the WEBKIT_EXEC_PATH environment variable behind a developer mode flag (if an attacker can set arbitrary environment variables, can't it already change the behavior of the dynamic linker and/or the WebKit binary itself to run malicious code?), but the only feasible way I can see to deal with this is to do what Tauri did in the linked issue and binary-patch the strings embedded in the libraries. Or patch AppRun to hook the process spawning calls, but I'm not sure how feasible is that to do.

The main problem with Tauri's approach is that I've tested it, and it doesn't work for appimage-builder as-is. Tauri's solution replaces the offending /usr path prefix by ././, so it probably relies on the working directory being set to some value that differs in appimage-builder:

$ LC_ALL=C ../../target/appimage/PackSquash\ \(GUI\)-v0.3.1-333-g86df839-custom-x86_64.AppImage
Gtk-Message: 20:36:37.367: Failed to load module "colorreload-gtk-module"
Gtk-Message: 20:36:37.373: Failed to load module "window-decorations-gtk-module"

** (packsquash-gui:28576): ERROR **: 20:36:37.826: Unable to spawn a new child process: Failed to spawn child process ?././/lib/x86_64-linux-gnu/webkit2gtk-4.0/WebKitNetworkProcess? (No such file or directory)
[1]    28576 trace trap  LC_ALL=C

For completeness and reference purposes, this is the relevant script that Tauri uses to generate the AppDir and patch the WebKitGTK binaries.

Edit: I found out the rationale for WEBKIT_EXEC_PATH being only honored on development builds. Some WebKit developer thought on 2014 that environment variable was only useful for "internal tools and tests", and decided to gate it behind that flag, with the approval of another developer. Clearly they didn't have AppImages in mind :sweat_smile:

Edit 2: oddly enough, when mounting the AppImage with --appimage-mount and trying to run the offending WebKit processes from a terminal, I'm also greeted with a "No such file or directory" error, despite the file being there and having execute permission. Perhaps it's necessary to tweak some ELF loader bits too?

Edit 3: the error I mentioned on "Edit 2" was caused due to appimage-builder relativizing the path to the dynamic link interpreter to lib64/ld-linux-x86-64.so.2. Switching the working directory to the runtime directory within the AppImage filesystem worked. This suggests that maybe Tauri's workaround is okay, but the missing piece is getting the spawned process to use the dynamic linker embedded in the AppImage.


Sadly, all of this means that AppImages containing applications that depend on WebKitGTK don't work properly, relying on WebKitGTK binaries to be present in the target system. I hope that my thorough description at least is useful to give more insight on what's going on and possible ways to tackle it.

AlexTMjugador commented 1 year ago

@azubieta I'd love to tackle this issue on appimage-builder some day. Would you mind sharing tips and other interesting tidbits of information about the topic that may help making a contribution?

andrewda commented 1 year ago

@AlexTMjugador I'm running into the same problem and have come to a similar conclusion -- great writeup! I'd love to help out with fixing this issue.

The main problem with Tauri's approach is that I've tested it, and it doesn't work for appimage-builder as-is. Tauri's solution replaces the offending /usr path prefix by ././, so it probably relies on the working directory being set to some value that differs in appimage-builder.

I'm curious how you tested this with appimage-builder. Could you share your process or patch? I'd love to try something similar on my end and play around with getting something to work.

AlexTMjugador commented 1 year ago

@andrewda I'm glad my writeup was helpful!

I'm curious how you tested this with appimage-builder. Could you share your process or patch? I'd love to try something similar on my end and play around with getting something to work.

Sure! I just used an after_bundle script, inspired by Tauri's scripts.