[GH-ISSUE #5787] Hard to do "secure by default" profiles #3093

Closed
opened 2026-05-05 09:43:58 -06:00 by gitea-mirror · 0 comments
Owner

Originally created by @jjakob on GitHub (Apr 17, 2023).
Original GitHub issue: https://github.com/netblue30/firejail/issues/5787

As someone who just started using firejail I had quite a few problems. The biggest issue I have is there is no "secure by default" mode, where the profile could start with zero permissions and gradually add to them. By zero permissions I mean something like a container or VM, where the only mounted filesystems are tmpfs, all required files to run are made from scratch (not copied from the host which could expose the host's identity in the sandbox, which is how it currently works for a lot of files in /etc: passwd, resolv.conf,...), there is no network, the host's username and environment are not copied in, and so on.

  1. filesystem
    Regarding blacklist specifically, I found that blacklist /* breaks everything, because blacklist seems to be processed as the last step when building the filesystem, so even any mounts and directories created by firejail itself (for example private-etc, private-bin, private-lib,...) are blacklisted and return "permission denied" inside the sandbox. I could not figure out how to "unblacklist" only specific directories after a blacklist /* - I tried noblacklist, whitelist, did not work, so I had to create a long list of blacklist directives that specifically excluded things like: /tmp, /dev, /bin, /sbin, /usr/lib, /usr/lib64, /lib, /lib64, /home, /proc. This is made worse by the fact that blacklist only supports basic globbing and so you cannot exclude just one directory from the glob /usr/*: I wanted to not blacklist /usr/share or /usr/lib, so I had to separately blacklist these: /usr/[a-k]* /usr/[m-r]* /usr/s[br]* /usr/[t-z]*. Maybe I am completely misunderstanding how blacklist, whitelist, noblacklist, ignore blacklist work, but I could not figure out any other way. And in order to make a file accessible, not blacklisting is not enough, it also has to be whitelisted? Not blacklisting it and not whitelisting it does not make it accessible if I understand correctly?

  2. private-lib
    If you specify a path to a lib file, firejail will put the file directly into /lib, it will not recreate the original path components (for example: private-lib my/libexample.so will put it in /lib/libexample.so even though it was in /lib/my/example.so.). This breaks some programs that are hardcoded to search in a particular path. If you specify a directory, the directory is recreated with all its contents, for example private-lib my. This works around the previous problem but then you can't select just one lib file inside a directory because it will copy all of them.
    In combination with private-bin it does not find all libraries binaries depend on. In my case it did not find libstdc++.so.6 and libgcc_s.so.1, which I found a lot of issues here saying the same thing. Seems like a bug. (it also did not find libatomic.so or libGL.so)

  3. private-bin
    It does not work on /usr/libexec. For example /usr/libexec/webkit2gtk-4.1 which contains binaries for webkit-gtk. So you have to whitelist the path manually. This means private-lib will not automatically find the libraries those binaries depend on so you have to add them by hand to private-lib. Ideally it would also work on and create /usr/libexec inside the sandbox (preserve the full path as it is on the host, in case something expects a hardcoded path to those binaries) and allow private-lib to find libraries those binaries depend on.

  4. rmenv, env
    There's no way to clear all environment from the host, for example just rmenv could clear all host environment.
    env could then work like this: env HOME would copy HOME from the host into the sandbox. (no need for fixed assignment).
    I worked around this by copying env and sh executables into the sandbox and executing a shell script like so: sh -c 'env -i HOME="$HOME" USER="$USER" DISPLAY="$DISPLAY" command' which is ugly. env -i unsets all environment except that set by its arguments, but only for the executed command passed as arguments. I have not found a simple way to unset all env variables for the entire shell script (shell unset does not have a "unset all" mode).

  5. add a random username function
    Currently the host's username is copied into the sandbox. This is identifying information, it should be possible to have a feature that randomizes the username, or even better uses a very common username, for example 'ubuntu'. It would also need to work with private in order to change the home directory name, and set environment variables accordingly.

In general I think it is better to always write default behavior to be as secure as possible, even if it makes creating custom profiles more tedious because every single thing must be specifically allowed - that is much better than having a default to allow and having to disallow access to a list. I don't think it would be such a problem to hinder functionality or ease of use. Ease of use and security are roughly inversely proportionate to one another.

Originally created by @jjakob on GitHub (Apr 17, 2023). Original GitHub issue: https://github.com/netblue30/firejail/issues/5787 As someone who just started using firejail I had quite a few problems. The biggest issue I have is there is no "secure by default" mode, where the profile could start with zero permissions and gradually add to them. By zero permissions I mean something like a container or VM, where the only mounted filesystems are tmpfs, all required files to run are made from scratch (not copied from the host which could expose the host's identity in the sandbox, which is how it currently works for a lot of files in /etc: passwd, resolv.conf,...), there is no network, the host's username and environment are not copied in, and so on. 1. filesystem Regarding blacklist specifically, I found that `blacklist /*` breaks everything, because blacklist seems to be processed as the last step when building the filesystem, so even any mounts and directories created by firejail itself (for example private-etc, private-bin, private-lib,...) are blacklisted and return "permission denied" inside the sandbox. I could not figure out how to "unblacklist" only specific directories after a `blacklist /*` - I tried noblacklist, whitelist, did not work, so I had to create a long list of blacklist directives that specifically excluded things like: /tmp, /dev, /bin, /sbin, /usr/lib, /usr/lib64, /lib, /lib64, /home, /proc. This is made worse by the fact that blacklist only supports basic globbing and so you cannot exclude just one directory from the glob `/usr/*`: I wanted to not blacklist /usr/share or /usr/lib, so I had to separately blacklist these: `/usr/[a-k]* /usr/[m-r]* /usr/s[br]* /usr/[t-z]*`. Maybe I am completely misunderstanding how blacklist, whitelist, noblacklist, ignore blacklist work, but I could not figure out any other way. And in order to make a file accessible, not blacklisting is not enough, it also has to be whitelisted? Not blacklisting it and not whitelisting it does not make it accessible if I understand correctly? 2. private-lib If you specify a path to a lib file, firejail will put the file directly into /lib, it will not recreate the original path components (for example: `private-lib my/libexample.so` will put it in `/lib/libexample.so` even though it was in `/lib/my/example.so`.). This breaks some programs that are hardcoded to search in a particular path. If you specify a directory, the directory is recreated with all its contents, for example `private-lib my`. This works around the previous problem but then you can't select just one lib file inside a directory because it will copy all of them. In combination with private-bin it does not find all libraries binaries depend on. In my case it did not find libstdc++.so.6 and libgcc_s.so.1, which I found a lot of issues here saying the same thing. Seems like a bug. (it also did not find libatomic.so or libGL.so) 3. private-bin It does not work on /usr/libexec. For example /usr/libexec/webkit2gtk-4.1 which contains binaries for webkit-gtk. So you have to whitelist the path manually. This means private-lib will not automatically find the libraries those binaries depend on so you have to add them by hand to private-lib. Ideally it would also work on and create /usr/libexec inside the sandbox (preserve the full path as it is on the host, in case something expects a hardcoded path to those binaries) and allow private-lib to find libraries those binaries depend on. 4. rmenv, env There's no way to clear all environment from the host, for example just `rmenv` could clear all host environment. `env` could then work like this: `env HOME` would copy HOME from the host into the sandbox. (no need for fixed assignment). I worked around this by copying `env` and `sh` executables into the sandbox and executing a shell script like so: `sh -c 'env -i HOME="$HOME" USER="$USER" DISPLAY="$DISPLAY" command'` which is ugly. `env -i` unsets all environment except that set by its arguments, but only for the executed command passed as arguments. I have not found a simple way to unset all env variables for the entire shell script (shell `unset` does not have a "unset all" mode). 5. add a random username function Currently the host's username is copied into the sandbox. This is identifying information, it should be possible to have a feature that randomizes the username, or even better uses a very common username, for example 'ubuntu'. It would also need to work with `private` in order to change the home directory name, and set environment variables accordingly. In general I think it is better to always write default behavior to be as secure as possible, even if it makes creating custom profiles more tedious because every single thing must be specifically allowed - that is much better than having a default to allow and having to disallow access to a list. I don't think it would be such a problem to hinder functionality or ease of use. Ease of use and security are roughly inversely proportionate to one another.
gitea-mirror 2026-05-05 09:43:58 -06:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: github-starred/firejail#3093
No description provided.