Skip to content
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

Flatpak Electron App Throws Error With libhardened_malloc.so #193

Closed
czhang03 opened this issue Jan 30, 2024 · 21 comments
Closed

Flatpak Electron App Throws Error With libhardened_malloc.so #193

czhang03 opened this issue Jan 30, 2024 · 21 comments

Comments

@czhang03
Copy link
Contributor

I have tested several flatpak electron apps, including Signal, Slack, Freetube, all of them seems to give the following error:

ERROR: ld.so: object '/var/run/host/usr/lib64/libhardened_malloc.so' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored.

This error does not appear in app in other framework, like fsearch, syncthingy, or gnome core app. Native apps like codium and chormium also don't have this issue.

Example command:

flatpak run org.signal.Signal --filesystem=host-os:ro

My signal is running xwayland and slack is running in wayland, yet both of them raise the same error, so I don't think it is a wayland issue.

I don't know if this can be reproduced on other systems.


Deployment info (rpm-ostree status):

  ostree-image-signed:docker://ghcr.io/secureblue/silverblue-main-laptop-userns-hardened:latest
                   Digest: ...
                  Version: 39.20240130.0 (2024-01-30T18:19:08Z)
          LayeredPackages: ...
                Initramfs: regenerate

... represents unrelated information.

@qoijjj
Copy link
Collaborator

qoijjj commented Jan 31, 2024

I've seen this as well. I'm almost certain it's something to do with the combination of flatpak and electron, as you've mentioned. I'm not exactly sure why it happens, but my guess is that it's something to do with the way electron handles environment variables for child processes.

When we set LD_PRELOAD in ld.so.preload, it applies to all processes (aside from flatpaks). So when an electron app like codium creates child processes, it applies to those as well.

For flatpak however, my hunch is that the environment variable is being sent to the initial process, but subsequent child processes aren't being spawned with the same environment variable.

@boredsquirrel
Copy link

boredsquirrel commented Feb 4, 2024

~ ❯❯❯ flatpak run --filesystem=host-os:ro --command=signal-desktop org.signal.Signal 
Debug: Will run signal with the following arguments: --enable-features=WaylandWindowDecorations --ozone-platform=wayland
Debug: Additionally, user gave: 

<--- Last few GCs --->

[2:0x3e28004c8000]      130 ms: Mark-Compact (reduce) 0.7 (3.2) -> 0.7 (1.9) MB, 2.67 / 0.00 ms  (average mu = 0.477, current mu = 0.018) last resort; GC in old space requested
[2:0x3e28004c8000]      131 ms: Mark-Compact (reduce) 0.7 (1.9) -> 0.7 (1.9) MB, 1.36 / 0.00 ms  (average mu = 0.350, current mu = 0.012) last resort; GC in old space requested


<--- JS stacktrace --->


#
# Fatal JavaScript out of memory: CALL_AND_RETRY_LAST

but now after manually adding xdg-host-os readonly in KDE Flatpak settings it works!

~ ❯❯❯ flatpak run --filesystem=host-os:ro --command=signal-desktop org.signal.Signal                                                                                                   ✘ 133
Debug: Will run signal with the following arguments: --enable-features=WaylandWindowDecorations --ozone-platform=wayland
Debug: Additionally, user gave: 
Set Windows Application User Model ID (AUMID) { AUMID: 'org.whispersystems.signal-desktop' }
NODE_ENV production
NODE_CONFIG_DIR /app/Signal/resources/app.asar/config
NODE_CONFIG {}
ALLOW_CONFIG_MUTATIONS undefined
HOSTNAME undefined
NODE_APP_INSTANCE undefined
SUPPRESS_NO_CONFIG_WARNING undefined
SIGNAL_ENABLE_HTTP undefined
userData: /var/home/user/.var/app/org.signal.Signal/config/Signal
config/get: Successfully read user config file
config/get: Successfully read ephemeral config file
making app single instance
LaunchProcess: failed to execvp:
xdg-settings
LaunchProcess: failed to execvp:
xdg-settings

I have the feeling the problem is this temporary override. Will the overrides be for all apps, or just the ones installed when yafti is executed?

@qoijjj
Copy link
Collaborator

qoijjj commented Feb 4, 2024

@trytomakeyouprivate very interesting, maybe we need to override xdg-host-os instead of host-os. Can you confirm that signal is running with hardened_malloc in the second one by posting both the output of top and the output of cat /proc/$procId/maps | grep hardened

@qoijjj
Copy link
Collaborator

qoijjj commented Feb 5, 2024

@trytomakeyouprivate I tried an xdg-host-os override and it didn't change anything.

@boredsquirrel
Copy link

boredsquirrel commented Feb 6, 2024

strange...

using hardened_malloc:

30814 pts/1    S+     0:00 /usr/bin/bwrap --args 38 signal-desktop
30826 pts/1    S+     0:00 /usr/bin/bwrap --args 38 signal-desktop

not using hardened_malloc:

30827 pts/1    SLl+   0:08 /app/Signal/signal-desktop --enable-features=WaylandWindowDecorations --ozone-platform=wayland
30839 pts/1    S+     0:00 /app/Signal/signal-desktop --type=zygote --no-zygote-sandbox
30892 pts/1    Sl+    0:00 /app/Signal/signal-desktop --type=gpu-process --ozone-platform=wayland [and a lot more parameters]
30904 pts/1    Sl+    0:00 /app/Signal/signal-desktop --type=utility --utility-sub-type=network.mojom.NetworkService
30937 pts/1    Sl+    0:17 /app/Signal/signal-desktop --type=renderer --enable-crash-reporter=[...]

So it looks like Electron apps are going to be fun...

To be honest I think this is an Electron issue. On Android its is a single webview which is hardened, on Linux it is not even hardened. I guess it would be best to make flatpaks for those commonly used apps including hardened_malloc and a hardened Electron. This sounds like quite some work though.

Those Flatpaks would work anywhere though, and follow the idea of not depending on the OS for libraries.

@thestinger
Copy link

You could eliminate some of these issues by building hardened_malloc into glibc as the default allocator with an extended attribute set on the executable for disabling it which is read inside libc and used to select the standard glibc allocator instead. That's essentially the approach we use ourselves, although we hard-wire the few rare cases of exceptions of the base OS and apps are handled more dynamically via a user-facing toggle integrated into the UI.

LD_PRELOAD adds some complexity and glibc's implementation of replacing the allocator isn't 100% complete and has some rare edge cases where applications do weird things with dynamic linking where it won't properly work and will cause a crash.

@thestinger
Copy link

@trytomakeyouprivate Since Android provides a standard OS WebView that's kept up-to-date, very few apps bundle their own web browser engine. That means they get an updated one that the OS is able to harden. On GrapheneOS, that allows us to use CFI, MTE, etc. for the web rendering engine used by all these apps. Chromium doesn't really use the system malloc in practice so hardened_malloc doesn't really do much for it. Android WebView currently doesn't have fine-grained isolation but it does at least provide an overall content sandbox separate from the app itself comparable to the browser sandbox. It doesn't currently sandbox separate content used simultaneously by the app in separate OS sandboxes but it's planned upstream and we can enable it early.

Windows has WebView2 based on Edge (Chromium) but it's relatively new and would mainly be used by new Windows-only applications. Most of these desktop apps are using web content to be cross-platform across Windows, macOS and desktop Linux so they aren't going to use an OS specific WebView API. There's not going to be cooperation on this between Windows and macOS or even across desktop Linux distributions. Desktop Linux alone has a bunch of fragmented options, mostly badly maintained and they repeatedly get replaced in backwards incompatible ways. Android has always had the same WebView API evolving and gaining new features which became based on proper Chromium shipped with the OS browser over a decade ago.

Electron massively rolls back Chromium security, breaks the sandbox and is a regularly backwards incompatible library used by applications so there's a huge mess created by it. Android WebView preserves compatibility to the same extent as Chromium does for the web, which is to say that essentially nothing breaks even after a decade if you don't do anything stupid. Rare apps do stupid enough stuff to break on Chromium updates, but it's generally easy for them to fix it. It's essentially just the same as the web since the Android WebView adds very minimal API surface beyond standard Chromium. It has a tiny set of APIs for configuring it, executing JS, adding JavaScript interfaces from Java/Kotlin, intercepting network requests to replace them and do content filtering along with interoperability with APK assets (asset:), content providers (content:) and direct file access (file:). It's dramatically simpler than Electron since it makes no attempt to provide a full application API. It's only a sandboxed web content renderer with interoperability with the rest of the app code. Electron is for writing a whole application while the WebView is for putting web content in an app, although you can provide all the APIs you need to the WebView and write your whole app in it. Still, that avoids the WebView having complex APIs since the developer and the libraries they use would be defining any of that. Electron is a huge mess, as are most alternatives. WebView2 on Windows is reasonable, if only it wasn't Windows-specific and stuff actually used it.

@thestinger
Copy link

Electron also breaks Content-Security-Policy and other things. Signal being an Electron app without Trusted Types turns it into a huge mess of XSS vulnerabilities. It was way less bad when it was still a Chrome app and moving to Electron to keep it alive with the end of Chrome apps while not turning it into a web app (due to E2EE) was a massive security regression for them.

@qoijjj
Copy link
Collaborator

qoijjj commented Feb 20, 2024

You could eliminate some of these issues by building hardened_malloc into glibc as the default allocator

That's almost certainly the right way forward here, since there's zero chance of that ever happening in upstream Fedora's glibc. However, I'd expect it to be significantly more effort to maintain than the current setup of just throwing hardened_malloc into LD_PRELOAD. So it'll be something we need to work on over time.

Electron massively rolls back Chromium security, breaks the sandbox and is a regularly backwards incompatible library used by applications so there's a huge mess created by it.

Yep, I think the right move here with regards to the topic of this ticket specifically is to discourage users from using electron at all if possible. Fortunately there are often alternatives to using electron apps:

  • Signal should be used only on your phone
  • Slack can be used from within the browser
  • VSCode can be used from within the browser
  • There are numerous alternatives to Freetube like Piped, Invidious, or just playing youtube links in mpv
  • and so on...

@qoijjj
Copy link
Collaborator

qoijjj commented Feb 20, 2024

14402a6

@qoijjj qoijjj closed this as completed Feb 20, 2024
@qoijjj qoijjj closed this as not planned Won't fix, can't repro, duplicate, stale Feb 20, 2024
@boredsquirrel
Copy link

boredsquirrel commented Feb 21, 2024

to add some more:

  • Element: Fractal, Neochat, (GNOME Chats), nheko
  • Signal: (but Devs say themselves that its probably less secure)
  • Discord: use Browser to comply with TOS
  • Telegram uses Qt

@qoijjj
Copy link
Collaborator

qoijjj commented Feb 21, 2024

Adding some notes for the sake of documentation:

Fractal, Neochat, (GNOME Chats), nheko

These are all matrix client alternatives to element I believe, however they add an additional trusted entity so Element Web should be recommended.

Flare

I don't think it's responsible to recommend anything aside from Signal itself, on a mobile device

Discord: QTCord, gtkcord4 (or Browser)

Browser is probably best here to avoid both electron and violating discord TOS

Telegram: 64Gram, (cutegram, sigram, tdesktop-lite are all abandoned)

I'm not familiar with 64Gram or the Telegram Desktop app (is it electron?), but I believe it has a browser version so that's probably preferable anyways.

@kremzli
Copy link

kremzli commented Feb 21, 2024

Telegram desktop is QT

@boredsquirrel
Copy link

Updated my comment. This would be another usecase of some app recommendation text. Not like "I recommend this and if there is an issue it is my problem" but simply "you should avoid using electron, to our knowledge these apps follow best practices"

https://github.com/trytomakeyouprivate/Recommended-Flatpak-Apps

this list is probably incomplete and may have mistakes in it.

@jermanuts
Copy link

jermanuts commented Mar 27, 2024

These are all matrix client alternatives to element I believe, however they add an additional trusted entity so Element Web should be recommended.

I wouldn't trust a web app to handle cryptography, Element Desktop might be an improvement but it is Electron webapp.

https://www.devever.net/~hl/webcrypto

Web-based cryptography is always snake oil

@qoijjj
Copy link
Collaborator

qoijjj commented Mar 27, 2024

https://www.devever.net/~hl/webcrypto

This article is full of nonsense and doesn't even back up your statement about webapps.

Element Desktop might be an improvement

According to the article you linked, it wouldn't be.

the code which implements a client-side web application is distributed by the given website. Thus the client-side code is always distributed by the operator of the web server.

This is not unique to webapps. Signal distributes client side code in the form of android and iOS apps, and they also operate the servers for signal's backend.

Also, this is ultimately just a critique pointing to the need for reproducible builds for FOSS software, which is in no way unique to FOSS webapps.

if the server operator was malicious, they could just push different client-side JavaScript.

If Signal was malicious, they could push different client-side mobile apps 🙂

Later on, the article conflates webapps with web-based:

In this regard all web-based “E2E” cryptography can be regarded as backdoored, as can Whatsapp, Signal, etc.

What the hell kind of end to end crypto do you want? End to end crypto over physical mail?

The article also refers to Signal as proprietary: offered by Whatsapp and Signal, amongst other proprietary services,?

There is one kernel of truth in the article, and that is that FOSS software generally lacks a consistent and ubiquitous mechanism to verify that the software you're running was built from the source you're reading. But this isn't unique to FOSS software distributed by the same owner of the corresponding web services. The exact same problem exists if the client side software is distributed by someone else (i.e. third party clients). The article takes a widespread problem with all FOSS, narrows it down to a small subset of cases without warrant, and then cries wolf.

@jermanuts
Copy link

jermanuts commented Mar 27, 2024

If Signal was malicious, they could push different client-side mobile apps

How? They would need to upload a malicious update to all their users from their app store, they can't target anyone specifically silently like it is possible with web apps.

this blog goes more in details and concise: https://cronokirby.com/posts/2021/06/e2e_in_the_browser/

@qoijjj
Copy link
Collaborator

qoijjj commented Mar 27, 2024

If Signal was malicious, they could push different client-side mobile apps

How? They would need to upload a malicious update to all their users from their app store, they can't target anyone specifically silently like it is possible with web apps.

The blog you linked points out that signal isn't exempt from their critique

In this regard all web-based “E2E” cryptography can be regarded as backdoored, as can Whatsapp, Signal, etc.

Mobile apps can and do receive and run client side updates at runtime.

this blog goes more in details and concise: https://cronokirby.com/posts/2021/06/e2e_in_the_browser/

Contrast this with a native application. Once it’s installed, you can choose whether or not you want to update it, and wait until other people have vetted a new version.

How do you know the native app is actually only running native code? What if it's pulling and running js? The whole point of concern, as I already stated, comes back to not having reproducible builds, which is a genuine issue. It's just not at all specific to webapps.

The author also says this:

This makes sure that you’re downloading a version of an application approved by the developers

while simultaneously saying that the issue with webapps is that we can't trust the provider:

you need to trust the providers of the application to not have done anything fishy.
Trusting a signed build means trusting that the developers didn't do anything fishy.

Another advantage of this release model is that it prevents targeted attacks.

Again this is simply untrue. Many companies like Facebook openly do flighting campaigns and run different application code on different users' phones, even when they have the same version installed.

So you've linked another blog that covers up the same kernel of truth with nonsense and contradictory statements, instead of actually addressing my comments.

You need to read this:
https://www.cs.cmu.edu/~rdriley/487/papers/Thompson_1984_ReflectionsonTrustingTrust.pdf

Please make more well-evidenced comments if you're going to make claims like this.

@jermanuts
Copy link

jermanuts commented Mar 27, 2024

How do you know the native app is actually only running native code? What if it's pulling and running js?

By checking the code? You gave an example of a terrible closed source app (Facebook) as an example https://techcrunch.com/2024/03/26/facebook-secret-project-snooped-snapchat-user-traffic/

You need to read this: https://www.cs.cmu.edu/~rdriley/487/papers/Thompson_1984_ReflectionsonTrustingTrust.pdf

I'm aware of this paper, guix recently published this blog post.

https://guix.gnu.org/en/blog/2024/identifying-software/

Full-Source Bootstrap

Reproducible builds alone cannot ensure the source-to-binary correspondence: the compiler could contain a backdoor, as demonstrated by Ken Thompson in Reflections on Trusting Trust. To address that, Guix goes further by implementing so-called full-source bootstrap: for the first time, literally every package in the distribution is built from source code, starting from a very small binary seed. This gives an unprecedented level of transparency, allowing code to be audited at all levels, and improving robustness against the “trusting-trust attack” described by Ken Thompson.

Edit:

while simultaneously saying that the issue with webapps is that we can't trust the provider:

Yes. Because you will always have to trust them with serving you a non-backdoored client from their server, unlike native apps where you have client code available with less trust from the server.

@qoijjj
Copy link
Collaborator

qoijjj commented Mar 27, 2024

By checking the code?

Back to the reproducible issue.

starting from a very small binary seed. This gives an unprecedented level of transparency, allowing code to be audited at all levels, and improving robustness
I'm aware of this paper

And yet it seems you've not internalized it. The blog post from guix further highlights my point that this is a broad issue not specific to webapps.

@qoijjj
Copy link
Collaborator

qoijjj commented Mar 27, 2024

unlike native apps where you have client code available with less trust from the server.

again this is not true and comes back to reproducible builds. you only know that native apps are only running native code if you can reproduce the build.

I'm going to lock this post shortly as it's wildly offtopic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants