https://bugs.kde.org/show_bug.cgi?id=525861

            Bug ID: 525861
           Summary: SIGSEGV in
                    DataControlOffer::retrieveData()/QHash::emplace:
                    use-after-free racing offer destruction against a
                    concurrent read
    Classification: Frameworks and Libraries
           Product: frameworks-kguiaddons
      Version First 6.30.0
       Reported In:
          Platform: NixOS
                OS: Linux
            Status: REPORTED
          Severity: crash
          Priority: NOR
         Component: general
          Assignee: [email protected]
          Reporter: [email protected]
  Target Milestone: ---

Created attachment 196272
  --> https://bugs.kde.org/attachment.cgi?id=196272&action=edit
systemd-coredump of the SIGSEGV crash (2026-09-17), zstd-compressed

## Summary

A Wayland `ext-data-control-v1` client (here, CopyQ's clipboard-monitor helper)
crashes with SIGSEGV inside `QHash<QString,QVariant>::emplace`, called from
`DataControlOffer::retrieveData()`. The coredump shows the crash's `this`
pointer pointing into memory that was already freed and reused elsewhere. It
looks like a UAF in kguiaddons' data-control client code.

## Environment

- kguiaddons: 6.30.0 (NixOS nixos-unstable, built 2026-09-14)
- Qt: 6.11.2
- Compositor: Hyprland 0.56.2
- Wayland protocol: ext-data-control-v1
- Triggering client: CopyQ 16.0.0's clipboard-monitor helper process (`copyq
--clipboard-access monitorClipboard`), via KSystemClipboard

## What's happening (from a coredump backtrace of both threads involved)

Two threads race on the same clipboard offer.

**Main (GUI) thread**, reading the current clipboard content:
```
QHash<QString, QVariant>::emplace<QVariant>(...)          <- SIGSEGV here
DataControlOffer::retrieveData(QString const&, QMetaType) const
QMimeDataPrivate::retrieveTypedData(QString const&, QMetaType) const
QMimeData::data(QString const&) const
...  (client's own clipboard-changed handler)
KSystemClipboard::changed(QClipboard::Mode)
QObject::event(QEvent*)
...
```

**`ClipboardThread`** (kguiaddons' dedicated Wayland dispatch thread), handling
a newer selection event at the same time:
```
DataControlDevice::ext_data_control_device_v1_selection(ext_data_control_offer_v1*)
QObject::~QObject()               <- destroys the previous DataControlOffer
QObject::destroyed(QObject*)
...
wl_display_dispatch_queue_pending()
ClipboardThread::run()
```

Per the ext-data-control-v1 protocol, the client must destroy the previous
`ext_data_control_offer_v1` as soon as a new `selection` event arrives.
`DataControlDevice::ext_data_control_device_v1_selection()` does exactly that,
on its own dispatch thread, with no coordination against the GUI thread, which
may be reading data out of that same offer at the same moment via
`QMimeData::data()` -> `DataControlOffer::retrieveData()`.

When two clipboard or selection changes land close together, the GUI thread can
still be mid-read of offer N when the dispatch thread destroys it to make way
for offer N+1. The GUI thread then reads and writes into freed memory.

## Evidence this is a genuine use-after-free

At the crash, `rdi` (the `this` for `QHash::emplace`, the hash it's writing
into) pointed at:

```
0x59cb...2640: "ariantMap,QString)"
```

That's a fragment of an unrelated Qt method-signature string, not a `QHash`.
The memory that used to back the `DataControlOffer`'s cached `QMimeData` had
already been freed and reused for something else by the time this frame ran.

## Impact

The crashing process is a helper/monitor process that its supervisor respawns
automatically, so it isn't immediately destructive. But it recurs under
ordinary use: repeated crashes from the same clipboard-read code path showed up
on the same machine days apart.

## Suggested fix direction

Synchronize access to a `DataControlOffer` between the thread that destroys it
(on `selection`) and any thread reading its data at the same time. For example,
refcount the offer and defer destruction until in-flight `retrieveData()` calls
finish, or guard offer destruction and data retrieval with a mutex.

I have the full two-thread coredump backtrace locally and can paste more of it
if useful.

---

This report (crash analysis and write-up) was produced with the help of an AI
coding assistant, Claude Code. I reviewed the coredump evidence and backtraces
myself and confirmed the conclusions before filing.

-- 
You are receiving this mail because:
You are watching all bug changes.

Reply via email to