[GH-ISSUE #565] Some firejailed processes join an unsandboxed parent instance #397

Closed
opened 2026-05-05 05:47:06 -06:00 by gitea-mirror · 3 comments
Owner

Originally created by @Sidnioulz on GitHub (Jun 11, 2016).
Original GitHub issue: https://github.com/netblue30/firejail/issues/565

Many apps use various hacks to ensure they have a single instance running. Which of course is a problem for sandboxes. There are two common cases: files and DBus.

Blocking PID files

For files, apps write to a specific file to indicate they're running (with a PID / path to a UDS to contact the current instance), which needs to be hidden in the sandbox, and this could simply be a "blacklist" line in the profile.

It sometimes happens that apps require these files for a good reason. They might not support multiple instances changing the settings or cache. So there should also be a way to state that the app's config folders should be mount-bind'ed or overlayfs'ed to prevent conflicts.

Alternatively, Firejail could be made to refuse to run an app if the existing filesystem options expose the path of the PID file. For instance, if I run "firejail firefox", and firejail reads that $HOME/.firefox.lock is the PID file, Firejail could refuse to run unless I have specified something like --private-home or --overlay or --overlay-private-home (on my fork), which means the user knows the sandboxed instance is not conflicting with the unsandboxed one for config/cache file usage. In my GUI I almost always use filesystem options so that's fine by me.

Blocking DBus

For DBus, some apps rely on DBus sockets, so they need to be run in dbus-run-session. Inside the sandbox, Firejail could check if it is already running in a DBus session (check if any of your parents is dbus-run-session or dbus-daemon), and then just continue, or it could wrap the call in a dbus-run-session if necessary for the app.

In the future, it might be possible to do access control on specific DBus names, but I suspect this is not ready / easy yet. It is an intended feature of kdbus though and worth looking into.

Also note that if you implement support for DBus sessions, basically this is how it works:

  • apps read the path to the DBus socket via an env variable
  • this env variable is overridden by dbus-run-session
  • apps can still use the original / default DBus socket if it is not blacklisted, it has a default path that is known and hard-coded as backup in some apps, so it must be blacklisted
  • if you run firejail --name=foo dbus-run-session bar, then all firejail --join=foo instances must find the environment of the original sandbox and parse it to find the correct value for the DBus environment variable. Else those new instances will try to talk to the main session's socket

I support DBus isolation in my fork, though my code is super messy (poor architectural choices in my early hacking which carried on), but maybe you can selectively steal code before I get to rebase.

I call this function right before join_namespace() in join.c. This ensures the DBus environment variable is set properly.

I support DBus with this code in main.c. My firejail.h contains

#define DBUS_RUN_SESSION          "dbus-run-session"
int dbus; // in the Config struct

In sandbox.c, I wrap the call to Firejail when necessary (see also L295 and L331) and I blacklist the original DBus socket path.

Of course I also edit usage.c.

If there was support for these options in Firejail profiles (along with the possibility for explicitly forcing dbus on or forcing the PID file to be visible, with arguments), Firejail could be a lot more secure by default, by preventing those pesky apps from escaping. This is especially useful for people who wrap their Firejail calls and open GUI apps, since current DEs don't provide unique decorations to help identify sandboxed apps.

Originally created by @Sidnioulz on GitHub (Jun 11, 2016). Original GitHub issue: https://github.com/netblue30/firejail/issues/565 Many apps use various hacks to ensure they have a single instance running. Which of course is a problem for sandboxes. There are two common cases: files and DBus. ### Blocking PID files For files, apps write to a specific file to indicate they're running (with a PID / path to a UDS to contact the current instance), which needs to be hidden in the sandbox, and this could simply be a "blacklist" line in the profile. It sometimes happens that apps require these files for a good reason. They might not support multiple instances changing the settings or cache. So there should also be a way to state that the app's config folders should be mount-bind'ed or overlayfs'ed to prevent conflicts. Alternatively, Firejail could be made to refuse to run an app if the existing filesystem options expose the path of the PID file. For instance, if I run "firejail firefox", and firejail reads that $HOME/.firefox.lock is the PID file, Firejail could refuse to run unless I have specified something like --private-home or --overlay or --overlay-private-home (on my fork), which means the user knows the sandboxed instance is not conflicting with the unsandboxed one for config/cache file usage. In my GUI I almost always use filesystem options so that's fine by me. ### Blocking DBus For DBus, some apps rely on DBus sockets, so they need to be run in dbus-run-session. Inside the sandbox, Firejail could check if it is _already_ running in a DBus session (check if any of your parents is dbus-run-session or dbus-daemon), and then just continue, or it could wrap the call in a dbus-run-session if necessary for the app. In the future, it might be possible to do access control on specific DBus names, but I suspect this is not ready / easy yet. It is an intended feature of kdbus though and worth looking into. Also note that if you implement support for DBus sessions, basically this is how it works: - apps read the path to the DBus socket via an env variable - this env variable is overridden by dbus-run-session - apps can still use the original / default DBus socket if it is not blacklisted, it has a default path that is known and hard-coded as backup in some apps, so it must be blacklisted - if you run firejail --name=foo dbus-run-session bar, then all firejail --join=foo instances must find the environment of the original sandbox and parse it to find the correct value for the DBus environment variable. Else those new instances will try to talk to the main session's socket I support DBus isolation in my fork, though my code is super messy (poor architectural choices in my early hacking which carried on), but maybe you can selectively steal code before I get to rebase. I call [this function](https://github.com/Sidnioulz/firejail/blob/master/src/firejail/exechelp_client.c#L126) right before join_namespace() in join.c. This ensures the DBus environment variable is set properly. I support DBus with [this code in main.c](https://github.com/Sidnioulz/firejail/blob/master/src/firejail/main.c#L1198). My firejail.h contains ``` #define DBUS_RUN_SESSION "dbus-run-session" int dbus; // in the Config struct ``` In sandbox.c, I [wrap the call to Firejail when necessary](https://github.com/Sidnioulz/firejail/blob/master/src/firejail/sandbox.c#L261) (see also [L295](https://github.com/Sidnioulz/firejail/blob/master/src/firejail/sandbox.c#L295) and [L331](https://github.com/Sidnioulz/firejail/blob/master/src/firejail/sandbox.c#331)) and I [blacklist the original DBus socket path](https://github.com/Sidnioulz/firejail/blob/master/src/firejail/sandbox.c#L483). Of course I also edit [usage.c](https://github.com/Sidnioulz/firejail/blob/master/src/firejail/usage.c#69). If there was support for these options in Firejail profiles (along with the possibility for explicitly forcing dbus on or forcing the PID file to be visible, with arguments), Firejail could be a lot more secure by default, by preventing those pesky apps from escaping. This is especially useful for people who wrap their Firejail calls and open GUI apps, since current DEs don't provide unique decorations to help identify sandboxed apps.
gitea-mirror 2026-05-05 05:47:06 -06:00
Author
Owner

@netblue30 commented on GitHub (Jun 11, 2016):

Thanks for the writeup. I intend to merge in your dbus code. I'll give it a try next week!

<!-- gh-comment-id:225366057 --> @netblue30 commented on GitHub (Jun 11, 2016): Thanks for the writeup. I intend to merge in your dbus code. I'll give it a try next week!
Author
Owner

@netblue30 commented on GitHub (Jul 10, 2016):

I ended up implementing --rmenv option:

      --rmenv=name
              Remove environment variable in the new sandbox.

              Example:
              $ firejail --rmenv=DBUS_SESSION_BUS_ADDRESS

I don't think you can blacklist the dbus socket, at least on Debian/Ubuntu computers it is an abstract socket. You can only get rid of it using a new network namespace (--net=eth0 or --net=none).

<!-- gh-comment-id:231594880 --> @netblue30 commented on GitHub (Jul 10, 2016): I ended up implementing --rmenv option: ``` --rmenv=name Remove environment variable in the new sandbox. Example: $ firejail --rmenv=DBUS_SESSION_BUS_ADDRESS ``` I don't think you can blacklist the dbus socket, at least on Debian/Ubuntu computers it is an abstract socket. You can only get rid of it using a new network namespace (--net=eth0 or --net=none).
Author
Owner

@Sidnioulz commented on GitHub (Aug 21, 2017):

I realise I'm doing necromancy by replying so late, but I had originally tested my code specifically with Ubuntu systems. You're correct that there are multiple methods used to expose the socket though. I would suggest having a quick chat with the DBus developers on their IRC channel to validate your solution.

IIRC, the problem with simply removing the DBus environment variable rather than wrapping in a new session is that some applications will try to use a default path for the address when no environment variable, which may point to the actual socket (which is still open) when stored in /run/user//bus (e.g. on ArchLinux).

<!-- gh-comment-id:323759303 --> @Sidnioulz commented on GitHub (Aug 21, 2017): I realise I'm doing necromancy by replying so late, but I had originally tested my code specifically with Ubuntu systems. You're correct that there are multiple methods used to expose the socket though. I would suggest having a quick chat with the DBus developers on their IRC channel to validate your solution. IIRC, the problem with simply removing the DBus environment variable rather than wrapping in a new session is that some applications will try to use a default path for the address when no environment variable, which may point to the actual socket (which is still open) when stored in /run/user/<uid>/bus (e.g. on ArchLinux).
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#397
No description provided.