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

            Bug ID: 527499
           Summary: Exclusive mode (RemoteAccess): reconnecting requests a
                    second SDDM greeter on the same VT, leaving the seat
                    without an active session; session lock/unlock also
                    fails when krdpserver runs as a systemd user service
    Classification: Plasma
           Product: KRdp
      Version First 6.8.0
       Reported In:
          Platform: NixOS
                OS: Linux
            Status: REPORTED
          Severity: crash
          Priority: NOR
         Component: general
          Assignee: [email protected]
          Reporter: [email protected]
                CC: [email protected]
  Target Milestone: ---

Created attachment 197415
  --> https://bugs.kde.org/attachment.cgi?id=197415&action=edit
Atached a patch that fixes the problem for me

Exclusive mode (RemoteAccess): reconnecting requests a second SDDM greeter on
the same VT, leaving the seat without an active session; session lock/unlock
also fails when krdpserver runs as a systemd user service

Description:

With "exclusive mode" enabled (ExclusiveMode=true, i.e.
OperationMode::RemoteAccess), the first RDP connection works: the local seat
switches to the SDDM greeter and the remote client gets the desktop on a
virtual monitor. After disconnecting and connecting again (from the same or
another client), the local seat ends up with no active session. The local
monitors show a frozen image, local keyboard and mouse do nothing, and the
remote client often only gets a black screen. Recovering needs `chvt` to the
user's VT from another session or a reboot.

There are two problems in server/SessionController.cpp.

1. switchToGreeter() is called on every connection

SessionController::onNewConnection() calls switchToGreeter()
(org.freedesktop.DisplayManager.Seat.SwitchToGreeter) on every activated
connection in RemoteAccess mode. It doesn't check whether the user's session is
still in the foreground. After the first connection, the greeter from that
connection is still running on the seat. SDDM 0.21 then creates another display
and puts it on the same VT as the existing greeter. That fails, and SDDM tears
it down:

    sddm[1421]: Adding new display...
    sddm[1421]: Using VT 1
    sddm[1421]: Greeter starting...
    krdpserver[2089]: Switched to greeter successfully.
    sddm-helper[3888]: Failed to take control of "/dev/tty1" ("sddm"):
Operation not permitted
    sddm[1421]: Auth: sddm-helper exited with 5
    sddm[1421]: Greeter stopped. SDDM::Auth::HELPER_TTY_ERROR
    sddm[1421]: Jumping to VT 1
    systemd-logind[947]: Removed session c4.
    kwin_wayland[1932]: Invalid framebuffer status: 
"GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"

Afterwards logind reports no active session on seat0, even though the first
greeter (VT1) and the user session (VT2) still exist:

    $ loginctl show-seat seat0 -p ActiveSession
    ActiveSession=
    $ loginctl show-session 2  -p VTNr -p Active   ->  VTNr=2  Active=no
    $ loginctl show-session c2 -p VTNr -p Active   ->  VTNr=1  Active=no

`chvt 2` brings the user session back. Switching back to VT1 leaves the seat
without an active session again, so the original greeter is no longer usable
either.

The same thing happens with SDDM autologin. In that case the user session
itself is on VT1, and even the first SwitchToGreeter fails with
HELPER_TTY_ERROR.

(SDDM picking an occupied VT is arguably also an SDDM bug. But KRdp shouldn't
ask for a new greeter when the user session isn't in the foreground at all.)

2. setSessionLocked() uses /org/freedesktop/login1/session/auto

krdpserver is started as a systemd user service
(app-org.kde.krdpserver.service), which doesn't belong to any logind session.
So the "auto" session object doesn't resolve:

    krdpserver: krdp: could not lock the logind session: "Unknown object
'/org/freedesktop/login1/session/auto'."

As a result, the user's session is never locked after the last remote client
disconnects. Anyone at the machine who switches to the user's VT gets an
unlocked desktop.

3. Screencast starts while the VT switch is still in progress

When the user's session is in the foreground at connect time, switchToGreeter()
is called and the virtual-monitor screencast starts immediately afterwards
(wrapper->session->start()). KWin loses the DRM devices in the middle of
setting up the virtual output:

    krdpserver: Switched to greeter successfully.
    kwin_wayland: Invalid framebuffer status: 
"GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"
    krdpserver: Forcing encoder to "libx264"
    kwin_wayland: drmModeListLessees() failed: Permission denied
    kwin_wayland: Atomic commit failed: EACCESS

The client then shows only a black screen with a cursor. The code already has a
comment about this ("we also want something to prevent a VT switch breaking
things").

4. Stream stalls for good after a GFX channel reset (black screen, mstsc stuck
at high CPU)

Sometimes mstsc sends RDPGFX CapsAdvertise again after the stream has started.
Here it happened only on some reconnects, and only those sessions failed.
VideoStream::onCapsAdvertise() destroys the surface and clears pendingFrames.
But setActiveEncodingMode() returns early because the mode (H.264) hasn't
changed. So the encoder and the queued frames survive, and no new key frame is
produced. The client then gets P-frames on a fresh surface with no reference
picture. mstsc hangs at high CPU without sending FrameAcknowledge, and the
server stops sending once maxInFlight is reached:

    GFX channel reset (re-advertisement), resetting surface state
    Selected encoding mode: "h264"
    Encoder backpressure activated 4
    Processed 9 frames in the last second.
    Processed 0 frames in the last second.   (repeats until the client is
killed)
    skipping empty buffer 8294400 1

The mstsc process has to be killed from Task Manager. The next connection
works.

5. Recreating a stream reuses a PipeWire fd that has already been closed

VideoStreamSurface passes the same pipeWireFd to every PipeWireEncodedStream /
PipeWireSourceStream it creates. KPipeWire's PipeWireCore hands it to
pw_context_connect_fd(), which takes ownership and closes it when the core goes
away. So once a stream has been recreated (for example on an encoding-mode
change, or with the fix for 4), the new stream gets a closed fd, and krdpserver
aborts:

    error: "Failed to connect to PipeWire" 48
    failed to set up stream for 85 "Failed to connect to PipeWire"
    'source->loop == &impl->loop' failed at ../spa/plugins/support/loop.c:189
remove_from_poll()
    app-org.kde.krdpserver.service: Failed with result 'core-dump'.

Suggestion (also in the patch, not a bug): in RemoteAccess mode, disconnect the
remote client when the user logs in at the local greeter (the session becomes
Active again), the way Windows does. Don't lock the session in that case.

Proposed fix (patch attached, applies to and builds against 6.8.0):

- Resolve the user's graphical session from org.freedesktop.login1.User.Display
on /org/freedesktop/login1/user/self, and use it for Lock/Unlock. Fall back to
session/auto if that doesn't resolve.
- In RemoteAccess mode, only call SwitchToGreeter when that session is
currently Active. If it isn't, the greeter (or another session) already owns
the seat, so skip the switch and just unlock for the remote client.
- On a GFX channel reset (CapsAdvertise after caps were already confirmed),
reset activeEncodingMode so setActiveEncodingMode() recreates the encoder. This
clears the frame queue and restarts the stream with a key frame.
- VideoStreamSurface owns the fd it receives and passes a
fcntl(F_DUPFD_CLOEXEC) duplicate to each KPipeWire stream. It closes its own
copy in the destructor.
- While remote clients are connected in RemoteAccess mode, poll the session's
Active property once a second. On an inactive -> active transition, close the
remote connections. Skip setSessionLocked(true) when the session is active
locally.
- When switching to the greeter, start the screencast only once the user's
session has become inactive (polling Active every 100 ms, max 5 s), plus a 500
ms grace period.

Steps to reproduce:
1. Plasma 6.8 Wayland, SDDM 0.21 (Wayland greeter), log in normally.
2. System Settings > Remote Desktop: enable, "Use system user", exclusive mode
on.
3. Connect from a Windows mstsc client, then disconnect (close the client
window).
4. Connect again.

Observed: local seat frozen, ActiveSession empty, remote often black.
Expected: the greeter from the first connection stays on the local monitors,
and the remote client gets the desktop again.

Environment:
- NixOS 26.11 (unstable 2026-10-17), kernel 7.2.11
- Plasma / KWin / KRdp 6.8.0, KPipeWire 6.8.0, FreeRDP 3, SDDM 0.21.0
(DisplayServer=wayland)
- Intel UHD 770 + AMD Radeon Pro WX 3200 (3x 4K outputs on the AMD card)
- Client: Windows Remote Desktop Connection (mstsc)

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

Reply via email to