CVE-2023-40084 AI-generated analysis
platform/system/netd, server/MDnsSdListener (mDNS service monitor thread)
Replaces the netdutils::threadLaunch-started monitor thread in netd's MDnsSdListener::Monitor with a stored std::thread. A new Monitor destructor interrupts this thread by closing one end of the control socketpair and then joins it, so Monitor::run can no longer run on a destroyed Monitor instance.
Root cause
MDnsSdListener::Monitor::Monitor() started the monitor thread with ::android::netdutils::threadLaunch(this) and kept no thread handle. The destructor was an empty `virtual ~Monitor() {}`. When a Monitor (embedded as MDnsSdListener::mMonitor) was destroyed, nothing stopped or waited for the thread running Monitor::run(), which uses members such as mPollFds, mPollRefs and mCtrlSocketPair. In the shown old code, the control socket revents were handled by a switch with only a POLLIN case, so there was no exit path on hangup. The commit message describes this as a heap-use-after-free in MDnsSdListener::Monitor::run, found with mdns_service_fuzzer after about 500 rounds.
How the fix works
- server/MDnsSdListener.h: class Monitor gains a `std::thread* mRescanThread` member and `#include <thread>`. The empty `virtual ~Monitor() {}` is replaced by a declared, non-virtual `~Monitor()`.
- server/MDnsSdListener.cpp:MDnsSdListener::Monitor::Monitor(): the netdutils::threadLaunch(this) call is replaced by `mRescanThread = new std::thread(&Monitor::run, this)`. An ALOGE is logged if the thread is not joinable.
- server/MDnsSdListener.cpp:MDnsSdListener::Monitor::~Monitor() (new): closes mCtrlSocketPair[1]. Per the code comment, this interrupts poll in run() with revents 17 (POLLIN|POLLHUP). The destructor then calls mRescanThread->join() and deletes the thread object, so members stay valid until the thread has exited.
- server/MDnsSdListener.cpp:MDnsSdListener::Monitor::run(): the switch on mPollFds[0].revents is replaced by two ifs. If `revents & POLLHUP`, the thread frees mPollFds and mPollRefs, logs and returns. This is the new termination path. If `revents == POLLIN`, it reads one byte from mCtrlSocketPair[0] and calls rescan() for the RESCAN command, like the old `case POLLIN`.
Completeness
- The fix covers the Monitor object lifetime: destruction now waits for run() to return, which addresses the reported UAF in Monitor::run.
- Thread termination depends on the POLLHUP on mPollFds[0] that the destructor produces by closing mCtrlSocketPair[1].
- The new destructor does not close mCtrlSocketPair[0]. mPollFds/mPollRefs are freed by the exiting thread on the POLLHUP path.
- The joinable() check in the constructor only logs. std::thread construction either succeeds or throws (general platform knowledge).
- This commit does not change the lifetime of other objects used by run() (Context objects, DNSServiceRef entries, callbacks).
Behavior changes
- Monitor::~Monitor() now blocks until the monitor thread exits.
- The monitor thread now terminates when the control socket reports POLLHUP, and frees mPollFds/mPollRefs on exit.
- Monitor's destructor is no longer virtual.
- New log lines: ALOGE 'Unable to launch thread.' and VDBG logs 'Monitor recycling', 'Monitor thread leaving.' and 'Monitor recycled'.
Per major
- Android 14: same fix: commit 7dae058172ac in android-security-14.0.0_r3 (cherry-pick of 9c0c15f80cffb98b36284dd169a2e62e059dbbe3, Ignore-AOSP-First), recorded as resolved. At android-security-14.0.0_r29, 5/8 lines of the patched region are present.
- Android 15: not affected: not listed by the bulletin. The patched files server/MDnsSdListener.cpp and .h are absent at android-security-15.0.0_r17.
- Android 16: not affected: not listed by the bulletin. The patched files are absent at android-security-16.0.0_r8.
- Android 17: not affected: not listed by the bulletin. The patched files are absent at android-security-17.0.0_r1.
Unknowns
- Which production netd code path (outside the fuzzer) destroys MDnsSdListener/Monitor is not shown.
- How the unchanged parts of run() handle other control socket revents values (e.g. POLLERR/POLLNVAL) is not shown.
- The fix commits for Android 11, 12, 12L and 13 are not in the material.
- Why only 5/8 lines of the patched region are present at android-security-14.0.0_r29 is not shown.