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

            Bug ID: 524348
           Summary: [plasma-nm/openconnect] Clicking Connect while the SSO
                    web view is still loading deadlocks kded6 in
                    connectHost()
    Classification: Plasma
           Product: plasmashell
      Version First 6.7.4
       Reported In:
          Platform: EndeavourOS
                OS: Linux
            Status: REPORTED
          Severity: crash
          Priority: NOR
         Component: Networking in general
          Assignee: [email protected]
          Reporter: [email protected]
  Target Milestone: 1.0

Hey. I ran into a bug with the openconnect functionality in KDE. Here's what I
could find. Please note an LLM assisted me in gathering the info and with some
technical portions (backtrace and root cause), but I wrote the rest myself. I
hope this is okay.

DESCRIPTION
There's a freeze/hang bug in plasma-nm's openconnect SSO dialog. If you click
Connect while the login page is still loading/rendering, a deadlock occurs and
freezes the entire window - and with it the entirety of kded6 daemon.

STEPS TO REPRODUCE
1. Configure openconnect VPN with SAML/SSO webview login. In my case it's
AnyConnect via Cisco Secure Access with Microsoft Entra login flow.
2. Start it and let the QtWebEngine login dialog open. Mine is set to
auto-connect so it starts immediately.
3. Before the login page finishes rendering, click "Connect".

OBSERVED RESULT
The window becomes fully unresponsive and eventually the "application is not
responding" prompt comes up to kill it. No errors are shown. kded6 freezes
permanently and does not recover even after a few minutes. I think this is
because plasma-nm secret agent is a KDED module, so all other KDED modules in
the process freeze with it.

EXPECTED RESULT
Clicking Connect should either restart the login attempt or just be ignored
when a previous attempt is happening. It shouldn't freeze the GUI permanently.

SOFTWARE/OS VERSIONS
OS: EndeavourOS (Arch), kernel 7.1.8-arch1-3. Running on Wayland.
KDE: KDE Plasma 6.7.4, KDE Frameworks 6.28.0.
Qt: Qt 6.11.1, qt6-webengine 6.11.1-5.
plasma-nm 6.7.4-1, openconnect-git 1:9.21.r25.g70d1e79-1.

BACKTRACE
Both threads from the same core dump, symbolized with debuginfod. Qt stuff for
the actual button press are removed since I don't think they're relevant here.

GUI thread (joining the worker from the Connect button's slot):

  #10 __pthread_clockjoin_ex () at pthread_join_common.c:67
  #12 QThreadPrivate::wait () at qthread_unix.cpp:999
  #13 QThread::wait () at qthread.cpp:974
  #14 OpenconnectAuthWidget::connectHost (this=0x5607ea9fd010)
        at plasma-nm-6.7.4/vpn/openconnect/openconnectauth.cpp:375
  #15 ... QtPrivate::QSlotObjectBase::call / doActivate / QMetaObject::activate
...
  #18 QAbstractButton::clicked () at moc_qabstractbutton.cpp:254
  #21 QAbstractButton::mouseReleaseEvent () at qabstractbutton.cpp:987

openconnect worker thread (TID 3784), waiting on the semaphore. plasma-nm has
no
debug package on Arch, hence the raw offsets:

  #0  syscall (libc.so.6 + 0x11e4ed)
  #1  QSemaphore::acquire(int) (libQt6Core.so.6 + 0x2b9c60)
  #2  plasmanetworkmanagement_openconnect_pulseui.so + 0x24b47
  #3  libopenconnect.so.5 + 0x179ac
  #4  libopenconnect.so.5 + 0x2aa50
  #5  plasmanetworkmanagement_openconnect_pulseui.so + 0x25ad9

ROOT CAUSE
connectHost() (vpn/openconnect/openconnectauth.cpp:375) cancels the in-flight
worker
before restarting it:

    d->userQuit = true;
    if (write(d->cancelPipes[1], "x", 1)) {
        // not a lot we can do
    }
    d->workerWaiting.wakeAll();
    d->worker->wait();
    d->userQuit = false;

Both cancellation mechanisms miss the SSO web view case:

  - the cancel pipe is only observed while the worker sits in openconnect's
poll
    loop, and it does not;
  - d->workerWaiting is not the condition the worker is blocked on.

So d->worker->wait() blocks the GUI thread indefinitely.

What the worker is actually blocked on is d->waitForWebEngineFinish, the
QSemaphore
that libopenconnect's web view callback waits on. That semaphore is released
only
here, and in the equivalent handleWebEngineCookie / handleWebEngineUrl paths:

    if (!openconnect_webview_load_changed(d->vpninfo, &res)) {
        QSemaphore *waitForWebEngineFinish =
            d->waitForWebEngineFinish.fetchAndStoreRelaxed(nullptr);
        if (waitForWebEngineFinish) {
            waitForWebEngineFinish->release();
        }
    }

Those are GUI-thread slots driven by QWebEnginePage signals. Blocking the GUI
thread
in d->worker->wait() is exactly what prevents them from running, so the
semaphore is
never released, the worker never returns, and wait() never returns.


ADDITIONAL INFORMATION

If needed, I can provide the full core dump or run specific commands against
the core. Also let me know you need any additional info. Thank you for reading
this!

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

Reply via email to