Skip to content

gnome-wall-clock.c: Fix use-after-free in 'changed' signal handlers. - #276

Open
Tedpac wants to merge 1 commit into
linuxmint:masterfrom
Tedpac:fix-wall-clock-use-after-free
Open

gnome-wall-clock.c: Fix use-after-free in 'changed' signal handlers.#276
Tedpac wants to merge 1 commit into
linuxmint:masterfrom
Tedpac:fix-wall-clock-use-after-free

Conversation

@Tedpac

@Tedpac Tedpac commented Sep 3, 2026

Copy link
Copy Markdown

Fixes linuxmint/cinnamon-screensaver#503 (filed here originally and moved to cinnamon-screensaver: the process that dies is the screensaver, but the faulting code is this library).

Problem

GnomeWallClock connects on_schema_change and on_tz_changed to the "changed" signals of its GSettings and GFileMonitor with plain g_signal_connect() and never disconnects them. dispose() only unrefs the two objects.

That is not enough. GLib delivers settings change notifications asynchronously and holds a strong reference on the GSettings while a notification is queued (g_settings_backend_dispatch_signal()), so unref'ing it in dispose() does not guarantee it dies with the clock. If the clock is finalized while a notification is in flight, the handler still runs with a dangling self:

#0  g_settings_get_value              (libgio-2.0.so.0)
#1  g_settings_get_boolean            (libgio-2.0.so.0)
#2  update_format_string              (libcinnamon-desktop.so.4)
#3  on_schema_change                  (libcinnamon-desktop.so.4)
#4  g_cclosure_marshal_VOID__STRINGv  (libgobject-2.0.so.0)
...
#7  g_signal_emit                     (libgobject-2.0.so.0)
...
#17 g_main_context_iteration          (libglib-2.0.so.0)

How cinnamon-screensaver hits it

On resume from suspend, logind's Active property flips and the screensaver destroys and rebuilds its stage (manager.refresh_stage()), dropping the old clock widget and finalizing its WallClock. If a change to org.cinnamon.desktop.interface is delivered in that same main loop iteration, the queued handler fires on the freed clock and the screensaver segfaults, leaving the session on the "Something went wrong" fallback screen. A manual lock never rebuilds the stage, which is why only resume crashes.

The code is unchanged since the 2013 import and the bug is a race, which is probably why it is rarely reported. Any applet or desklet that uses WallClock is exposed the same way.

Fix

Connect both handlers with g_signal_connect_object() so they are disconnected automatically when the clock is destroyed, as gnome-idle-monitor.c and gnome-rr.c already do. on_tz_changed has the same latent problem with the GFileMonitor, so it gets the same treatment. No API or ABI change.

Testing

Built gnome-wall-clock.c before and after the change into a small test program that creates a GnomeWallClock plus a second GSettings on the same schema whose "changed" handler drops the clock, mirroring the screensaver's stage teardown. A second process then changes clock-use-24h in an isolated D-Bus/dconf session:

Result
Before segfault in g_settings_get_value() (exit 139)
After clock destroyed cleanly, process exits normally

Also checked that a live clock still reacts to the same settings change after the patch (the format switches between 00:06 and 12:06 AM).

The "changed" handlers for the GSettings and the GFileMonitor are
connected with g_signal_connect() and never disconnected; dispose()
only unrefs the two objects.

That does not guarantee the handlers stop running. GLib dispatches
settings change notifications asynchronously and holds a strong
reference on the GSettings while a notification is queued
(g_settings_backend_dispatch_signal()). If the clock is finalized in
the meantime, the GSettings outlives it, on_schema_change() still runs
with a dangling GnomeWallClock, and update_format_string() crashes in
g_settings_get_value().

cinnamon-screensaver hits this on resume from suspend: when logind's
Active property flips, it destroys and rebuilds its stage, dropping the
old clock widget and its WallClock, in the same main loop iteration in
which a change to org.cinnamon.desktop.interface is delivered. A manual
lock never rebuilds the stage, which is why only resume crashes.

Connect both handlers with g_signal_connect_object() so they are
disconnected automatically when the clock is destroyed, as
gnome-idle-monitor.c and gnome-rr.c already do.

Fixes linuxmint/cinnamon-screensaver#503.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cinnamon screensaver crashes after resuming from suspend

1 participant