Bug 2246923

Summary: 3.6.0 regression: `stratis key set --capture-key` fails with termios.error: (25, 'Inappropriate ioctl for device')
Product: [Fedora] Fedora Reporter: Martin Pitt <mpitt>
Component: stratis-cliAssignee: mulhern <amulhern>
Status: CLOSED WONTFIX QA Contact: Fedora Extras Quality Assurance <extras-qa>
Severity: high Docs Contact:
Priority: unspecified    
Version: 39CC: amulhern, bgurney, jbaublitz, mvollmer
Target Milestone: ---Keywords: Regression
Target Release: ---   
Hardware: Unspecified   
OS: Linux   
URL: https://cockpit-logs.us-east-1.linodeobjects.com/pull-19541-20231028-061240-f17dc026-fedora-39-updates-testing/log.html#234-2
Whiteboard: CockpitTest
Fixed In Version: Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2024-11-13 12:49:54 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description Martin Pitt 2023-10-30 07:01:08 UTC
Cockpit's tests recently started to run nightly checks on Fedora 39 updates-testing (until Friday it was still F38). This found a stratis-cli regression from the recent 3.5.3 → 3.6.0 update [1].

Our test needs to create a stratis key noninteractively. `stratis key set` has an option for that:

 --capture-key         Read key from stdin with no terminal echo or userspace buffer storage


In 3.5.3 this already does not work very well: When run in a normal terminal or ssh, it asks on the PTY despite the option:

# echo s3kr1t | stratis key set --capture-key pool1
Enter key data followed by the return key:

It even does that if none of stdin, out, err is on a tty:

# echo s3kr1t | stratis key set --capture-key pool1 2>&1 | cat
Enter key data followed by the return key: 

And *even* when running through nohup. The smallest hammer that works is

systemd-run --unit key --wait sh -exc 'echo s3kr1t | stratis key set --capture-key pool1; echo done'


With 3.5.3 this worked:

Running as unit: key.service
Finished with result: success
Main processes terminated with: code=exited/status=0
Service runtime: 541ms
CPU time consumed: 209ms

# stratis key 
Key Description     
pool1          

But with 3.6.0 even that doesn't work any more, and it runs into a traceback:

# systemd-run --unit key --wait sh -exc 'echo s3kr1t | stratis key set --capture-key pool1; echo done'
Running as unit: key.service
Finished with result: exit-code
Main processes terminated with: code=exited/status=1
Service runtime: 415ms
CPU time consumed: 186ms

# journalctl -u key

/usr/lib64/python3.12/getpass.py:91: GetPassWarning: Can not control echo on the terminal.
  passwd = fallback_getpass(prompt, stream)
Warning: Password input may be echoed.
Enter key data followed by the return key:
Warning: Password input may be echoed.
Verify key data entered: stratis encountered an unexpected error during execution. Please report the error and include in your report the stack trace shown below.
Traceback (most recent call last):
  File "/usr/lib64/python3.12/getpass.py", line 69, in unix_getpass
    old = termios.tcgetattr(fd)     # a copy to save
          ^^^^^^^^^^^^^^^^^^^^^
termios.error: (25, 'Inappropriate ioctl for device')
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
  File "/usr/lib/python3.12/site-packages/stratis_cli/_main.py", line 43, in the_func
    result.func(result)
  File "/usr/lib/python3.12/site-packages/stratis_cli/_parser/_parser.py", line 95, in wrapped_func
    func(*args)
  File "/usr/lib/python3.12/site-packages/stratis_cli/_actions/_top.py", line 171, in set_key
    ((changed, existing_modified), return_code, message) = _add_update_key(
                                                           ^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/stratis_cli/_actions/_top.py", line 76, in _add_update_key
    verify = getpass(prompt="Verify key data entered: ")
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.12/getpass.py", line 91, in unix_getpass
    passwd = fallback_getpass(prompt, stream)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.12/getpass.py", line 126, in fallback_getpass
    return _raw_input(prompt, stream)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.12/getpass.py", line 148, in _raw_input
    raise EOFError
EOFError
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
  File "/usr/bin/stratis", line 35, in <module>
    main()
  File "/usr/bin/stratis", line 32, in main
    return run()(sys.argv[1:])
           ^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/stratis_cli/_main.py", line 64, in the_func
    handle_error(err)
  File "/usr/lib/python3.12/site-packages/stratis_cli/_error_reporting.py", line 368, in handle_error
    raise err
  File "/usr/lib/python3.12/site-packages/stratis_cli/_main.py", line 59, in the_func
    raise StratisCliActionError(command_line_args, result) from err
stratis_cli._errors.StratisCliActionError: Action selected by command-line arguments ['key', 'set', '--capture-key', 'pool1'] which were parsed to Namespace(propagate=False, unhyphenated_uuids=False, func=<function add_subcommand.<locals>.wrap_func.<locals>.wrapped_func at>
key.service: Main process exited, code=exited, status=1/FAILURE


Reproducible: Always



Expected Results:  
With --capture-key it should not even *try* to invoke the console. Read the password from stdin, and fail if it is empty, no fallbacks.

[1] https://bodhi.fedoraproject.org/updates/FEDORA-2023-c464ef1f0a

Comment 1 Marius Vollmer 2023-10-30 11:57:35 UTC
--keyfile-path /dev/stdin might work.

Comment 2 mulhern 2023-10-30 14:12:42 UTC
I believe that the only difference between the two versions is that for --capture-key option, the user must enter the password twice in 3.6.0.

Please let us know if that is the source of the problem. For your tests, I think switching to, e.g., --keyfile-path option, as suggested, would be the best approach.

Comment 3 Martin Pitt 2023-10-31 07:12:56 UTC
Indeed sending the password twice works:

  systemd-run --unit key --wait sh -exc 'echo -e "s3kr1t\ns3kr1t" | stratis key set --capture-key pool1; echo done'

So maybe the documentation of --capture-key is misleading then: Either it is not really meant for this noninteractive case, and then it should be documented differently, or it is broken and should be fixed to not touch the tty at all, and just read the password from stdin.

Indeed --keyfile-path works better:

   echo s3kr1t | stratis key set --keyfile-path /dev/stdin pool2

That doesn't need any jumping through hoops to hide the tty. I'll change our tests to use that. However, I keep this open to clarify/fix the --capture-key option.

Thank you!

Comment 4 Martin Pitt 2023-10-31 09:06:14 UTC
> Indeed --keyfile-path works better:

Ah no, it doesn't. While the *command* works, it seems to associate the given file path to the key, instead of reading the file and storing the contents as the key. So with /dev/stdin that is broken, see e.g. https://cockpit-logs.us-east-1.linodeobjects.com/pull-19549-20231031-071549-fd5d9d9a-fedora-38-storage/TestStorageStratisNBDE-testBasic-fedora-38-127.0.0.2-2301-FAIL.png .

So indeed there is a raison d'être for both --keyfile-path and --capture-key. I'll go back to the latter and just send the passphrase twice.

Comment 5 Martin Pitt 2023-10-31 15:48:09 UTC
Correction: This does work, it's just picky about *not* having a newline at the end. Adding `-n` fixes it:

  echo -n s3kr1t | stratis key set --keyfile-path /dev/stdin pool2

Comment 6 Aoife Moloney 2024-11-13 09:57:50 UTC
This message is a reminder that Fedora Linux 39 is nearing its end of life.
Fedora will stop maintaining and issuing updates for Fedora Linux 39 on 2024-11-26.
It is Fedora's policy to close all bug reports from releases that are no longer
maintained. At that time this bug will be closed as EOL if it remains open with a
'version' of '39'.

Package Maintainer: If you wish for this bug to remain open because you
plan to fix it in a currently maintained version, change the 'version' 
to a later Fedora Linux version. Note that the version field may be hidden.
Click the "Show advanced fields" button if you do not see it.

Thank you for reporting this issue and we are sorry that we were not 
able to fix it before Fedora Linux 39 is end of life. If you would still like 
to see this bug fixed and are able to reproduce it against a later version 
of Fedora Linux, you are encouraged to change the 'version' to a later version
prior to this bug being closed.

Comment 7 Martin Pitt 2024-11-13 12:49:54 UTC
As nobody else complained, let's put this to rest -- we've used --keyfile-path since then.