Inproper Free of Static Pointer leading to LPE on Ubuntu

We discussed this vulnerability as part of our weekly podcast on 12 January 2022

Here, we have a case of one function returning a pointer to a caller, but expecting to retain ownership over that pointer; the caller, thinking it has ownership, frees it; and by calling the same function multiple times the same pointer gets freed multiple times.

The user_get_fallback_value function exists essentially to take a key name, and return a default value which is used when a value for that key cannot be found in other sources (such as the user’s .pam_envrionment file). The default value is stored in a static pointer and only allocated once, expecting the caller to use the value and forget about it. Instead in user_change_language_authorized_cb it recieves the value and annotes it with the g_autofree macro which as the name implies will end up freeing the value, leaving the original function with a dangling pointer. Repeating this process multiple times will result in a double free situation.


The post also goes into some exploitation strategy and talks a bit about the general process of going from this dangling pointer and how to turn it into something useful, and its a great read for some of that process. The final attack ended up being a data-oriented attack targeting the CheckAuthData structure used by polkit.

Polkit is an authorization API, meant to be used by privileged processes offering services to unprivileged users. The basic process is that when a new service request comes in this CheckAuthData structure is generated for the request, and it contains a callback function pointer. The privileged service sends off a asynchronous request to polkit, and when it gets a response, if the response indicates the user is authorized to perform the action the callback in the structure will be executed.

The attack process would target this structure, first by triggering the invalid free and having it get picked up by a benign request to change a user’s email. Polkit will reply that the request is authorized, but before it does, the invalid free will be triggered again. This time with a more sensitive action, such as changing the root password. If this happens fast enough, and it manages to reuse the targeted memory block, when the authorized response comes back from the benign action, it will execute the callback for the more sensitive action.