Coordinated Disclosure Timeline
- 2021-02-18: Emailed report and PoC to systemd-security@redhat.com
- 2021-02-19: Reply from Lennart Poettering: This issue was already reported and fixed, although it was not declared a security issue.
Summary
There is a potential type confusion vulnerability in the varlink interface of systemd-resolved. This is due to the userdata
field of the Varlink
struct being used to store two unrelated datatypes: Manager
and DnsQuery
.
Product
systemd-resolved
Tested Version
systemd v247.3-1 (tested on Arch Linux)
Note: the new varlink interface to systemd-resolved has only been added quite recently. Many Linux distributions ship with older versions of systemd which do not include the new interface. However, Arch Linux ships with v247, which includes it.
Details
Issue 1: Type confusion in systemd-resolved varlink interface (GHSL-2021-049
)
The Varlink
struct has a void*
field named userdata
.
The varlink interface of systemd-resolved initially uses this field to store a pointer to the Manager
object (resolved-varlink.c, line 515):
varlink_server_set_userdata(s, m);
But, later, the userdata
field is used to store a pointer to the DnsQuery
object (resolved-varlink.c, line 318 and resolved-varlink.c, line 485):
varlink_set_userdata(link, q);
It looks like the code was written with the assumption that the Varlink
object will only survive for the duration of single request, so the change of the type of the userdata
field won’t cause a problem. However, if two varlink requests are received in quick succession then the same Varlink
object is reused, potentially leading to a type confusion vulnerability.
To reproduce the issue, please build the attached proof-of-concept as follows:
gcc varlink_resolve.c -o varlink_resolve
You might also need to start systemd-resolved if it isn’t already running:
sudo systemctl start systemd-resolved
The PoC has two modes, to test the io.systemd.Resolve.ResolveHostname
and io.systemd.Resolve.ResolveAddress
interfaces, respectively:
./varlink_resolve hostname www.github.com
./varlink_resolve address 127.0.0.1
Both those commands cause systemd-resolved to crash.
In our testing, systemd-resolved always crashes due to the userdata
field containing a NULL pointer, which triggers an assertion failure at resolved-varlink.c, line 277 or resolved-varlink.c, line 455. We are not sure why we have never seen a crash due to the userdata
field containing a pointer to a DnsQuery
object. The code is invoked by an epoll event handler, which suggests that the behavior should be non-deterministic, based on the order in which the events are received. If the events are handled in a different order then we believe it will lead to a type confusion rather than a NULL pointer error.
Impact
This issue may lead to a memory corruption, which could enable a local attacker to gain code execution as the systemd-resolve user.
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-049
in any communication regarding this issue.