Bug 1199148 - (CVE-2022-31214) VUL-0: CVE-2022-31214: firejail: local root exploit reachable via --join logic
VUL-0: CVE-2022-31214: firejail: local root exploit reachable via --join logic
: 1201299 (view as bug list)
Classification: Novell Products
Product: SUSE Security Incidents
Classification: Novell Products
Component: Incidents
Other Other
: P3 - Medium : Normal
: ---
Assigned To: Sebastian Wagner
Security Team bot
Depends on:
  Show dependency treegraph
Reported: 2022-05-03 09:19 UTC by Matthias Gerstner
Modified: 2022-07-08 04:41 UTC (History)
5 users (show)

See Also:
Found By: ---
Services Priority:
Business Priority:
Blocker: ---
Marketing QA Status: ---
IT Deployment: ---

release candidate patch (56.32 KB, patch)
2022-06-08 08:19 UTC, Matthias Gerstner
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Matthias Gerstner 2022-05-03 09:19:12 UTC
I have discovered a local root exploit issue in Firejail in its `--join`
program flow. I will post the full description in the next comment.

I just shared the information with Firejail upstream and the issue is still
private. Please don't share information about this outside of this bug before
the embargo is lifted.
Comment 1 Matthias Gerstner 2022-05-03 09:33:01 UTC
 # Join Logic
 Most of the logic behind the join feature is found in the source code file
 `src/firejail/join.c`. Critical sections of code are running with elevated
 privileges (effective UID 0). The process ID passed as command line argument
 is inspected to determine whether it is a Firejail container and to determine
 certain of its properties that will be applied likewise to the newly joining
 The main criterion that decides whether joining the target process succeeds is
 the presence of a file in the mount namespace of the target process found at
 /run/firejail/mnt/join. This check is performed in the `is_ready_for_join()`
 function. The file is opened using `O_RDONLY|O_CLOEXEC` flags and the
 follow-up `fstat()` result needs to fulfil the following requirements:
 - the file needs to be a regular file.
 - the file needs to be owned by user ID 0 (as seen from the root user
 - the file needs to have a size of 1 byte.
 Then in a follow-up `read()` call the first byte of the file needs to equal
 the ASCII '1' character (`SANDBOX_DONE` preprocessor define in the source).
 If this check succeeds then the various namespaces the target process is in
 will be joined and further preparations are made to containerise the newly
 joining process.
 # The Vulnerability
 An unprivileged user in the system can fake a legit Firejail process by
 providing a symlink at /run/firejail/mnt/join that points to a file that
 fulfils the requirements listed in the previous section. By creating a custom
 user and mount namespace the attacker can create an environment of its own
 where mounting tmpfs file systems in arbitrary locations is possible. Thus
 /run/firejail can be made writeable within the separate mount namespace. Since
 the `open()` call in `join.c:335` follows symlinks, the target file can reside
 anywhere else within the accessible file system tree. Using bind mounting a
 suitable "join" file could also be placed there without using symlinks,
 A file owned by root that contains a '1' character is not that unlikely to
 exist somewhere on the system. If the attacker has local system access and
 automounting of removable storage devices is available then attaching a
 storage device that contains such a file could also be an option. Even
 simpler, however, is using Firejail itself to provide the file. Creating a
 Firejail instance without security profiles applied (switch `--noprofile`)
 will make its "join" file accessible also from within the initial mount
 namespace in the system via its /proc/<pid>/root entry.
 Once a suitable file is staged in a fake Firejail instance, the fake Firejail
 process will be basically accepted by Firejail for joining it. Firejail by
 default sets the `NO_NEW_PRIVS` `prctl()` for sandboxed processes. When using
 `firejail --noprofile` or when faking a Firejail instance, the setting will
 not be applied, however. Firejail's join logic is trusting the target process,
 and copies this property from it. Next Firejail will join the target process's
 namespaces (`join.c:441`), particularly interesting for this attack, the mount
 namespace. Then, after forking a new child process for the join operation, the
 logic attempts to drop privileges by joining the target user namespace
 For joining the user namespace not the target process is used but the init
 process with PID 1. The consideration behind this is probably that it is
 always expected that the Firejail container is running in its own PID
 namespace and the init process inside it can be trusted for having the correct
 user namespace assigned. In this attack scenario there is no separate
 PID namespace, so the initial PID namespace will still be visible in /proc.
 Regardless of this the attacker controlled mount namespace (of which the
 Firejail process already is a member of by now) can blend in a tmpfs in
 /proc/1, thereby controlling which user namespace the Firejail join operation
 will actually join.
 Joining an actual separate user namespace is not what is desired for this
 attack (although this could also be interesting for joining arbitrary other
 users' containers and sandboxes). The aim of this attack is not to join any
 user namespace at all. Joining the initial user namespace will fail, because
 joining the current user namespace again is denied by the kernel. To avoid
 this, a symlink can be placed in /proc/1/ns/user that points to an arbitrary
 different namespace object. In this example the symlink will point to the
 *time* namespace of the current process. Joining the time namespace will
 succeed and Firejail will not detect an error.
 The resulting "joined" shell will now live in the initial user namespace,
 holding still the original normal user privileges, however the mount namespace
 will be the one controlled by the attacker. Since the nonewprivs setting has
 not been applied, the attacker is now able to run setuid-root programs within
 this mount namespace. From here on all that needs to be done is changing file
 system contents in a way that typical setuid-root binaries like `su` or `sudo`
 will grant full root privileges. The proof of concept exploit I wrote for this
 vulnerability does this by replacing the PAM stack configuration.
Comment 2 Matthias Gerstner 2022-05-03 09:35:24 UTC
This is an embargoed bug. This means that this information is not public.

Please do NOT:
- talk to other people about this unless they're involved in fixing the issue
- make this bug public
- submit this into OBS (e.g. fix Leap/Tumbleweed) until this bug becomes
  public. This means that the security team removed the EMBARGOED tag from
  the bug title after we verified that there's already information about
  this bug publicly available. If you find such information yourself and
  the bug is still embargoed please contact us

Your primary responsibility is to apply a fix for this issue.
Here is some guidance on openSUSE package maintenance:
- https://en.opensuse.org/openSUSE:Package_maintenance
- https://en.opensuse.org/openSUSE:Maintenance_update_process

You need to submit AFTER the bug became public, to the current openSUSE
Leap codestreams, and to the devel project of your package.

The security team will then take the following steps:
- We wait for your submission and package them into an incident for QA
  testing. The QA tester might reach out to you if they find issues with
  the update.
- If QA doesn't find any issues, we publish the updates.

You can contact us at:

* IRC: irc.suse.de #security
* Do NOT use Slack or any non-SUSE hosted messaging services
* Email: security-team@suse.de
Comment 3 Thomas Leroy 2022-05-04 07:19:09 UTC
Regarding the fixes, we will need the following codestreams to be fixed:
- openSUSE:Backports:SLE-15-SP3          
- openSUSE:Backports:SLE-15-SP3:Update   
- openSUSE:Backports:SLE-15-SP4          
- openSUSE:Factory
Comment 4 Matthias Gerstner 2022-05-19 07:44:03 UTC
We have had a hard time forwarding the report to upstream but since the
beginning of this week the report has finally been shared with suitable
upstream developers.

Due to the delays in communication the CRD is also delayed. Currently we're
planning to publish this finding by end of the month.

I requested a CVE from Mitre that is now also visible in this bug.
Comment 6 Matthias Gerstner 2022-05-25 09:07:00 UTC
Upstream is working on the issue but we don't have any patches available yet.
The CRD should still be in place though.
Comment 7 Matthias Gerstner 2022-05-30 13:16:54 UTC
Upstream approached me by now with a tentative patch for review. It looks like
they will need a couple of more days for reviewing and packaging. Once I know
a new CRD and once I have a final patch that all parties agreed upon I will
update this bug accordingly.
Comment 9 Matthias Gerstner 2022-06-03 11:36:46 UTC
The patch under review looks mostly good. I expect a final patch to be
available early next week. Probably also a new upstream version will be
available by then. For the Factory package bumping the version should be

For the SLE backports I'm not completely sure how to handle them.
Comment 10 Matthias Gerstner 2022-06-08 08:19:09 UTC
Created attachment 859476 [details]
release candidate patch
Comment 11 Matthias Gerstner 2022-06-08 08:22:07 UTC
The patch review is finished and we agreed on the patch that can be found in
attachment 859476 [details]. Upstream intends to publish this fix today. Once this
happens I will make this bug public.

@sebix+novell.com@sebix.at: Once the bug becomes public you can submit a fix
to Factory. I suppose upstream will also make a new version release, so you
can either prepare a submission using the attached patch or wait for the
version release to make a version bump.
Comment 12 Matthias Gerstner 2022-06-08 12:05:55 UTC
The fix has now been published:


Therefore I'm also publishing this bug.

There is no new release available on GitHub at the moment, therefore I suggest to fix our packaging using the patch.
Comment 14 Matthias Gerstner 2022-06-09 07:44:38 UTC
(In reply to sebix+novell.com@sebix.at from comment #13)
> > Sorry, you are not authorized to access attachment #859476 [details].

I thought I made it public yesterday, but it seems not. I will do that now.

> I therefore used these three commits from upstream:
> https://github.com/netblue30/firejail/commit/27cde3d7d1e4e16d4190932347c7151dc2a84c50
> https://github.com/netblue30/firejail/commit/dab835e7a0eb287822016f5ae4e87f46e1d363e7.patch
> https://github.com/netblue30/firejail/commit/1884ea22a90d225950d81c804f1771b42ae55f54

Even better. There have been some regressions.

> I submitted the package to Factory as first step.
> https://build.opensuse.org/request/show/981393

Thanks! Doing the version bumps for the SLE- backports should also not be a
big matter.
Comment 15 Sebastian Wagner 2022-06-14 20:35:34 UTC
I finally submitted 0.9.70 to Factory, Leap 15.3 and Leap 15.4.
Comment 16 OBSbugzilla Bot 2022-06-14 22:40:03 UTC
This is an autogenerated message for OBS integration:
This bug (1199148) was mentioned in
https://build.opensuse.org/request/show/982662 Backports:SLE-15-SP3 / firejail
https://build.opensuse.org/request/show/982663 Backports:SLE-15-SP4 / firejail
Comment 17 Swamp Workflow Management 2022-06-20 13:22:29 UTC
openSUSE-SU-2022:10016-1: An update that fixes one vulnerability is now available.

Category: security (important)
Bug References: 1199148
CVE References: CVE-2022-31214
JIRA References: 
Sources used:
openSUSE Backports SLE-15-SP4 (src):    firejail-0.9.70-bp154.2.3.1
Comment 18 Swamp Workflow Management 2022-06-20 13:23:31 UTC
openSUSE-SU-2022:10015-1: An update that fixes one vulnerability is now available.

Category: security (important)
Bug References: 1199148
CVE References: CVE-2022-31214
JIRA References: 
Sources used:
openSUSE Backports SLE-15-SP3 (src):    firejail-0.9.70-bp153.2.6.1
Comment 19 Sebastian Wagner 2022-06-21 07:45:47 UTC
Update is now available in all distros, closing here.
Comment 20 Andreas Stieger 2022-07-08 04:41:07 UTC
*** Bug 1201299 has been marked as a duplicate of this bug. ***