fix(kvm): one desktop-tab owner per seat via advisory lock (VA-108) #112

Merged
Claude-Run merged 1 commit from fix/VA-108-single-kvm-owner-per-seat into main 2026-07-04 18:06:14 +02:00
Member

Two vervain-agent instances can run on one host: the root system service (attaches to seat0's active session, VA-84/VA-107) and a per-user instance started by systemd --user at login. Both expose the desktop tab, so both could open a portal RemoteDesktop session, grab a uinput device, and drive XTEST on the same seat at once: double input injection, competing portal sessions, duplicated capture. The root cause is packaging that installs and enables both a system unit and a per-user unit on the same host; neither knows about the other.

Add a per-seat KVM ownership guard (crate::seat_lock): before publishing session addressing into vervain_agent_kvm::session_ctx (the single gate every capture/input backend reads at connect time), each instance takes a non-blocking advisory flock on /run/user//vervain-agent.kvm.lock. Both instances address the same active user session through that path and contend on the same file. The winner publishes the addressing and drives the seat; the loser publishes None, so every backend returns KvmError::NotAvailable and opens no portal session and no input device. First acquirer wins; because systemd starts the root system service at boot before any user logs in, the root service is the de-facto sole KVM provider and the per-user instance yields to it. The lock is an open file description, so the kernel releases it if the holder exits or crashes, and session_watch republishes through the same guard, which moves the lock when the active session switches.

All three publish sites (root startup seed, per-user seed, and the logind supervisor's republish) route through active_session::publish_guarded so the guard applies uniformly.

Document the root cause and the intended single-instance deployment in docs/single-instance-deployment.md: install exactly one unit per host (root system service on a managed host, per-user unit on an unprivileged host), with the seat lock as the in-process safety net against a stray second launch.

#VA-108

Two vervain-agent instances can run on one host: the root system service (attaches to seat0's active session, VA-84/VA-107) and a per-user instance started by systemd --user at login. Both expose the desktop tab, so both could open a portal RemoteDesktop session, grab a uinput device, and drive XTEST on the same seat at once: double input injection, competing portal sessions, duplicated capture. The root cause is packaging that installs and enables both a system unit and a per-user unit on the same host; neither knows about the other. Add a per-seat KVM ownership guard (crate::seat_lock): before publishing session addressing into vervain_agent_kvm::session_ctx (the single gate every capture/input backend reads at connect time), each instance takes a non-blocking advisory flock on /run/user/<uid>/vervain-agent.kvm.lock. Both instances address the same active user session through that path and contend on the same file. The winner publishes the addressing and drives the seat; the loser publishes None, so every backend returns KvmError::NotAvailable and opens no portal session and no input device. First acquirer wins; because systemd starts the root system service at boot before any user logs in, the root service is the de-facto sole KVM provider and the per-user instance yields to it. The lock is an open file description, so the kernel releases it if the holder exits or crashes, and session_watch republishes through the same guard, which moves the lock when the active session switches. All three publish sites (root startup seed, per-user seed, and the logind supervisor's republish) route through active_session::publish_guarded so the guard applies uniformly. Document the root cause and the intended single-instance deployment in docs/single-instance-deployment.md: install exactly one unit per host (root system service on a managed host, per-user unit on an unprivileged host), with the seat lock as the in-process safety net against a stray second launch. #VA-108
fix(kvm): one desktop-tab owner per seat via advisory lock (VA-108)
All checks were successful
Check / fmt + clippy + tests (pull_request) Successful in 3m57s
Create release / Create release from merged PR (pull_request) Has been skipped
94b2cba5df
Two vervain-agent instances can run on one host: the root system service (attaches to seat0's active session, VA-84/VA-107) and a per-user instance started by systemd --user at login. Both expose the desktop tab, so both could open a portal RemoteDesktop session, grab a uinput device, and drive XTEST on the same seat at once: double input injection, competing portal sessions, duplicated capture. The root cause is packaging that installs and enables both a system unit and a per-user unit on the same host; neither knows about the other.

Add a per-seat KVM ownership guard (crate::seat_lock): before publishing session addressing into vervain_agent_kvm::session_ctx (the single gate every capture/input backend reads at connect time), each instance takes a non-blocking advisory flock on /run/user/<uid>/vervain-agent.kvm.lock. Both instances address the same active user session through that path and contend on the same file. The winner publishes the addressing and drives the seat; the loser publishes None, so every backend returns KvmError::NotAvailable and opens no portal session and no input device. First acquirer wins; because systemd starts the root system service at boot before any user logs in, the root service is the de-facto sole KVM provider and the per-user instance yields to it. The lock is an open file description, so the kernel releases it if the holder exits or crashes, and session_watch republishes through the same guard, which moves the lock when the active session switches.

All three publish sites (root startup seed, per-user seed, and the logind supervisor's republish) route through active_session::publish_guarded so the guard applies uniformly.

Document the root cause and the intended single-instance deployment in docs/single-instance-deployment.md: install exactly one unit per host (root system service on a managed host, per-user unit on an unprivileged host), with the seat lock as the in-process safety net against a stray second launch.

#VA-108
Claude-Run deleted branch fix/VA-108-single-kvm-owner-per-seat 2026-07-04 18:06:15 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/vervain-agent!112
No description provided.