xfce4-screensaver 4.20.2: Lock Screen Bypass via Daemon Crash (Rapid Keystroke Trigger)
Summary
xfce4-screensaver 4.20.2 can be crashed by rapidly pressing Fn+Super (Windows key) while the lock screen is active. The daemon segfaults due to a use-after-free in gs-manager.c:recreate_windows(), causing the lock screen to disappear entirely and granting full desktop access without authentication.
This is a different attack vector from #187 (closed) (which required HDMI cable manipulation). This vulnerability requires only a keyboard and is reproducible by hand in under 5 seconds.
Affected Versions
- Confirmed vulnerable: 4.20.2 (current default on Kali Linux 2025.4, Debian testing)
- Not affected: 4.20.1
- Fix status: The patch merged for #187 (closed) (commit 4436087c, "manager: Fix keyboard leak when recreating windows") does not prevent this crash. When that patch is applied, the screensaver instead enters a state where the password field is unresponsive (blank screen, no keyboard input accepted), requiring a hard reboot — consistent with the regression reported by @MuratAWARE7 in #187 (closed).
Reproduction Steps
Environment: Any X11 session running xfce4-screensaver 4.20.2 (tested on Kali Linux 2025.4, kernel 6.18.5).
- Lock the screen
- Rapidly press Fn+Super (the Windows/Meta key combined with the Fn key) repeatedly for 3–5 seconds
- The lock screen disappears. The desktop is fully accessible without entering a password.
No external monitor, USB device, or special hardware is required. A standard laptop keyboard is sufficient.
Verification
After the bypass, the following confirms the daemon is dead:
$ xfce4-screensaver-command --query
xfce4-screensaver-Message: Screensaver is not running!
$ dbus-send --session --dest=org.xfce.ScreenSaver --print-reply \
/org/xfce/ScreenSaver org.xfce.ScreenSaver.GetActive
boolean falseKernel log shows the segfault:
kernel: xfce4-screensav[PID]: segfault at 8 ip 00007f63fa3fd678 sp 00007fff24297eb0 error 4 in libgtk-3.so.0.2419.32or:
kernel: xfce4-screensav[PID]: segfault at 1000000002 ip 0000001000000002 sp 00007ffc21a2b588 error 14Root Cause Analysis
Regression introduced by the overlay refactor
The bug was introduced by two commits in 4.20.2:
- "manager: Use only one permanent window as overlay" — replaced per-monitor temporary overlays (
GList *overlays) with a single persistent popup window (GtkWidget *overlay) - "manager: Grab devices on overlay when recreating windows" — simplified
recreate_windows()to a direct function call
What was removed
In 4.20.1, the add_overlays() function contained explicit safety logic that was deleted in the refactor:
/* 4.20.1: add_overlays() — DELETED in 4.20.2 */
g_hash_table_iter_init (&iter, manager->priv->windows);
while (g_hash_table_iter_next (&iter, NULL, &window)) {
g_signal_handlers_disconnect_by_func (window, remove_overlays, manager);
disconnect_window_signals (manager, window); /* ← disconnects before destroy */
}
/* we need to disconnect_window_signals() right now above to avoid an X11 error that looks
* like a bug in GtkSocket/GtkPlug, so we also need to reset this flag just in case */
manager->priv->dialog_up = FALSE; /* ← resets dialog state */In 4.20.2, recreate_windows() destroys all windows without these protections:
/* 4.20.2: recreate_windows() — no signal disconnection, no dialog_up reset */
g_hash_table_remove_all (manager->priv->jobs);
g_hash_table_remove_all (manager->priv->windows); /* ← destroys with signals still connected */Crash mechanism
- Screen is locked. The dialog process (
xfce4-screensaver-dialog) is running,dialog_up = TRUE, with signal handlers connected to the GSWindow widgets (includingwindow_dialog_up_changed_cb,window_grab_broken_cb, etc.) - Rapid Fn+Super keypresses generate X11 events that cause the screensaver dialog to be killed and respawned in quick succession.
dialog_process_watch()detects the dialog dying (G_IO_HUP) and callspopdown_dialog()→gs_window_dialog_finish().- Simultaneously or shortly after,
g_hash_table_remove_all(manager->priv->windows)firesgs_window_destroy()on each window via the hash table's GDestroyNotify callback. gs_window_destroy()callsgs_window_cancel_unlock_request()→popdown_dialog()on a window that is being destroyed, while signal handlers still reference GTK widgets that are being torn down.- The still-connected signal handlers fire during GTK's event loop drain, accessing freed widget memory.
- Segfault: depending on heap state, this manifests as either:
- NULL + offset dereference (error 4) inside
gtk_widget_set_parent— widget pointer was zeroed after free - Wild function pointer jump (error 14) to addresses like
0x1000000002/0x1500000002— vtable pointer overwritten by heap reuse, low bytes0x02consistent with a small integer overwriting what was a valid code pointer
- NULL + offset dereference (error 4) inside
Crash Evidence
Crash — xfce4-screensaver 4.20.2 (Kali Linux)
xfce4-screensaver-dialog[58677]: pam_unix(xfce4-screensaver:auth): conversation failed
kernel: xfce4-screensav[58109]: segfault at 1000000002 ip 0000001000000002 sp 00007ffc21a2b588 error 14- Instruction fetch from corrupted address 0x1000000002
- Heap reuse overwrote vtable pointer with small integer data
Proposed Fix
Restore the safety guards from 4.20.1's add_overlays() into 4.20.2's recreate_windows():
static void
recreate_windows (GSManager *manager) {
GdkDisplay *display = gdk_display_get_default ();
guint n_monitors = gdk_display_get_n_monitors (display);
+ GHashTableIter iter;
+ gpointer window;
gs_debug ("Reconfiguring monitors, recreating windows");
+ /* Disconnect window signals before destroying to prevent use-after-free
+ * via GtkSocket/GtkPlug callbacks during teardown (see 4.20.1 add_overlays) */
+ g_hash_table_iter_init (&iter, manager->priv->windows);
+ while (g_hash_table_iter_next (&iter, NULL, &window)) {
+ disconnect_window_signals (manager, window);
+ }
+ manager->priv->dialog_up = FALSE;
#ifdef ENABLE_X11
if (manager->priv->grab != NULL) {
gs_grab_move_to_window (manager->priv->grab,
gtk_widget_get_window (manager->priv->overlay),
display, FALSE, FALSE);
}
#endif
g_hash_table_remove_all (manager->priv->jobs);
/* ... rest unchanged ... */This is the minimal fix. The XSetInputFocus approach from commit 4436087c addresses a different symptom (keyboard leak) but does not prevent the daemon crash, and introduces its own regression (unresponsive password field after monitor changes).
Severity Assessment
CVSS:3.1 — AV:P/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H — 6.8 (Medium)
- Attack Vector: Physical — requires physical access to the keyboard
- Attack Complexity: Low — reproducible by hand in under 5 seconds, no special tools needed
- Privileges Required: None — works against any locked session
- User Interaction: None — no action needed from the logged-in user
- Impact: High across CIA — full desktop access including files, browser sessions, credentials, and the ability to execute arbitrary commands as the locked-in user
Relationship to Existing Issues
- #187 (closed) (XFCE4-Screensaver <= 4.20.2 Login Bypass Vulnerability) — same vulnerable code path (
recreate_windows()), different trigger (HDMI vs keyboard), different failure mode (keyboard leak vs daemon crash). The fix merged for #187 (closed) does not prevent this crash.