Skip to content

gh-157538: Read getpass() input in non-canonical mode - #157805

Open
nouraellm wants to merge 1 commit into
python:mainfrom
nouraellm:fix-gh-157538-getpass
Open

nouraellm wants to merge 1 commit into
python:mainfrom
nouraellm:fix-gh-157538-getpass

Conversation

@nouraellm

@nouraellm nouraellm commented Sep 19, 2026 •

Copy link
Copy Markdown
Contributor

unix_getpass() disables ECHO but leaves the tty in canonical mode and calls readline(). A long pasted secret with no newline (a JWT is the usual case) can fill the kernel input queue (MAX_INPUT is 1024 on Darwin). Terminal.app writes the paste synchronously, so the UI wedges until the process is killed.

Always switch the tty to non-canonical mode (VMIN=1, VTIME=0) and read byte-by-byte. Reuse the existing line editor so ERASE / KILL / INTR / EOF keep working when echo is off; only the echo_char drawing is skipped. readline() remains the fallback when the tty cannot be controlled.

Fixes #157538

unix_getpass() disables ECHO but leaves the tty in canonical mode and calls readline(). A long pasted secret with no newline (a JWT is the usual case) can fill the kernel input queue (MAX_INPUT is 1024 on Darwin). Terminal.app writes the paste synchronously, so the UI wedges until the process is killed.

Always switch the tty to non-canonical mode (VMIN=1, VTIME=0) and read byte-by-byte. Reuse the existing line editor so ERASE / KILL / INTR / EOF keep working when echo is off; only the echo_char drawing is skipped. readline() remains the fallback when the tty cannot be controlled.

Fixes python#157538
@nouraellm

Copy link
Copy Markdown
Contributor Author

@picnixz feedback plz on why?

@picnixz

picnixz commented Sep 19, 2026 •

Copy link
Copy Markdown
Member
  1. Someone already suggested to work on that. It is rude tonjust open a pr without asking.
  2. this needs more investigation and I am not entirely sure it is a specific issue as the issue already exists in 3.13. We should look at what changed there first. Line editor a new featurenin 3.15 iirc (or maybe 3.14).
  3. There are unrelated changes

@nouraellm

Copy link
Copy Markdown
Contributor Author

@picnixz

  1. I started working on it before someone suggested taking it :)
  2. It's rude to make assumptions and close a PR without feedback
  3. Could've been better if you requested clarifications or the option to peer-fix the issue :)

@picnixz

picnixz commented Sep 19, 2026

Copy link
Copy Markdown
Member

You should have posted on the issue first then, to mention that you worked on it. At least looking at the thread before. And I am still unsure about this fix. Switching to noncanonical had issues in the past (and thus I also wonder whether the problem is this specific change). So first we should diagnose the issue.

@nouraellm

Copy link
Copy Markdown
Contributor Author

@picnixz well this is some useful feedback. Thanks, I'll leave it to Adarsh-Me. Have a great day!

@picnixz picnixz reopened this Sep 25, 2026
@nouraellm

Copy link
Copy Markdown
Contributor Author

@picnixz As previously mentioned in the issue I was able to reproduce, so we move past that.

As per your request I ran an even deeper investigation into the history of the module not just a repro of the hang, so here's what we are working with:

  • Unix getpass has only cleared ECHO for a long time
  • Canonical mode and ISIG were left on so the kernel would keep doing line editing (ERASE/KILL/WERASE) and job-control signals, so clearing ISIG as well (ECHO|ISIG) is what made Ctrl+C / Ctrl+Z dead and that was reverted in bpo-11236 also hg 154b323e0e7f (ECHO|ISIG → ECHO only)
  • That is why the default path is still tcsetattr(ECHO off) + readline() please take a look at the current unix_getpass()
  • Leaving canonical mode is also why echo_char hurt us and that's because 3.14 dropped ICANON so stars could appear per key (#77065 and #130496)
  • Kernel shortcuts then stopped working and Ctrl+U ended up in the password #138577
  • That limitation was documented first #138677 and 3.15 added _PasswordLineEditor and cleared IEXTEN so userspace owns editing #141597 which was noted in getpass docs
  • In mac, terminal freezes when taking JWT token as getpass input #157538 is not that regression and it is reported on 3.13 on the old hidden-input path: echo_char is None, ICANON still set, readline() waiting for \n
  • Darwin’s MAX_INPUT is 1024 termios(3) and Darwin tty
  • A pasted JWT is longer and has no newline yet so the kernel queue fills
  • Terminal.app writes the paste synchronously and the UI wedges
  • Linux usually has a much larger queue which is why this looks Mac-only

The constraint from this whole history is the following:

  • Do not drop ICANON unless userspace replaces the driver
  • We already have that replacement for echo_char
  • Reuse it when echo is off (draw nothing), set VMIN=1/VTIME=0, keep ISIG on, copy the cc array so the saved attrs are not mutated, and leave readline() as the fallback when tcsetattr fails
  • Also keep the post-restore stream.flush() from bpo-7208.

Thus, in my opinion this does not need a new PR because this one is that exact change and strictly not a new tty design or a Darwin #ifdef.

Please let me know what you think and whether you'd like me to adjust the PR text or tests to spell the history out if useful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

In mac, terminal freezes when taking JWT token as getpass input

2 participants