# SecDesk An attempt to port Windows *secure desktop* to Linux. ## Background On Windows, every window belongs to a [desktop](https://learn.microsoft.com/en-us/windows/win32/winstation/desktops), and processes can (?) read the input of other windows, unless they are privileged (?). Winlogon and UAC consent protects user inputs (e.g. passwords) from being stolen by 1) running as `NT Authority\SYSTEM` , and running on the secure desktop, which is a separate desktop from the users'. This way, user processes cannot read inputs. macOS should (?) has a similar security measurement, but I am not sure. On Unix, X11 does not have such a protection, and user processes are free to read any other process's input. This includes your lock screen (e.g. `i3lock(1)`) or terminal (running `sudo(1)`). Wayland fixes this issue by implementing a security control, while X11 users are left unprotected. This proof-of-concept project aims at porting the secure desktop concept on Windows to Unix. ## Threat model This project is aimed at preventing malware running as the unprivileged user to capture or hijack the input of sensitive dialogues. It assumes that the operating system (kernel, libraries, binaries, daemons, and everything privileged) is trusted. ## Basic idea Without modifying the kernel, the easiest approach is to use virtual terminals. While most current Unix operating systems has virtual terminal support, this project is mainly focused on Linux due to the author's familiarity. Porting it to other Unix could be possible. Linux has multiple virtual terminals (defined in `MAX_NR_CONSOLES`), and each one can run a text terminal or GUI. The kernel provides text terminals: programs read and write to `/dev/ttyN`, and the kernel handles input and outputs from the keyboard and to the screen. Display servers can use framebuffer or DRM, as well as `/dev/input/`, to draw their own graphics. Popular implementations of display servers, like Xorg or wayland compositors using `seatd` are all using DRM and `/dev/input`. Each virtual terminal is independent of each other, and users may switch from one to another using `Ctrl + Alt + Fx` or `VT_ACTIVATE` ioctl. Each virtual terminal is isolated from each other. For the text terminals, `/dev/ttyN` has the default permission of `0620 root:tty`, and privileged display servers holding `/dev/input/*` does not pass keystrokes to user processes after switching to other virtual terminals (Xorg will keep these files open, while `seated` will close them). This is ideal for implementing a secure desktop on Linux. The approach is to start a separate display server (e.g. Xorg) on a free (unused) virtual terminal, switch to it, read sensitive data, switch back, and close the virtual terminal. This guarantees that unprivileged processes have no way to hijack the password dialogue, with the limitation that the password dialogue must be trusted and ran by root. For example, a dedicated X server coule be started using: ```shell Xorg -background none :$NEW_DISPLAY vt$NEW_VT -nolisten tcp # Setup XAuth, so only root can connect. ``` Then, start a password dialogue: ```shell DISPLAY=:$NEW_DISPLAY /usr/lib/ssh/x11-ssh-askpass ``` This would be the simplest form of a secure desktop. ## Implementation To make the startup process faster, more portable, and simpler, I wrote this PoC that uses the text terminal instead of a display server. It is not a *desktop* in terms of the Windows secure desktop, but it satisfies the requirement of securely reading sensitive data. This PoC makes uses of various TTY and Console related ioctl (see `ioctl_console(2)` and `ioctl_tty(2)`), and it uses codes from [kbd](http://kbd-project.org/). How this PoC works is obvious: 1. Open the TTY of the current process. 2. Find an open virtual terminal (`VT_OPENQRY`) and open it. 3. Make the virtual terminal the controlling terminal (`setsid(2)` and `TIOCSCTTY`). 4. Read / write as usual using the file descriptor from step 2. 5. Switch to it or switch back using `VT_ACTIVATE` and `VT_WAITACTIVATE`. ## SAK Although the above process can safely read passwords, one more security measure must be taken into consideration: the user must know the authenticity of the password dialogue. That is, a user process may create a full-screen window to mimic the password dialogue in order to obtain the password. Windows mitigates this issue by having a SAK (Secure attention key), which is `Ctrl + Alt + Delete`. The NT kernel directly handles this key combo, and it notifies winlogon to show a privileged screen (either login screen or the security options page). Users can trust the page is authentic because no other programs shall capture the key combo. Moreover, domain administrators can enable the Require Ctrl Alt Del on Logon group policy to train users that they must press the SAK before login to ensure the authenticity of the login screen. However, this feature is missing on most current Unix operating systems. Linux is the only known Unix operating system to have a SAK, and it is less known and has little use. On Linux, the SAK is `SysRq + K`. The kernel will kill all processes (including the display server) in the current virtual terminal, so the service manager will restart the login prompt (either the display manger or getty), and it is authentic. This behaviour makes SAK on Linux very limited, as most users do not want their desktop programs to be killed just for logging in. This project took the advantage of the Linux SAK by forking a child to display the message `Press SysRq + K to continue` on the new virtual terminal and wait for it to be killed by `SIGKILL`. Although race condition could happen after `waitpid(2)` and `TIOCSCTTY`, it is still safe because the `/dev/ttyN` file does not allow non-root processes to write. ## In the future This project is far from perfect: its authentication UI / UX is naive, and it requires running as root to open the TTY. In the future, I will make it an AskPass / PolKit agent, where unprivileged user can run use it to securely authenticate themselves. I will also fix the behaviour when running from environments like SSH (pts) or serial, where virtual terminals do not exist. In these environments, it should simply use the current terminal and inform the user that the terminal is insecure, which is what Windows RDP does regarding remote UAC consent. ## Build and run ```shell mkdir build cd build cmake .. chown root ./secdesk && chmod 4755 ./secdesk ./secdesktop password test # mode prompt ``` The code is ugly: it is written in 4 hours. I will try to make it pretty. ## License WTFPL