Repository navigation
fingerprint: reset device proxy on terminate - #1068
Open
juriSacchetta wants to merge 1 commit into
Open
juriSacchetta wants to merge 1 commit into
juriSacchetta wants to merge 1 commit into
Conversation
terminate() only released the device when the verification had not been aborted. On abort the proxy stayed alive, and since it borrows g_dbus->m_connection rather than sharing ownership of it, it outlived the connection that run() destroys a few lines later. The proxy was then destroyed during static destruction of g_pAuth, unreffing its signal slots through a dangling Connection and segfaulting in libsdbus-c++. abort is set when fprintd reports verify-disconnected, so any sensor disconnect while locked turned a successful unlock into a SIGSEGV at exit. Before 8bac7da the connection was a member of SDBUSState declared ahead of the proxies, so reverse member destruction kept the ordering safe and the early return was harmless. Moving the connection to g_dbus removed that guarantee.
There was a problem hiding this comment.
Pull request overview
This PR fixes a shutdown-time use-after-free in the fingerprint auth implementation by ensuring the fprintd device proxy cannot outlive the D-Bus connection it borrows, addressing the segfault described in #1067.
Changes:
- Update
CFingerprint::terminate()to always resetm_sDBUSState.device, even when the session was aborted (e.g.,verify-disconnected). - Add an inline comment documenting the proxy lifetime constraint (borrowed connection).
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1067.
The bug
CFingerprint::terminate()only released the fprintd device when the verification had not been aborted:m_sDBUSState.abortis set inhandleVerifyStatus()onMATCH_DISCONNECTED, i.e. whenever fprintd reportsverify-disconnected. On that path the device proxy is kept alive.The proxy is created with the reference overload:
m_sDBUSState.device = sdbus::createProxy(*g_dbus->m_connection, FPRINT, path);which borrows the connection instead of sharing ownership of it, so the proxy must not outlive it. But
run()destroys the connection atg_dbus.reset()whileg_pAuthis left to static destruction, so the ordering at exit is:g_pAuth->terminate()— skipsreleaseDevice()because ofabort, proxy survivesg_dbus.reset()—CDbusandm_connectiondestroyedmainreturns,exit()destroysg_pAuth→~CFingerprint→~Proxy~Proxyunrefs its signal slots through a lambda capturing the now-danglingConnection, and hyprlock segfaults inConnection.cpp:640. Backtrace and logs are in #1067.The session is already unlocked at that point, so the user-visible damage is limited, but hyprlock terminates on a signal instead of returning 0.
Regression
Yes, and I got this wrong in the issue — I have corrected it there.
Before 8bac7da (#1029)
SDBUSStatelooked like this:Members are destroyed in reverse declaration order, so
devicewas always destroyed beforeconnectionand the early return interminate()was harmless. Moving the connection out tog_dbusremoved that guarantee without changingterminate(). v0.9.6 is the first tag containing the commit.The fix
Reset the proxy unconditionally, so it cannot outlive the connection regardless of which branch was taken.
terminate()runs beforeg_dbus.reset()inrun(), so this is early enough.Note for maintainers
This makes the reported crash go away, but the underlying fragility is that
g_pAuthis the only global in that teardown block left to static destruction — everything around it (g_pSeatManager,g_asyncResourceManager,g_pRenderer,g_pEGL) is reset explicitly beforeg_dbus. Addingg_pAuth.reset();beforeg_dbus.reset();would make the ordering explicit and cover any future proxy held by an auth implementation. I left it out to keep this diff to the actual bug — happy to add it if you would prefer that instead of, or on top of, this change.Testing
clang-format --dry-run --Werrorclean.