mirror of
https://github.com/joleuger/vuinputd.git
synced 2026-07-17 16:36:03 +00:00
Move fallbackdm into own repository.
This commit is contained in:
parent
e5bb81f86e
commit
8d1627ee42
5 changed files with 3 additions and 302 deletions
|
|
@ -549,7 +549,7 @@ To further mitigate these risks, `vuinputd` could be extended to parse the host'
|
|||
|
||||
### **Decision**
|
||||
|
||||
`fallbackdm` is implemented as a **logind-managed fallback graphical session**.
|
||||
`fallbackdm` is implemented as a **logind-managed fallback graphical session**. It is available at https://github.com/joleuger/fallbackdm.
|
||||
|
||||
It runs only when **no other graphical session is active** on the seat and exists solely to:
|
||||
|
||||
|
|
|
|||
|
|
@ -395,7 +395,7 @@ The following approaches can be used to prevent or mitigate this behavior.
|
|||
|
||||
### Solution 1: Use KMSCON (DRM/KMS-based console)
|
||||
|
||||
A robust solution is to replace the kernel VT text console with a **DRM/KMS-based console** such as `kmscon`.
|
||||
A robust solution is to replace the kernel VT text console with a **DRM/KMS-based console** such as `kmscon`. This is very likely the solution that works natively with Fedora 44+ (see [phoronix.com](https://www.phoronix.com/news/Fedora-44-Considers-KMSCON)).
|
||||
|
||||
#### How it helps
|
||||
|
||||
|
|
@ -451,7 +451,7 @@ This is done via direct VT ioctls (e.g. `KDSETMODE`), ensuring that:
|
|||
|
||||
### Solution 3: fallbackdm (Work in Progress)
|
||||
|
||||
`fallbackdm` is an experimental, lightweight **logind-integrated fallback display manager**.
|
||||
`fallbackdm` is an experimental, lightweight **logind-integrated fallback display manager**. `fallbackdm` is available at https://github.com/joleuger/fallbackdm.
|
||||
|
||||
#### Intended behavior
|
||||
|
||||
|
|
|
|||
|
|
@ -1,144 +0,0 @@
|
|||
# DESIGN.md
|
||||
## 1. Design Philosophy: Standardized Infrastructure
|
||||
|
||||
The core design principle of `fallbackdm` is to **utilize established systemd interfaces** to solve the "Empty Seat" problem.
|
||||
|
||||
In a modern Linux ecosystem, hardware resource arbitration has moved away from direct device manipulation by individual applications. `systemd-logind` now acts as the central arbiter for seats, sessions, and terminal states.
|
||||
|
||||
`fallbackdm` is designed to be a "minimalist citizen" of this architecture. Instead of implementing a full graphical stack to "own" the hardware, it leverages the fact that the kernel and `logind` already provide a mechanism to mute VTs and protect input streams. By registering as a formal session controller, `fallbackdm` ensures the system remains in a "graphical-ready" state—silencing the legacy text console—without the overhead of an actual display server.
|
||||
|
||||
## 2. The Mechanism: The `TakeControl` Handshake
|
||||
|
||||
The critical functionality of `fallbackdm`—silencing the kernel terminal to prevent input leakage—is achieved through a single, standardized D-Bus handshake: `TakeControl`.
|
||||
|
||||
This mechanism replaces manual `ioctl` calls. By invoking the `TakeControl` method on the `org.freedesktop.login1.Session` interface, `fallbackdm` triggers a privileged workflow inside `logind` that safely transitions the machine state.
|
||||
|
||||
### 2.1 The Internal Workflow
|
||||
|
||||
When `fallbackdm` calls `TakeControl`, it triggers the following verified code path within `systemd-logind` (as referenced in `logind-session.c`):
|
||||
|
||||
1. **Permission Check:** `logind` verifies the caller owns the session.
|
||||
2. **Controller Assignment:** `session_set_controller()` marks `fallbackdm` as the active display server.
|
||||
3. **VT Preparation:** `logind` executes `session_prepare_vt()`, which performs the privileged operations:
|
||||
* **Mute Input:** Calls `ioctl(vt, KDSKBMODE, K_OFF)`. This effectively disconnects the kernel console from the keyboard, preventing `getty` or the kernel from interpreting keystrokes.
|
||||
* **Graphics Mode:** Calls `ioctl(vt, KDSETMODE, KD_GRAPHICS)`. This disables the blinking cursor and text rendering.
|
||||
* **Signal Handling:** Configures the VT to send signals (like `SIGUSR1`) for switching, rather than automatically switching context.
|
||||
|
||||
|
||||
|
||||
**Result:** `fallbackdm` achieves a "muted" state without ever needing to open a device file or possess `CAP_SYS_TTY_CONFIG` capabilities directly.
|
||||
|
||||
## 3. Industry Precedent: The Standard Stack
|
||||
|
||||
`fallbackdm` does not invent a new protocol; it isolates the infrastructure logic used by modern Linux desktops. To understand why `fallbackdm` works, we must look at how the **Wayland Native** stack (GDM and Mutter) handles seat ownership.
|
||||
|
||||
### 3.1 Foundational Concepts: Seats, Sessions, and Leaders
|
||||
|
||||
On a modern system, hardware access is governed by several distinct layers:
|
||||
|
||||
* **The Seat (e.g., `seat0`):** A collection of hardware (GPU, Keyboard, Mouse).
|
||||
* **The Session:** An instance of a user (or service) interacting with a seat.
|
||||
* **The Session Leader:** The primary process responsible for the session. In a graphical world, this is the **Compositor** (Mutter).
|
||||
* **The Display Manager (GDM):** A supervisor that manages the lifecycle of sessions.
|
||||
|
||||
In the **Wayland Native** workflow, the compositor (Mutter) serves as the "Display Server." It talks directly to the kernel for graphics (DRM/KMS) and input (libinput). However, it does not "steal" these resources; it asks `systemd-logind` for permission.
|
||||
|
||||
### 3.2 Technical Execution: PAM and the Handshake
|
||||
|
||||
The transition from a text-based boot to a graphical environment follows a strict sequence. `fallbackdm` mimics the first half of this cycle:
|
||||
|
||||
#### 1. Simplified Session Registration (The PAM Layer)
|
||||
|
||||
Before a process can "Take Control" of a seat, a session must exist. GDM initiates this via a specialized, minimalist PAM stack (e.g., `gdm-launch-environment.pam`).
|
||||
|
||||
Following the GDM precedent, `fallbackdm` uses a simplified PAM stack because a greeter/placeholder session **has no password and cannot be locked.** This removes the overhead of full `system-auth` account and password modules, focusing strictly on:
|
||||
|
||||
* Setting up the environment (`pam_env.so`).
|
||||
* Permitting the session entry (`pam_permit.so`).
|
||||
* Registering the session with `logind` via `pam_systemd.so` as `class=greeter`.
|
||||
|
||||
#### 2. Claiming the Seat (The D-Bus Layer)
|
||||
|
||||
Once registered, the Session Leader (Mutter in a standard setup, `fallbackdm` in ours) must claim the seat. The process calls `TakeControl(force=true)` on its own Session object via D-Bus. `logind` validates that the caller is the registered leader and then performs the privileged "silencing" of the VT.
|
||||
|
||||
### 3.3 Sequence & Implementation Mapping
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant P as PAM (Simplified Stack)
|
||||
participant F as fallbackdm (Session Leader)
|
||||
participant L as systemd-logind
|
||||
participant K as Kernel (VT Layer)
|
||||
|
||||
Note over P, L: 1. Registration (class=greeter)
|
||||
P->>L: CreateSession (via pam_systemd)
|
||||
L-->>P: Session Path / ID
|
||||
|
||||
Note over F, L: 2. The Handshake (Wayland Native Style)
|
||||
F->>L: D-Bus: TakeControl(force=true)
|
||||
|
||||
Note over L: Validate Caller (session_set_controller)
|
||||
|
||||
Note over L, K: 3. VT Preparation (session_prepare_vt)
|
||||
L->>K: ioctl(vt, KDSKBMODE, K_OFF)
|
||||
L->>K: ioctl(vt, KDSETMODE, KD_GRAPHICS)
|
||||
|
||||
Note over K: Keyboard Muted / Console Silenced
|
||||
|
||||
L-->>F: Method Return (Success)
|
||||
Note over F: Hold Seat (Idle)
|
||||
|
||||
```
|
||||
|
||||
#### Source References for Verification
|
||||
|
||||
* **GDM (PAM):** `data/gdm-launch-environment.pam` — Demonstrates the minimalist "don't run full account/password stacks" approach for greeters.
|
||||
* **GDM (PAM):** `src/daemon/gdm-session-worker.c` — Shows how the minimalist pam session is started via `gdm_session_worker_initialize_pam`.
|
||||
* **systemd-logind:** `src/login/logind-session-dbus.c` — see `method_take_control()`.
|
||||
* **systemd-logind:** `src/login/logind-session.c` — see `session_prepare_vt()` (where the `K_OFF` and `KD_GRAPHICS` ioctls live).
|
||||
* **Mutter:** `src/backends/native/meta-launcher.c` — see `meta_launcher_new()` where the D-Bus proxy for the session is created and `TakeControl` is called.
|
||||
* **GDM:** `daemon/gdm-manager.c` — see `set_up_greeter_session()` which coordinates the PAM transition.
|
||||
|
||||
### 3.4 The Parallel
|
||||
|
||||
* **Standard DM:** `PAM` → `Mutter` → **`TakeControl`** → *Open DRM/Input Devices*
|
||||
* **fallbackdm:** `PAM` → `fallbackdm` → **`TakeControl`** → *Wait/Idle*
|
||||
|
||||
By stopping after the `TakeControl` handshake, `fallbackdm` provides the exact same system-level protection as a full desktop environment with zero overhead and a vastly smaller attack surface.
|
||||
|
||||
|
||||
## 4. Alignment with Systemd Guidelines
|
||||
|
||||
The design strictly adheres to the *[Writing Display Managers](https://systemd.io/WRITING_DISPLAY_MANAGERS/)* specification provided by the systemd project.
|
||||
|
||||
| Systemd Requirement | `fallbackdm` Implementation |
|
||||
| --- | --- |
|
||||
| **"Register via PAM"** | `fallbackdm` uses `pam_systemd.so` with `class=greeter` to register a valid session. |
|
||||
| **"Take possession"** | We use the `TakeControl` D-Bus method to explicitly claim the seat. |
|
||||
| **"Passive C API"** | We use `sd-login` (or equivalent D-Bus calls) to identify the seat, avoiding manual parsing of `/var/run` or `/proc`. |
|
||||
| **"Minimal Porting"** | By offloading VT management to `logind`, we achieve the "Minimal porting" goal described in the docs, removing legacy ConsoleKit/ioctl code. |
|
||||
|
||||
## 5. Security & Stability Implications
|
||||
|
||||
### 5.1 Adherence to Least Privilege
|
||||
|
||||
By using `logind` as a proxy for hardware configuration, `fallbackdm` avoids the need for:
|
||||
|
||||
* `CAP_SYS_TTY_CONFIG`: No need to configure TTYs directly.
|
||||
* Device Node Access: No need to open `/dev/ttyX` or `/dev/input/eventX`.
|
||||
* Root Privileges: `fallbackdm` can run as a dedicated unprivileged system user, as `logind` validates the `TakeControl` request based on session ownership, not UID 0.
|
||||
|
||||
### 5.2 Graceful Handover
|
||||
|
||||
Because `fallbackdm` is a "polite" session controller:
|
||||
|
||||
* When a real DM (like GDM) starts, it triggers a new session or requests the seat.
|
||||
* `logind` manages the transition, and `fallbackdm` yields or exits based on standard D-Bus signals (`ReleaseSession`).
|
||||
* This ensures no "input blips" where the keyboard reverts to text mode during the split-second transition between `fallbackdm` and a real compositor.
|
||||
|
||||
|
||||
## 6. Summary
|
||||
|
||||
The design of `fallbackdm` is not a workaround; it is a **canonical implementation of a headless systemd session controller**.
|
||||
|
||||
By leveraging the `TakeControl` API, we utilize the exact mechanism built for this purpose, supported by the kernel and `systemd` developers, and battle-tested by GNOME and KDE. This ensures that the "Input Leakage" problem is solved at the infrastructure level, where it belongs.
|
||||
|
|
@ -1,147 +0,0 @@
|
|||
# fallbackdm
|
||||
|
||||
> This crate is WIP and has not released any source, yet.
|
||||
|
||||
**fallbackdm** is a minimal, headless display manager that exists solely to **own a seat and VT when no graphical session is running**.
|
||||
|
||||
It prevents unintended keyboard input from reaching `getty` or the kernel VT layer by registering a proper **greeter session** with `systemd-logind`, activating a VT, and switching it to graphics mode — without starting X11 or Wayland.
|
||||
|
||||
This is primarily useful for **kiosk setups, remote desktop systems, or input-virtualization scenarios** where no local user interaction is intended, but correct VT semantics must still be preserved.
|
||||
|
||||
---
|
||||
|
||||
## Problem Statement
|
||||
|
||||
On modern Linux systems:
|
||||
|
||||
* Virtual terminals (VTs) still exist and have a kernel keyboard handler
|
||||
* If **no graphical session is active**, `getty` will attach to a VT
|
||||
* Input injected via `uinput` or forwarded from remote systems may:
|
||||
|
||||
* Trigger `Ctrl+Alt+Fn`
|
||||
* Wake or interfere with `getty`
|
||||
* Cause VT switches or text-mode interaction
|
||||
|
||||
Graphical compositors avoid this by:
|
||||
|
||||
* Registering a session with `systemd-logind`
|
||||
* Owning a VT
|
||||
* Switching it to `KD_GRAPHICS`
|
||||
|
||||
But when **no compositor or greeter is running**, nothing owns the VT.
|
||||
|
||||
**fallbackdm fills exactly this gap.**
|
||||
|
||||
---
|
||||
|
||||
## What fallbackdm Does
|
||||
|
||||
* Registers a **`greeter` session** via PAM + `pam_systemd`
|
||||
* Acquires a seat using **libseat**
|
||||
* Activates a VT and switches it to graphics mode
|
||||
* Keeps the session alive while no real graphical session exists
|
||||
* Displays nothing and launches no compositor
|
||||
|
||||
Once a real display manager or compositor starts, it naturally replaces `fallbackdm`.
|
||||
|
||||
---
|
||||
|
||||
## What fallbackdm Does *Not* Do
|
||||
|
||||
* ❌ No X11
|
||||
* ❌ No Wayland
|
||||
* ❌ No greeter UI
|
||||
* ❌ No input filtering (by design)
|
||||
* ❌ No Device Ownership Required: Unlike a real compositor, `fallbackdm` does not need to open `/dev/dri/cardX` or `/dev/input/event*` to do its job. It only needs the TTY. This minimizes the attack surface significantly.
|
||||
|
||||
It only ensures **correct session, seat, and VT ownership**.
|
||||
|
||||
---
|
||||
|
||||
## When You Need This
|
||||
|
||||
You **do not need fallbackdm** if:
|
||||
|
||||
* X11 or Wayland is already running
|
||||
* A display manager (gdm, sddm, greetd, etc.) is active
|
||||
|
||||
You **do need fallbackdm** if:
|
||||
|
||||
* The system boots without a graphical stack
|
||||
* Input devices (especially `uinput`) must not reach `getty`
|
||||
* You rely on logind-correct VT behavior without a real compositor
|
||||
|
||||
---
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
```
|
||||
fallbackdm
|
||||
├─ PAM session (class=greeter)
|
||||
├─ pam_systemd
|
||||
├─ libseat
|
||||
│ └─ seatd or systemd-logind backend
|
||||
└─ VT activation + KD_GRAPHICS
|
||||
```
|
||||
|
||||
This mirrors what real display managers do — just without launching anything graphical.
|
||||
|
||||
---
|
||||
|
||||
## PAM Configuration
|
||||
|
||||
Create `/etc/pam.d/fallbackdm`:
|
||||
|
||||
```
|
||||
session required pam_systemd.so class=greeter
|
||||
```
|
||||
|
||||
This is mandatory. Without it, logind will not track the session.
|
||||
|
||||
---
|
||||
|
||||
## systemd Service Example
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=Fallback Display Manager
|
||||
After=systemd-user-sessions.service
|
||||
ConditionPathExists=!/run/graphical-session-active
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/fallbackdm
|
||||
PAMName=fallbackdm
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
> The condition is optional and can be replaced with more advanced logic later.
|
||||
|
||||
---
|
||||
|
||||
## Relationship to Other Projects
|
||||
|
||||
* **Display managers (gdm, sddm, greetd)**
|
||||
Full login stacks with UI and session spawning.
|
||||
|
||||
* **Greeters (gtkgreet, tuigreet)**
|
||||
UI components launched *by* a display manager.
|
||||
|
||||
* **fallbackdm**
|
||||
A *headless*, compatibility-focused DM whose only job is to own the seat.
|
||||
|
||||
---
|
||||
|
||||
## Future Ideas
|
||||
|
||||
* Optional status output on the VT
|
||||
* Signaling input-forwarding daemons (e.g. `vuinputd`)
|
||||
* Conditional exit when a real session becomes active
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
# /etc/pam.d/fallbackdm
|
||||
# https://man.archlinux.org/man/pam_systemd.8.en
|
||||
# alternative class=lock-screen
|
||||
# debug=yes
|
||||
# https://github.com/GNOME/gdm/blob/main/daemon/gdm-local-display-factory.c
|
||||
auth required pam_permit.so
|
||||
account required pam_permit.so
|
||||
session required pam_systemd.so class=greeter type=wayland
|
||||
Loading…
Add table
Add a link
Reference in a new issue