#1151170 gnome-keyring: disconnected Secret Service property reader can abort entire daemon

Package:
gnome-keyring
Source:
gnome-keyring
Description:
GNOME keyring services (daemon and tools)
Submitter:
Marcio Teixeira
Date:
2026-10-20 07:41:02 UTC
Severity:
normal
Tags:
#1151170#5
Date:
2026-10-17 17:21:21 UTC
From:
To:
DISCLOSURE OF AUTHORSHIP AND REVIEW STATUS

I am the user of the affected system and the contact for follow-up.

This report, the attached reproducer and the candidate patch were generated
by an AI assistant using Copilot SDK in VS Code. They have NOT been reviewed
by a human. Tests described below were executed by the agent. Authorization
to investigate or submit is not a claim of human technical review. Please
treat the explanation and patch as unreviewed candidates, not an endorsed
upstream fix. The submitter should retain this disclosure when forwarding.

Summary
-------

gnome-keyring-daemon can abort while handling a pending
org.freedesktop.DBus.Properties.Get request from a client which has already
disconnected. A missing per-client record propagates a NULL return without
the GError expected by GDBus, which asserts and terminates the daemon.

This was observed in one real private headless Secret Service instance,
and reproduced with the distribution /usr/bin/gnome-keyring-daemon using
only fictitious data and an isolated D-Bus. The exact client that triggered
the real incident is unknown. Normal polling tests did not reproduce the
failure; the attached test deliberately widens the race window.

Environment actually tested
---------------------------

Debian GNU/Linux forky/sid userspace with mixed testing/unstable
repositories, amd64, WSL2 kernel 6.18.54.1-microsoft-standard-WSL2.
This is not a claim of reproduction on a clean stable Debian installation.
gnome-keyring 48.0-1 (distribution binary)
libglib2.0-0t64 2.90.1-2
libgck-1-0 3.41.2-6+b1
libgcr-base-3-1 3.41.2-6+b1
libgcrypt20 1.12.4-2
dbus 1.16.2-8
systemd 262-1
python3-gi 3.58.0-1, gir1.2-glib-2.0 2.90.1-2

Observed failure
----------------

gkd_secret_service_get_pkcs11_session: assertion 'client' failed
secret_objects_lookup_gck_object_for_path: assertion 'session' failed
GLib-GIO:ERROR:../../../gio/gdbusconnection.c:4765:
invoke_get_property_in_idle_cb: assertion failed: (error != NULL)

The user service exited with signal 6/SIGABRT. Clients lost access to
credentials until the private daemon was started and unlocked again.
No credential disclosure or storage corruption was demonstrated. No real
keyring core dump was inspected or included. This is a service-availability
report, not a claim of remote code execution or a CVE assignment.

Reproduction (attach reproduce-disconnect.py)
-------------------------------------------

Requires /usr/bin/python3 with PyGObject/Gio, dbus-daemon, busctl and the
distribution gnome-keyring-daemon. No root privileges are required.

  /usr/bin/python3 -I -B reproduce-disconnect.py queued --count 3000 \
      --repeat 5 --expect-crash --daemon /usr/bin/gnome-keyring-daemon

The script creates a disposable HOME, storage, control directory and private
bus with no service activation. Core dumps are disabled. It pauses only
its own disposable foreground daemon, sends property reads through clients
which disconnect, resumes it and checks for the exact assertion signature.
All credentials are fictitious. It never uses the user's session bus.

The --expect-crash mode succeeds if at least one repetition observes the
specific SIGABRT signature. The race is nondeterministic: one run without
failure does not establish absence of the bug.

Controls:
  /usr/bin/python3 -I -B reproduce-disconnect.py persistent --count 1000 \
      --daemon /usr/bin/gnome-keyring-daemon
  /usr/bin/python3 -I -B reproduce-disconnect.py busctl --count 500 \
      --daemon /usr/bin/gnome-keyring-daemon

Expected: a disconnected client's pending request should fail or be
discarded without killing the Secret Service.
Actual: the complete daemon can abort.

Source-level explanation (AI analysis, not independently reviewed)
----------------------------------------------------------------

In upstream 48.0 daemon/dbus/gkd-secret-service.c,
service_name_owner_changed removes the disconnected client from the clients
table. A later gkd_secret_service_get_pkcs11_session lookup returns NULL.
In daemon/dbus/gkd-secret-objects.c,
secret_objects_lookup_gck_object_for_path returns early on the missing
session without populating error_out. A collection property getter passes
that NULL result to GLib, which requires an accompanying GError.

Candidate patch (attach 01-disconnected-client.patch)
----------------------------------------------------

The patch treats the missing client as a possible disconnect rather than
a critical assertion and explicitly returns a D-Bus error if the object
lookup cannot get a session, freeing the temporary path identifiers.
It prevents the reproduced daemon abort; it does not redesign client
lifetime handling or claim to solve all Secret Service races.

It applies to the official upstream 48.0 and 51.1 source tarballs.
Upstream archive SHA-256:
48.0: f20518c920e9ea3f9c9b8b44be8c50d8d7feecd0dd5624960f77bd2ca4fbeb9d
51.1: dfe7adc5876ef0670e7eba2907799bdbb8875ce58bb4208e1a52169bd16a47ca

The base 48.0 source was built with Meson 1.12.1, GCC 16.2, using:
  -Dssh-agent=false -Dpam=false -Dsystemd=disabled -Dselinux=disabled
  -Dmanpage=false -Ddebug-mode=false
Only daemon/gnome-keyring-daemon was built for use in isolated tests.
The unpatched rebuilt 48.0 also reproduced the failure.

Patched private build evidence, on the same host:
- 48.0: 10 x 5000 queued reads, no abort; a functional property read and
  collection Lock were checked after every repetition.
- 51.1: 5 x 5000 queued reads, same result. This was an upstream private
  build, not Debian 51.1-3 package testing.
- Eight upstream daemon/D-Bus suites and the secure-memory test executable
  passed in an isolated bus on the patched 48.0 test build, with
  debug-mode=true required for the upstream test hooks.

These are bounded regression results, not exhaustive assurance or an
estimate of daily crash frequency. The private build was subsequently
removed from active use in favour of the distribution binary to avoid
maintaining a downstream daemon. Its patch is supplied for maintainer review.

Related public report (not proof of identical local trigger):
https://github.com/jkoestinger/omarchy-vpn/issues/42

No identical Debian BTS entry was identified in a limited title/web search.
That search is not exhaustive; please merge or redirect if this is a duplicate.
Suggested severity is normal, subject to maintainer triage.

#1151170#10
Date:
2026-10-19 00:15:07 UTC
From:
To:
Another independent reproduction, in case it helps with reviewing.

**Environment**: gnome-keyring 51.1 (Debian package 51.1-3, Debian
testing), headless user session (systemd user units, D-Bus session
bus, no graphical session). The `login` collection is locked; there is
no auto-unlock at login.

**Reproduction**: with the collection locked, start 4 `secret-tool
lookup` clients at the same time (or 3 or more `gh auth token` calls,
which go through go-keyring's `Unlock`/`Prompt`).

**Observed** (identical across prompter variants: `gcr-prompter`
absent, `org.gnome.keyring.SystemPrompter` activation pointing at
`/bin/false`, and a functional prompter that answers every prompt as
cancelled, without opening any window):

- one client fails right away (~0.02 s);
- the other 3 stay blocked waiting for `Completed`; with an external
limit of 150 s, they were still blocked at the limit;
- any later client, even alone, also blocks;
- `Dismiss` on a stuck prompt is only accepted from the requesting
connection, so a third party cannot release it;
- restarting the daemon unblocks future clients but not the ones
already waiting, because libsecret/go-keyring do not watch for the
loss of the `org.freedesktop.secrets` owner.

With a single client, the same setup refuses immediately (prompt
dismissed, no hang).

**Reading of the code** (matches the analysis in this issue): in
`daemon/dbus/gkd-secret-unlock.c`, `mark_as_complete` pops the next
item and calls `perform_next_unlock(other)`, which sees the queue is
not empty and enqueues it again, so no request progresses.

The same section is unchanged on `main` when we checked. We would be
glad to retest a build with !92 against this scenario.

**Downstream mitigation** (for others hitting this in headless
sessions): fail-fast guards that refuse before calling the service
while the collection is locked, plus an external monitor that restarts
the daemon when prompts stay pending for more than a few seconds. This
protects future clients only; already blocked clients must be
terminated.

#1151170#15
Date:
2026-10-20 07:38:13 UTC
From:
To:
Thank you for taking the time to report this issue and helping to make
Debian better. However, the Debian GNOME team is small and does not
have the available time and energy to additionally handle requests for
upstream development in most cases. The issue you identified is an
upstream issue and needs to be reported there instead of here. That
way, the issue can be fixed for everyone instead of only for Debian.

https://gitlab.gnome.org/GNOME/gnome-keyring/-/work_items
https://gitlab.gnome.org/GNOME/gnome-keyring/-/merge_requests

I am closing this bug report since the team has too many open bug
reports to manage well. There isn't anything unique to Debian in this
bug report. In your bug report, you specifically wrote that the issue
also happens outside the Debian build.

Thank you,
Jeremy Bícha