Coordinated Disclosure Timeline
- 2021-05-04: Reported as a private issue.
- 2021-05-07: No response yet, so I added a comment to the issue, asking for somebody to acknowledge receipt of the report.
- 2021-05-09: Emailed Red Hat (secalert@redhat.com) to notify them of the vulnerability. Some of the polkit engineers are Red Hat employees, so I asked if they could check that the polkit team have received my report.
- 2021-05-10: Reply from Red Hat (secalert@redhat.com): they have assigned tracking number INC1755546 and will investigate.
- 2021-05-18: Reply from Red Hat (secalert@redhat.com): “We got in touch with people inside the upstream community. They will now be looking at it.”
- 2021-05-19: Message from Red Hat: “Although the PoC does not appear to be working in my RHEL test machine (the
Elapsed time
is an order of magnitude lower that in your example, so it may be that the disconnect happens too late?), but upstream appears to have validated it.” - 2021-05-19: I investigate why the PoC doesn’t work on RHEL. It turns out that the PoC depends on
gnome-control-center
being installed. - 2021-05-20: Red Hat confirm that the PoC is working for them after installing
gnome-control-center
. - 2021-05-20: Red Hat assigns CVE-2021-3560.
- 2021-05-25: I develop a second PoC that uses the vulnerability to exploit packagekit. This can be used to install
gnome-control-center
on RHEL. - 2021-05-26: Message from Red Hat: “I have sent a private disclosure notice to other distros ( https://oss-security.openwall.org/wiki/mailing-lists/distros ) The current tentative disclosure is Thursday 3rd of June (~7:00 AM UTC).”
- 2021-06-03: Bug fix
- 2021-06-03: Vulnerability disclosed: Red Hat, Debian, Ubuntu, Arch Linux
Summary
There is an authentication bypass vulnerability in polkit, which enables an unprivileged user to get authorization from polkit to perform a privileged action.
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.116-7 (tested on Fedora 32)
Details
Issue 1: Authentication bypass in polkit (GHSL-2021-074
)
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
. These unique names are assigned and managed by dbus-daemon
and cannot be forged, so this is a good way to check the privileges of the requesting process.
The vulnerability happens when the requesting process disconnects from dbus-daemon
just before the call to polkit_system_bus_name_get_creds_sync
starts. In this scenario, the unique bus name is no longer valid, so dbus-daemon
sends back an error reply. This error case is handled in polkit_system_bus_name_get_creds_sync
by setting the value of the error
parameter, but it still returns TRUE
, rather than FALSE
. We are not sure whether it’s a bug that the return value is TRUE when this error happens, but this behavior certainly means that all callers of polkit_system_bus_name_get_creds_sync
need to carefully check whether an error was set. If the calling function forgets to check for errors then it will think that the uid of the requesting process is 0 (because the AsyncGetBusNameCredsData
struct is zero initialized). In other words, it will think that the action was requested by a root process, and will therefore allow it.
Most of the callers of polkit_system_bus_name_get_creds_sync
check the error value correctly, and are therefore not vulnerable. But the error value is not checked in the following stack trace:
0 in polkit_system_bus_name_get_creds_sync of polkitsystembusname.c:393
1 in polkit_system_bus_name_get_user_sync of polkitsystembusname.c:511
2 in polkit_backend_session_monitor_get_user_for_subject of polkitbackendsessionmonitor-systemd.c:303
3 in check_authorization_sync of polkitbackendinteractiveauthority.c:1113
4 in check_authorization_sync of polkitbackendinteractiveauthority.c:1223
5 in polkit_backend_interactive_authority_check_authorization of polkitbackendinteractiveauthority.c:971
6 in server_handle_check_authorization of polkitbackendauthority.c:795
7 in server_handle_method_call of polkitbackendauthority.c:1274
The bug is in this snippet of code in check_authorization_sync
:
/* every subject has a user; this is supplied by the client, so we rely
* on the caller to validate its acceptability. */
user_of_subject = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor,
subject, NULL,
error);
if (user_of_subject == NULL)
goto out;
/* special case: uid 0, root, is _always_ authorized for anything */
if (POLKIT_IS_UNIX_USER (user_of_subject) && polkit_unix_user_get_uid (POLKIT_UNIX_USER (user_of_subject)) == 0)
{
result = polkit_authorization_result_new (TRUE, FALSE, NULL);
goto out;
}
Notice that the value of error
is not checked.
Impact
This issue may lead to local privilege escalation on any Linux system that uses polkit.
Resources
Proof of concept exploit: GHSL-2021-074-polkit.bundle
CVE
- CVE-2021-3560
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-074
in any communication regarding this issue.