-
-
Notifications
You must be signed in to change notification settings - Fork 31.2k
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
Linux specific local privilege escalation via the multiprocessing forkserver start method - CVE-2022-42919 #97514
Comments
Linux abstract sockets are insecure as they lack any form of filesystem permissions so their use allows anyone on the system to inject code into the process. This removes the default preference for abstract sockets in multiprocessing introduced in Python 3.9+ via python#18866 while fixing python#84031. Explicit use of an abstract socket by a user now generates a RuntimeWarning. If we choose to keep this warning, it should be backported to the 3.7 and 3.8 branches.
Linux abstract sockets are insecure as they lack any form of filesystem permissions so their use allows anyone on the system to inject code into the process. This removes the default preference for abstract sockets in multiprocessing introduced in Python 3.9+ via #18866 while fixing #84031. Explicit use of an abstract socket by a user now generates a RuntimeWarning. If we choose to keep this warning, it should be backported to the 3.7 and 3.8 branches.
…ythonGH-98501) Linux abstract sockets are insecure as they lack any form of filesystem permissions so their use allows anyone on the system to inject code into the process. This removes the default preference for abstract sockets in multiprocessing introduced in Python 3.9+ via python#18866 while fixing python#84031. Explicit use of an abstract socket by a user now generates a RuntimeWarning. If we choose to keep this warning, it should be backported to the 3.7 and 3.8 branches. (cherry picked from commit 49f6106) Co-authored-by: Gregory P. Smith <[email protected]>
…ythonGH-98501) Linux abstract sockets are insecure as they lack any form of filesystem permissions so their use allows anyone on the system to inject code into the process. This removes the default preference for abstract sockets in multiprocessing introduced in Python 3.9+ via python#18866 while fixing python#84031. Explicit use of an abstract socket by a user now generates a RuntimeWarning. If we choose to keep this warning, it should be backported to the 3.7 and 3.8 branches. (cherry picked from commit 49f6106) Co-authored-by: Gregory P. Smith <[email protected]>
…ythonGH-98501) Linux abstract sockets are insecure as they lack any form of filesystem permissions so their use allows anyone on the system to inject code into the process. This removes the default preference for abstract sockets in multiprocessing introduced in Python 3.9+ via python#18866 while fixing python#84031. Explicit use of an abstract socket by a user now generates a RuntimeWarning. If we choose to keep this warning, it should be backported to the 3.7 and 3.8 branches. (cherry picked from commit 49f6106) Co-authored-by: Gregory P. Smith <[email protected]>
…ythonGH-98501) Linux abstract sockets are insecure as they lack any form of filesystem permissions so their use allows anyone on the system to inject code into the process. This removes the default preference for abstract sockets in multiprocessing introduced in Python 3.9+ via python#18866 while fixing python#84031. Explicit use of an abstract socket by a user now generates a RuntimeWarning. If we choose to keep this warning, it should be backported to the 3.7 and 3.8 branches. (cherry picked from commit 49f6106) Co-authored-by: Gregory P. Smith <[email protected]>
…GH-98501) (GH-98502) Linux abstract sockets are insecure as they lack any form of filesystem permissions so their use allows anyone on the system to inject code into the process. This removes the default preference for abstract sockets in multiprocessing introduced in Python 3.9+ via #18866 while fixing #84031. Explicit use of an abstract socket by a user now generates a RuntimeWarning. If we choose to keep this warning, it should be backported to the 3.7 and 3.8 branches. (cherry picked from commit 49f6106) Co-authored-by: Gregory P. Smith <[email protected]> Automerge-Triggered-By: GH:gpshead
…GH-98501) (GH-98503) Linux abstract sockets are insecure as they lack any form of filesystem permissions so their use allows anyone on the system to inject code into the process. This removes the default preference for abstract sockets in multiprocessing introduced in Python 3.9+ via #18866 while fixing #84031. Explicit use of an abstract socket by a user now generates a RuntimeWarning. If we choose to keep this warning, it should be backported to the 3.7 and 3.8 branches. (cherry picked from commit 49f6106) Co-authored-by: Gregory P. Smith <[email protected]> Automerge-Triggered-By: GH:gpshead
…GH-98501) (GH-98502) Linux abstract sockets are insecure as they lack any form of filesystem permissions so their use allows anyone on the system to inject code into the process. This removes the default preference for abstract sockets in multiprocessing introduced in Python 3.9+ via #18866 while fixing #84031. Explicit use of an abstract socket by a user now generates a RuntimeWarning. If we choose to keep this warning, it should be backported to the 3.7 and 3.8 branches. (cherry picked from commit 49f6106) Co-authored-by: Gregory P. Smith <[email protected]> Automerge-Triggered-By: GH:gpshead
…H-98501) (#98504) Linux abstract sockets are insecure as they lack any form of filesystem permissions so their use allows anyone on the system to inject code into the process. This removes the default preference for abstract sockets in multiprocessing introduced in Python 3.9+ via #18866 while fixing #84031. Explicit use of an abstract socket by a user now generates a RuntimeWarning. If we choose to keep this warning, it should be backported to the 3.7 and 3.8 branches. (cherry picked from commit 49f6106) Co-authored-by: Gregory P. Smith <[email protected]>
I created https://python-security.readthedocs.io/vuln/multiprocessing-abstract-socket.html to track this vulnerability. |
Canonical is tracking it for Ubuntu (and ultimately Debian?) here: https://ubuntu.com/security/notices/USN-5713-1 RedHat seems to be tracking it for RHEL and Fedora as well: https://bugzilla.redhat.com/show_bug.cgi?id=2138705 |
Thanks for this @gpshead! With these changes you've effectively fixed it for 3.9? What are the next steps? Thank you in advance! |
openSUSE https://bugzilla.suse.com/1204886 (aka https://bugzilla.suse.com/show_bug.cgi?id=CVE-2022-42919) |
I added links to my page. Well, it would be even better if people other than me would maintain the vulnerability list. It's a long YAML page: https://github.com/vstinner/python-security/blob/main/vulnerabilities.yaml#L2049 |
@vstinner I'd be up for that if it mean freeing up some time for you? 👍 |
Generally, for openSUSE, |
Note that the NIST NVD record linked from the Python Security tracker contains misleading information. At the bottom it claims "Known Affected: up to (excluding) 3.10.8" which is confusing folks into thinking 3.10.8 is unaffected by this vulnerability. It would be great if someone with authority for Python's vulnerability disclosure could reach out to NIST and get that corrected, since it may be causing some organizations to not realize they need to patch their builds. |
Yes, I'm disappointed with my interactions with Mitre regarding getting the CVE text updated. The clear categorized information I provided to them via their cve request web form when reserving the CVE id was mostly discarded when they flipped it from "Reserved" to publish it with information. This process should in theory go smoother once Python is setup as its own CNA (we're planning to do this). Anyways the good news is that it can be updated and now that I finally got them to make the record public in some form, doing so should be easier. I'll see what I can do to clean the CVE record that winds up in the NVD up. It is ultimately a JSON blob following a defined schema and now that it is public I believe I can do so via a PR against https://github.com/CVEProject/cvelist/blob/master/2022/42xxx/CVE-2022-42919.json - we'll see. It's a byzantine process. :/ |
@gpshead I would like to point out that the bugfix with support for abstract namespace sockets was added in Python 3.8.3, not Python 3.8.4. See the following: |
Thanks. Main description text updated to say 3.8.3. |
Is there a way to reproduce it? @gpshead |
Yes. But it is basically a demo exploit so we're intentionally not releasing that ourselves. I'll leave an exploit as an exercise for others. To scan a Linux system for such vulnerable sockets being open.
If there are multiple network namespaces you probably need to do more to scan all of those from a sufficiently priviledged user. |
This adds authentication to the forkserver control socket. In the past only filesystem permissions protected this socket from code injection into the forkserver process by limiting access to the same UID, which didn't exist when Linux abstract namespace sockets were used (see issue) meaning that any process in the same system network namespace could inject code. We've since stopped using abstract namespace sockets by default, but protecting our control sockets regardless of type is a good idea. This reuses the HMAC based shared key auth already used by `multiprocessing.connection` sockets for other purposes. Doing this is useful so that filesystem permissions are not relied upon and trust isn't implied by default between all processes running as the same UID with access to the unix socket. ### pyperformance benchmarks No significant changes. Including `concurrent_imap` which exercises `multiprocessing.Pool.imap` in that suite. ### Microbenchmarks This does _slightly_ slow down forkserver use. How much so appears to depend on the platform. Modern platforms and simple platforms are less impacted. This PR adds additional IPC round trips to the control socket to tell forkserver to spawn a new process. Systems with potentially high latency IPC are naturally impacted more. Typically a 1-4% slowdown on a very targeted process creation microbenchmark, with a worst case overloaded system slowdown of 20%. No evidence that these slowdowns appear in practical sense. See the PR for details.
…-99309) This adds authentication to the forkserver control socket. In the past only filesystem permissions protected this socket from code injection into the forkserver process by limiting access to the same UID, which didn't exist when Linux abstract namespace sockets were used (see issue) meaning that any process in the same system network namespace could inject code. We've since stopped using abstract namespace sockets by default, but protecting our control sockets regardless of type is a good idea. This reuses the HMAC based shared key auth already used by `multiprocessing.connection` sockets for other purposes. Doing this is useful so that filesystem permissions are not relied upon and trust isn't implied by default between all processes running as the same UID with access to the unix socket. ### pyperformance benchmarks No significant changes. Including `concurrent_imap` which exercises `multiprocessing.Pool.imap` in that suite. ### Microbenchmarks This does _slightly_ slow down forkserver use. How much so appears to depend on the platform. Modern platforms and simple platforms are less impacted. This PR adds additional IPC round trips to the control socket to tell forkserver to spawn a new process. Systems with potentially high latency IPC are naturally impacted more. Typically a 1-4% slowdown on a very targeted process creation microbenchmark, with a worst case overloaded system slowdown of 20%. No evidence that these slowdowns appear in practical sense. See the PR for details.
TL;DR
Python 3.9, 3.10, and 3.11.0rc2 on Linux may allow for a local privilege escalation attack in a non-default configuration when code uses the
multiprocessing
module and configuresmultiprocessing
to use the forkserver start method.Details
The Python
multiprocessing
library, when used with the forkserver start method on Linux, allows Python pickles to be deserialized from any user in the same machine local network namespace, which in many system configurations means any user on the same machine. Pickles can execute arbitrary code. Thus, this allows for local user privilege escalation to the user that any Python multiprocessing forkserver process is running as.The forkserver start method for multiprocessing is not the default start method. This issue is Linux specific because only Linux supports abstract namespace sockets.
CPython before 3.9 does not make use of Linux abstract namespace sockets by default.
This issue has been assigned CVE-2022-42919.
Credit: This issue was discovered by Devin Jeanpierre (@ssbr) of Google.
Are Python 3.7 and 3.8 affected?
Not by default.
Support for users manually specifying an abstract namespace AF_UNIX socket was added as a bugfix in 3.7.8 and 3.8.3, but users would need to make specific uncommon
multiprocessing
API calls specifying their own forkserver control socket path in order to do that in CPython before 3.9.What about code that explicitly asks for an abstract socket?
Applications found to be making the uncommon
multiprocessing
API calls to explicitly use Linux abstract namespace sockets with a forkserver are believed to be rare and should have their own specific security issues filed.Workarounds
From Python application or library code:
This disables their use by default. You must execute that before anything else in your process has started making use of multiprocessing.
If you can patch your CPython runtime itself:
Remove these two lines from CPython's
Lib/multiprocessing/connection.py
:(that is what our security bug fix commits do).
Or, similar to the application level fix, edit
Lib/multiprocessing/util.py
to always set:Alternatives to avoid the problem
If your Linux Python application can be switched from multiprocessing's
.set_start_method("forkserver")
to a start method such as"spawn"
that will also avoid this issue.Scope of the bug fixes
We are changing the default in Python 3.9 and higher to not use the Linux abstract namespace sockets by default.
It would be ideal to add authentication to the forkserver control socket so that it isn't even relying on filesystem permissions. This is a more complicated change and is expected to be done as a feature in 3.12.
Tasks
Linked PRs
The text was updated successfully, but these errors were encountered: