Akar Masalah: VT Switching, Delayed Release, dan Spoofing
Terminal emulator berbasis kernel mode-setting (KMS) seperti kmscon beroperasi langsung di atas subsistem DRM/KMS tanpa X server atau Wayland compositor. Ketika berganti virtual terminal (VT switching), hak akses ke perangkat grafis (DRM-Master) harus dialihkan antar-sesi secara instan.
Masalah utama integrasi kmscon dengan session manager (seperti systemd-logind) berkisar pada tiga titik kritis:
- DRM Master Race Condition: Kernel Linux hanya mengizinkan satu DRM-Master aktif per primary node (
/dev/dri/cardX). Saat VT beralih dari sesi A ke sesi B, jika sesi A terlambat melepas master viadrmDropMaster()sebelum sesi B memanggildrmSetMaster(), sesi B gagal dengan galat-EACCESatau-EBUSY. - Sinyal Terlambat (Delayed Release): Kontrak D-Bus asinkron mengirimkan sinyal
PauseDevice. Jikakmsconmemblokir loop pemrosesan D-Bus (misalnya terhambat I/O lambat atau alokasi buffer), logind mengasumsikan klien tidak responsif, memutus akses kontrol secara paksa, dan menyebabkan konsol hang. - Socket Credential Spoofing: Pada komunikasi socket lokal internal antara kontroler konsol dan worker process, kegagalan memverifikasi identitas proses lawan membuka celah eskalasi hak akses jika socket IPC dapat diakses oleh UID non-root.
Autentikasi Peer IPC via SO_PEERCRED
Komunikasi IPC melalui UNIX domain socket harus memvalidasi kredensial peer pada saat koneksi terjalin untuk mencegah spoofing. Linux menyediakan opsi socket SO_PEERCRED yang mengembalikan PID, UID, dan GID proses lawan secara aman dari konteks kernel.
#define _GNU_SOURCE
#include <sys/socket.h>
#include <unistd.h>
#include <errno.h>
int validate_ipc_peer(int sock_fd, uid_t required_uid) {
struct ucred cred;
socklen_t len = sizeof(struct ucred);
if (getsockopt(sock_fd, SOL_SOCKET, SO_PEERCRED, &cred, &len) < 0) {
return -errno;
}
if (cred.uid != required_uid) {
return -EACCES;
}
return 0;
}Fungsi tersebut memastikan hanya pesan dari UID tepercaya (misalnya 0 untuk root/daemon) yang diproses. Jika transfer file descriptor DRM dilakukan melalui socket, gunakan kontrol pesan SCM_RIGHTS yang dipadukan dengan SCM_CREDENTIALS untuk validasi per-pesan.
Desain Kontrak Pesan Idempoten untuk DRM Control
Interaksi antara kmscon dan API org.freedesktop.login1.Session harus dirancang secara idempoten. Panggilan ganda atau sinyal yang datang di luar urutan (out-of-order) tidak boleh merusak state aplikasi.
1. Claim Device (TakeDevice)
Saat sesi aktif, kmscon memanggil method TakeDevice(major, minor). Logind mengembalikan file descriptor perangkat DRM beserta flag paused. Operasi ini harus idempoten: jika FD sudah terbuka, kmscon memakai kembali resource yang ada tanpa melakukan re-inisialisasi pipeline rendering.
2. Pause Device (PauseDeviceComplete)
Logind memancarkan sinyal PauseDevice(major, minor, type) sebelum sesi beralih. Tipe penanganan terbagi dua:
force: Sesi telah ditutup paksa oleh kernel/logind. Segera nonaktifkan rendering loop; jangan panggildrmDropMaster()karena fd sudah tidak valid.normal: Lepas kontrol DRM sesegera mungkin, lalu kirim kembali konfirmasiPauseDeviceComplete(major, minor).
Implementasi State Machine Non-Blocking
Untuk menghindari deadlock saat VT switching, transisi state DRM harus dieksekusi tanpa pemanggilan fungsi blocking I/O di dalam event loop (misalnya epoll).
#include <xf86drm.h>
#include <errno.h>
typedef enum {
STATE_INACTIVE,
STATE_ACTIVE,
STATE_PAUSING
} SessionState;
int handle_session_pause(int drm_fd, SessionState *state) {
if (*state == STATE_INACTIVE) {
return 0; /* Operasi idempoten */
}
*state = STATE_PAUSING;
/* Drop master tanpa menunggu thread lain */
if (drmDropMaster(drm_fd) < 0) {
if (errno != EACCES && errno != EINVAL) {
return -errno;
}
}
*state = STATE_INACTIVE;
return 0;
}Kode di atas menangani EACCES dan EINVAL sebagai respons valid. Jika kernel telah mencabut hak DRM-Master sebelum aplikasi mengeksekusi drmDropMaster, sistem tetap menganggap status perangkat telah nonaktif tanpa menghentikan loop aplikasi.
Trade-off dan Debugging
Pendekatan asinkron berbasis event-driven menuntut sinkronisasi buffer render yang ketat. Jika thread rendering tetap menulis ke dumb buffer setelah state berubah menjadi STATE_INACTIVE, frame tearing atau crash subsistem grafis dapat terjadi.
Metode Debugging IPC dan DRM
- Periksa traffic D-Bus logind secara real-time:
busctl monitor org.freedesktop.login1 - Aktifkan tracing DRM kernel untuk memverifikasi peralihan master:
echo 0x1e > /sys/module/drm/parameters/debug - Pantau status seat perangkat:
loginctl show-session $XDG_SESSION_ID
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!