Skip to content

Authentication strictly fails and corrupts TTY state due to concurrent sudo execution during file save #4050

@niltonperimneto

Description

@niltonperimneto

Description

When attempting to save a protected file, I am experiencing a severe privilege escalation failure that permanently mangles my calling shell's terminal attributes. Initially, my authentication attempts were consistently failing, and because I utilize sudo-rs as a strict, auditable security boundary, the mangled input triggered pam_faillock to lock my user account. After investigating the terminal state and tracing the system calls, I discovered the root cause is not the escalation tool, but a fundamental race condition in how the editor orchestrates its subprocesses and handles terminal recovery.

Steps to debugging

I began debugging this by inspecting the terminal state after a failed save attempt. Running a standard stty -a command revealed that while canonical mode seemed partially intact, the echonl flag was left active and standard character echo was globally suppressed. The editor was clearly leaking a dirty TTY state into my shell.

To understand exactly how the state was being corrupted, I attached an elevated strace instance to a running micro process from a separate, clean terminal window. This allowed me to bypass the kernel's ptrace restrictions on setuid binaries and observe the exact ioctl system calls during the save handoff.

The trace file exposed a catastrophic concurrency flaw. When the save operation is triggered, the editor simultaneously forks multiple instances of sudo dd—presumably one attempting to write the buffer blocks and another attempting to probe or truncate the target file. These concurrent subprocesses immediately compete for exclusive interactive access to the shared pseudo-terminal. They both issue TCGETS2 and TCSETS2 commands to disable terminal echo for their respective password prompts. This collision deadlocks standard input routing, causing the underlying authentication helper (unix_chkpwd) to immediately fail with a status 7 exit code due to an unreadable input stream.

The secondary, persistent failure occurs during the editor's error recovery phase. After the overlapping escalation processes die or are aborted, the editor issues a TCGETS call that blindly captures the corrupted, intermediate TTY state left behind by the deadlocked child processes. It caches this dirty state as the new baseline. Upon exiting, the editor executes a TCSETS command that permanently applies this poisoned configuration to the parent shell, rendering the terminal useless for subsequent commands until forcefully reset.

Steps to Reproduce

I can reproduce this reliably by launching the editor from a standard terminal emulator and opening any system-owned configuration file. I make a trivial modification and trigger the save command. The internal wrapper spawns the overlapping escalation prompts, the authentication silently fails or hangs, and I am forced to abort the operation. Exiting the editor entirely then drops me back into a shell where standard character echo is permanently disabled, forcing me to manually reset the terminal environment to regain control.
Expected Behavior

As an application operating within a modern, horizontal system architecture, the editor must strictly serialize its privilege escalation execution to ensure only one interactive subprocess requests control of the TTY at any given moment. Furthermore, the application must cache the pristine canonical terminal state upon initial launch and guarantee that this exact original state is restored upon exit.

If needed any more steps to debug it feel free to ask me

Environment

  • Version: rolling-distro
  • OS: Arch Linux
  • Terminal: Gnome Console, Ghostty and getty

termios_trace.log

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions