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

fuse: failed to exec fusermount: Permission denied #15

Open
avently opened this issue Sep 4, 2023 · 29 comments
Open

fuse: failed to exec fusermount: Permission denied #15

avently opened this issue Sep 4, 2023 · 29 comments
Labels
bug Something isn't working

Comments

@avently
Copy link

avently commented Sep 4, 2023

Hello. We have an issue with the error mentioned in the title: simplex-chat/simplex-chat#3009

$ ./simplex-desktop-x86_64.AppImage --appimage-mount
fuse: failed to exec fusermount: Permission denied

Cannot mount AppImage, please check your FUSE setup.
You might still be able to extract the contents of this AppImage
if you run it with the --appimage-extract option.
See https://github.com/AppImage/AppImageKit/wiki/FUSE
for more information
open dir error: No such file or directory

By looking deeply in the situation, @tsjk found what difference we have in our Linux distributions.
In my case on Archlinux I have 4755 permission on the file /bin/fusermount.
He has 4711 permission on the same file in Gentoo.

When he set 4755 permission, the app can now be launched without the issue.

I see that in the code runtime tries to find fusermount binary:

+ if (access(prog, X_OK) == 0)

Maybe the function access doesn't work correctly? Because it looks like it should return false in the case of 4111 permission, right? It's just a guess, you know better.

This is how we package the app if it's important: https://github.com/simplex-chat/simplex-chat/blob/master-ghc9/scripts/desktop/make-appimage-linux.sh

For some unknown reason @tsjk can use our previous beta build of our application with the same permissions on fusermount binary (4711). However, we used the same build process and the same appimagetool binary from Github releases on both beta releases.

Anyway, can we fix the issue somehow from our side or from your side?

@probonopd
Copy link
Member

/bin/fusermount must be usable by the user, and if I am not mistaken, this means that it needs to have 0755?

@avently
Copy link
Author

avently commented Sep 5, 2023

/bin/fusermount must be usable by the user

Yeah, I think so too. But in the case of 711 permissions, the runtime shouldn't take fusermount as on option for mounting, right? And have to use built-in method

@probonopd
Copy link
Member

I don't think that it works without fusermount, because the AppImage is not run as root.

@tsjk
Copy link

tsjk commented Sep 9, 2023

Why does it need to read the suid root binary now, and not just execute? And why was it fine to not need it before?

@probonopd
Copy link
Member

fusermount was always this way. Nothing changed.

@tsjk
Copy link

tsjk commented Sep 10, 2023

What do you mean? This is a new error. In the previous version of the runtime the execute bit was sufficient. That's the whole point of the raised issue.

@probonopd
Copy link
Member

Please give an example on how to reproduce this - before and after. Thanks!

@tsjk
Copy link

tsjk commented Sep 10, 2023

Yeah, alright.
We noticed this as a part of running the AppImage for SimpleX Chat.
You can compare releases beta.6 with beta.5 at https://github.com/simplex-chat/simplex-chat/releases.
@avently found that:

We use appimagetool for packaging which is downloaded from releases: https://github.com/AppImage/appimagetool/tags
The last release was at July 16, which is before beta.5.

It uses this for including in every appimage it's built: https://github.com/AppImage/type2-runtime

The last release was at June 25.

To compare the releases it's sufficient to run

$ ./simplex-desktop-x86_64.AppImage --appimage-mount

Thus, you don't actually need to run the app.

For beta.5, the command succeeds with /usr/bin/fusermount{,3} having permission 04711, but with beta.6 (which uses the newer runtime) the command fails and the suid root binary must be set to be readable by the executing user.

Note that, installing suid root binaries with just the execution bit set for group and others is not uncommon.

@probonopd
Copy link
Member

probonopd commented Sep 10, 2023

Instead of using if (access(prog, X_OK) == 0), maybe we need to do something like this in order to properly take into account the setuid bit:

    struct stat file_stat;
    if ((stat(filename, &file_stat) != -1) && (file_stat.st_mode & S_IXUSR))

Example:

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>

int main() {
    const char *filename = "example_file"; // Replace with the path to the file you want to check

    struct stat file_stat;

    // Check if stat() succeeded and get file information
    if (stat(filename, &file_stat) == -1) {
        perror("Error");
        exit(EXIT_FAILURE);
    }

    // Check for execute permissions
    if (file_stat.st_mode & S_IXUSR) {
        printf("The current user has execute permissions for %s\n", filename);
    } else {
        printf("The current user does not have execute permissions for %s\n", filename);
    }

    return 0;
}

@probonopd
Copy link
Member

probonopd commented Sep 10, 2023

Maybe we should use a custom function like this:

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdbool.h>

bool hasExecutePermission(const char *filename) {
    struct stat file_stat;

    if (stat(filename, &file_stat) == -1) {
        return false;
    }

    // Check for execute permissions for the owner
    return (file_stat.st_mode & S_IXUSR) ? true : false;
}

If you have some time to experiment with this, a pull request would be welcome. Thanks for bringing this to my attention @avently and @tsjk.

@probonopd
Copy link
Member

@avently @tsjk can you please try the runtime from the artifact linked in #16? You can use it with https://github.com/AppImage/appimagetool by using the --runtime-file option.

@tsjk
Copy link

tsjk commented Sep 24, 2023

I think @avently needs to update the build, and then I can try it on my Gentoo systems. Thanks, @probonopd!

@avently
Copy link
Author

avently commented Sep 25, 2023

Sorry for the late reply.
@tsjk https://upload.disroot.org/r/cUw5eax2#/92ASoZW6HsnSWezmkkEv8HZk+GRDGEkKPv/v2RkRLg=

I use here --runtime-file option

@probonopd
Copy link
Member

@tsjk please let me know if this fixes it. Thanks!

@avently
Copy link
Author

avently commented Sep 25, 2023

What's expected output when you try to run AppImage with /bin/fusermount permissions 4711?

I deleted fuse3, keep only fuse2. Run chmod 4711 /bin/fusermount, got this:

mount: /tmp/.mount_SimpleMgCdEj: can't find in /etc/fstab.

Cannot mount AppImage, please check your FUSE setup.
You might still be able to extract the contents of this AppImage
if you run it with the --appimage-extract option.
See https://github.com/AppImage/AppImageKit/wiki/FUSE
for more information
open dir error: No such file or directory

@probonopd
Copy link
Member

probonopd commented Sep 25, 2023

can't find in /etc/fstab is new (to me anyways). Maybe it indicates that it cannot work with fusermount. What happens if you sudo chown root /bin/fusermount && sudo chmod 4755 /bin/fusermount?

@avently
Copy link
Author

avently commented Sep 25, 2023

@probonopd in this case the app starts (with 4755)

@probonopd
Copy link
Member

OK, then I assume it needs those permissions. Is there something in the fusermount documentation that makes you think otherwise?

@avently
Copy link
Author

avently commented Sep 26, 2023

Is there something in the fusermount documentation that makes you think otherwise?

I have no idea how it should work. @tsjk says that it's normal for Gentoo to have 4711. Why is it like this? Have no idea too. If appimage can not work without fusermount, and fusermount is inaccessible, maybe it should print something to log like: "Hey, you use weird fusermount permissions ('actual permissions here'), ask your maintainer to change them to 4755, otherwise, I'm unable to work". And if there is no fuse{2,3} installed, the log should tell about it too. Because when I don't have fuse installed, I can't run AppImage too

@tsjk
Copy link

tsjk commented Sep 26, 2023

SUID root binaries are often installed as 04711. I think not only on Gentoo.
I do wonder why this has broken, however. How come it worked before?
I don't know whether I'm missing something - but for the execution of a binary that is SUID root, read permissions are not needed.

@danpla
Copy link

danpla commented Oct 13, 2023

I get exactly the same error message.

Everything is fine on Ubuntu 22.04 (I used this new runtime to overcome the libfuse2 requirement for modern systems), but on Ubuntu 14.04 I get:

fuse: failed to exec fusermount: Permission denied

Cannot mount AppImage, please check your FUSE setup.
You might still be able to extract the contents of this AppImage 
if you run it with the --appimage-extract option. 
See https://github.com/AppImage/AppImageKit/wiki/FUSE 
for more information
open dir error: No such file or directory

I also tried the patched runtime from #15, but the result is the same.

Both /bin/fusermount3 on 22.04 and /bin/fusermount on 14.04 have 4775 permissions.

However, the AppImage runs fine under root on 14.04, if that matters.

@danpla
Copy link

danpla commented Oct 13, 2023

I looked at the patches/libfuse/mount.c.diff file, and it turns out that setting the FUSERMOUNT_PROG environment variable to /bin/fusermount fixes things on Ubuntu 14.04. So maybe there's a problem with the findBinaryInFusermountDir() function (e.g., its FUSERMOUNT_DIR is always /usr/bin)? But then I wonder why the AppImage works under root without FUSERMOUNT_PROG...

Another observation is that on Ubuntu 14.04, /bin/fusermount exists only in /bin, while on 22.04 it's also available in/usr/bin.

@danpla
Copy link

danpla commented Oct 13, 2023

BTW, FUSERMOUNT_PROG fixes things even without #15.

Maybe the problem is that fileExists uses fopen(path, "r")?

@tobtoht
Copy link

tobtoht commented Oct 16, 2023

With c9553b0, it only looks for fusermount{3,} in /usr/bin, unless FUSERMOUNT_PROG is set (see: here, here and here)

On Debian based distributions fusermount3 is located in /bin. See: https://debian.pkgs.org/12/debian-main-amd64/fuse3_3.14.0-4_amd64.deb.html)

@danpla
Copy link

danpla commented Oct 19, 2023

I created a pull request #18 that should fix the permission issue.

However, I haven't included the fix for the older systems like Ubuntu 14.04 that only have fusermount in /bin but not in /usr/bin, as I think this needs some discussion. I see two ways to fix the issue:

  • Look for fusermount in $PATH if it wasn't found in FUSERMOUNT_DIR. libfuse already does this by default, but this was removed in c9553b0 for "security reasons". I don't quite understand why it's insecure, especially considering the fact that the patched library can run an executable from the FUSERMOUNT_PROG environment variable and arbitrary named fusermount4, fusermount5, etc.
  • Explicitly search in /bin in addition to /usr/bin.

@probonopd
Copy link
Member

probonopd commented Oct 28, 2023

It's the classic problem that different Linux distribtutions seemingly never can agree on anything (e.g., where in the filesystem things are placed). This is the reason I am using FreeBSD nowadays - there is only one distribution.

Anyhow,

Look for fusermount in $PATH if it wasn't found in FUSERMOUNT_DIR. libfuse already does this by default

Are you sure about this? If yes, then we should definitely do the same.

@TheAssassin and I were hesitant about doing this due to it being a setuid program.

@probonopd
Copy link
Member

Thinking a bit more about it, if an attacker can somehow modify $PATH (or place a random executable there) then they can most likely modify $FUSERMOUNT_DIR as well. So maybe we should just fall back to using $PATH, what do people think?

@danpla
Copy link

danpla commented Oct 28, 2023

Look for fusermount in $PATH if it wasn't found in FUSERMOUNT_DIR. libfuse already does this by default

Are you sure about this? If yes, then we should definitely do the same.

Yes, I'm pretty sure: the original exec_fusermount function from libfuse consists of two calls:

execv(FUSERMOUNT_DIR "/" FUSERMOUNT_PROG, (char **) argv);
execvp(FUSERMOUNT_PROG, (char **) argv);

The execvp call was removed in c9553b0.


By the way, if we agree to restore execvp, then using FUSERMOUNT_DIR will probably become unnecessary.

As I understand, the idea behind FUSERMOUNT_DIR, which is configured through the libfuse meson option, is to provide a way to install the library (and fusermount) in some non-standard location, while still ensuring that libfuse can find the fusermount binary.

But since the AppImage runtime uses its own libfuse and needs to find differently named fusermount binaries, using FUSERMOUNT_DIR doesn't make much sense if we restore execvp, as we can be pretty sure that /bin and /usr/bin are already in $PATH in any sane environment.

@probonopd
Copy link
Member

Yes. Given your information I am all for it but we should also hear from @TheAssassin.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

5 participants