Skip to content

fix: nemo-window-manage-views: fix use-after-free crash in desktop sl…#3781

Open
nathan9513-aps wants to merge 1 commit into
linuxmint:masterfrom
nathan9513-aps:Bug2481175
Open

fix: nemo-window-manage-views: fix use-after-free crash in desktop sl…#3781
nathan9513-aps wants to merge 1 commit into
linuxmint:masterfrom
nathan9513-aps:Bug2481175

Conversation

@nathan9513-aps
Copy link
Copy Markdown

Summary

Fixes a SIGABRT crash in nemo-desktop caused by a use-after-free (dangling pointer) on NemoWindowSlot inside an async GLib file-info callback.

Fixes: linuxmint/nemo#XXXX (update with actual issue number)


Problem

nemo-desktop crashed with the following assertion failure:

assertion failed: (NEMO_IS_WINDOW_SLOT (slot))

Signal: SIGABRT
Crashed process: /usr/bin/nemo-desktop

Root cause

The crash originates in got_file_info_for_view_selection_callback() in
src/nemo-window-manage-views.c.

When a directory change is initiated, begin_location_change() calls
nemo_file_call_when_ready(), passing the raw NemoWindowSlot * pointer as
callback_data. GLib schedules the callback to fire at idle time
(g_idle_add). If the NemoWindowSlot is destroyed between registration
and dispatch
(e.g. the desktop window is torn down during startup), the
pointer becomes a dangling reference. When the idle callback eventually fires,
the first thing it does is call nemo_window_slot_get_window(slot), which
hits the internal g_assert (NEMO_IS_WINDOW_SLOT (slot)) — and aborts.

Relevant stack frames (from coredump)

#4  g_assertion_message         nemo-window-slot.c:528
#6  nemo_window_slot_get_window nemo-window-slot.c:526
#8  got_file_info_for_view_selection_callback
                                nemo-window-manage-views.c:822
#9  desktop_callback_check_done nemo-desktop-directory-file.c:241
#10 call_ready_callbacks_at_idle
                                nemo-directory-async.c:1850

Solution

Applied GObject weak reference guard (Solution B):

Instead of passing the raw NemoWindowSlot * directly as callback_data, we
now allocate a small heap-resident sentinel struct (SlotWeakData) that holds
the slot pointer and is registered as a GWeakNotify on the slot object.

When GObject finalizes the slot, it calls slot_weak_notify(), which zeroes
wd->slot. When the callback eventually fires, it checks whether wd->slot
is still valid before touching the slot — and returns safely if not.

Registration time                 Idle dispatch time
─────────────────                 ──────────────────
SlotWeakData *wd = alloc()        if (wd->slot == NULL)
wd->slot = slot                       free(wd); return;  ← safe exit
g_object_weak_ref(slot,           slot = wd->slot;
  slot_weak_notify, wd)           g_object_weak_unref(...);
call_when_ready(..., wd)          free(wd);
                                  /* slot is alive, proceed */

If free_location_change() cancels a pending call before it fires, it
correctly retrieves the saved SlotWeakData * from the new
slot->determine_view_weak_data field, passes it as callback_data to
nemo_file_cancel_call_when_ready() (which matches on both callback pointer
and data pointer), removes the weak ref, and frees the sentinel — leaving no
dangling notifiers.

Show: https://bugzilla.redhat.com/show_bug.cgi?id=2481175

…ot callback

nemo_file_call_when_ready() was called with a raw NemoWindowSlot *
as callback_data. If the slot was destroyed between registration and
idle dispatch, the callback received a dangling pointer and crashed
immediately on the g_assert(NEMO_IS_WINDOW_SLOT(slot)) inside
nemo_window_slot_get_window().

Crash trace:
  SIGABRT ← g_assert failure
  nemo_window_slot_get_window()          nemo-window-slot.c:528
  got_file_info_for_view_selection_callback() nemo-window-manage-views.c:822
  desktop_callback_check_done()          nemo-desktop-directory-file.c:241
  call_ready_callbacks_at_idle()         nemo-directory-async.c:1850

Fix: use a GObject weak reference (Solution B).

Introduce SlotWeakData, a small heap-allocated sentinel that holds the
slot pointer and is registered as a GWeakNotify on the slot. When GObject
finalizes the slot, slot_weak_notify() zeroes wd->slot. The callback
checks this field at entry and returns safely if the slot is gone.

Add slot->determine_view_weak_data to NemoWindowSlot so that
free_location_change() can retrieve the correct SlotWeakData pointer,
pass it to nemo_file_cancel_call_when_ready() (which matches on both
callback and callback_data), remove the weak ref, and free the sentinel
without leaving dangling notifiers.

The same guard is applied to all three call-sites that register
got_file_info_for_view_selection_callback:
  - begin_location_change()
  - mount_not_mounted_callback()
  - the parent-redirect branch inside the callback itself

Files changed:
  src/nemo-window-slot.h         add determine_view_weak_data field
  src/nemo-window-manage-views.c implement weak-ref guard
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.

1 participant