Bug 1600990

Summary: plymouth ask-for-password fails to retrieve typed password
Product: Red Hat Enterprise Linux 7 Reporter: Olivier LAHAYE <olivier.lahaye1>
Component: plymouthAssignee: Ray Strode [halfline] <rstrode>
Status: CLOSED WONTFIX QA Contact: Desktop QE <desktop-qa-list>
Severity: high Docs Contact:
Priority: unspecified    
Version: 7.5CC: okozina, olivier.lahaye1
Target Milestone: rc   
Target Release: ---   
Hardware: x86_64   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2021-02-15 07:40:34 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Attachments:
Description Flags
Requested dmesg log none

Description Olivier LAHAYE 2018-07-13 14:17:37 UTC
Description of problem:
SSHPASS=$(plymouth ask-for-password) returns empty result (Only on RHEL/CentOS-7 latest version; works perfectly on fedora-28 and opensuse-42.3 and RHEL/CentOS-6)

plymouthd.log gives the following:
[ply-boot-server.c:303] ply_boot_connection_on_password_answer:got password answer
[ply-boot-server.c:293] ply_boot_connection_send_answer:could not finish writing answer: Broken pipe


Version-Release number of selected component (if applicable):
plymouth-0.8.9-0.31.20140113.el7

How reproducible:
100%

Steps to Reproduce:
mkdir /tmp/bug; cd /tmp/bug
wget http://olivier.lahaye1.free.fr/SystemImager/plymouth_test/{VM_test_plymouth.sh,{kernel,initrd.img}-{CO6,CO7,fc28,OpenSuSE42.3}}
#edit the variables for VM_test_plymouth.sh to fit your needs ($INITRD and $KERNEL)
chmod +x ./VM_test_plymouth.sh
./VM_test_plymouth.sh

=> Wait for VM to fail (if nothing is displayed on splash screen just press any key to get a bash green prompt.
and from this prompt:
wget http://olivier.lahaye1.free.fr/SystemImager/plymouth_test/test_plymouth.sh
chmod +x test_plymouth.sh; ./test_plymouth.sh
# Type a dummy password
=> The password should be displayed in clear in a message log (in the GUI).
(problem is the same if you press ESC and type password in text mode)

You can test with other OS provided initrds and see that it works.

I can't provide initrd for RHEL due to licence, but it is easily build-able if you think initrd.img-CO7 is not sufficient to help find the bug.

1: wget http://svn.oscar.openclustergroup.org/pkgs/downloads/systemimager-4.9.0.tar.bz2
2: rpmbuild -tb systemimager-4.9.0.tar.bz2
 (Add install Requirements if needed)
3: yum install systemimager-x86_64boot-standard-4.9.0*rpm (ignore deps)
4: Adapt VM_test_plymouth.sh so it uses /usr/share/systemimager/boot/x86_64/standard/{kernel,initrd.img}

Usefull commands: strace, vi, wget, ssh, scp, rsync are available within the initramfs.
Tags	


Actual results:
plymouthd.log gives the following:
[ply-boot-server.c:303] ply_boot_connection_on_password_answer:got password answer
[ply-boot-server.c:293] ply_boot_connection_send_answer:could not finish writing answer: Broken pipe

and plymouth ask-for-password outputs nothing


Expected results:
plymouth ask-for-password outputs the typed password

Additional info:
Works on RHEL/CentOS-6, Fedora-27, Fedora-28, OpenSuSE-42.3 at least
Fails on RHEL-7 and CentOS-7 latest release (13 Jul 2018)

Note:
https://github.com/finley/SystemImager/tree/initrd-from-imageserver-and-dont-package-initrd
rely on a working plymouth ask-for-password. It works on all tested distributions that have dracut tool and plymouth (even old non-systemd ones like RHEL-6)

This query is used to create an ssh tunnel between the imaged system and the imaging server. Is is required in non secured networks.

See screenshots here:
https://github.com/finley/SystemImager/wiki/ScreenShots

Comment 2 Ray Strode [halfline] 2018-07-13 14:57:57 UTC
hey sorry for not replying to your mail upstream, it's pinned waiting for me to get an opportunity to investigate in more detail.

Perhaps it's an SELinux problem ? Are there any AVCs ?

Comment 3 Ray Strode [halfline] 2018-07-13 15:01:29 UTC
can you change

SSHPASS=$(plymouth ask-for-password)

to

SSHPASS=$(strace -s9999 -o /dev/kmsg plymouth ask-for-password)

and then post dmesg ? (be careful, the results will have the password in them, so don't use a real password)

Comment 4 Olivier LAHAYE 2018-07-16 07:30:49 UTC
Created attachment 1459059 [details]
Requested dmesg log

dmesg after running strace -s9999 -o /de/kmsg plymouth ask-for-password --promt "Please, enter password:"

Comment 5 Olivier LAHAYE 2018-07-16 07:46:53 UTC
Note: As you can see in dmesg log, SELinux is started in permissive mode, thus it shouldn't block anyting.
And regarding the clear text password, it is not in the strace output.

As said in initial bug report, you can test this initramfs with qemu-kvm easily (see "steps to reproduce" section in bug report). It includes many debug tools (strace, vi, wget, ssh, scp, rsync, ncat, ....).
This initramfs is designed to help the end-user debug what went wrong in the imaging process (mainly pre/post install script, but also other problems like this one).
From within the initramfs, you can get new plymouthd versions by retreiving it using ssh.
OR
You can rebuild the initramfs using the following command (dracut-systemimager, systemimager-common, systemimager-server must be installed):
si_mkbootpackage --flavor standard
the resulting initrd.img and associated kernel will be generated in /usr/share/systemimager/boot/x86_64/standard/

Comment 6 Ray Strode [halfline] 2018-07-16 14:56:26 UTC
Okay looking at the log we see this:

```
[  145.708238] socket(AF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 6
```
Socket is opened nonblocking

```
[  145.708559] setsockopt(6, SOL_SOCKET, SO_PASSCRED, [1], 4) = 0
[  145.708601] connect(6, {sa_family=AF_LOCAL, sun_path=@"/org/freedesktop/plymouthd"}, 29) = 0
```
connection is made to plymouthd okay

```
[…]
[  145.718943] write(6, "*\2\30Please, enter password:\0", 27) = 27
[…]
[  154.406166] read(6, "\2", 1)                        = 1
```
password is asked for, and user gave an answer.

```
[  154.406242] read(6, 0x7fff47c48b40, 4)              = -1 EAGAIN (Resource temporarily unavailable)
```
Trying to read the length of the response failed with `EAGAIN`.

Looking at the client code, `EAGAIN` is not expected, and so it's an error that the socket is marked non-blocking.  Indeed, the `SOCK_NONBLOCK` is removed from master. Looking through the git log, it was fixed by this commit:

https://cgit.freedesktop.org/plymouth/commit/?id=b97c30a019e412d30337515e615433bf6f886972

you might be able to use `socat` as a workaround until `plymouth` is fixed. maybe something like:

```
echo -e "*\02\030Please, enter password:" | socat ABSTRACT-CONNECT:/org/freedesktop/plymouthd STDIO,ignoreeof 
```

Comment 7 Olivier LAHAYE 2018-07-17 07:53:54 UTC
Workaround doesn't work so well as socat doesn't hang up after receiveing the password.
It receives \02,then password length (one byte) and there after the password.
It's then up to socat to close the connection when all password bytes have been received. (but I see no way to tell socat that.
I do a (sleep 30; killall socat)$ before requesting password but it's ultra ugly. Any better way to fix that? (and I need to remove the 2 leading bytes received, but ${SSHPASS:2} does it very well)

Comment 8 Olivier LAHAYE 2018-07-17 12:29:51 UTC
My less ugly solution:

read_password() {
    SIZE=$(od -An -t d4 -j1 -N4)
    read -s -r -N $SIZE PASS
    echo -n "$PASS"
    killall socat
}

ask_for_password() {
    PROMPT="Please, enter password"
    MSG_SIZE=$(echo "obase=8;$(( ${#PROMPT} + 1 ))"|bc)
    printf "*\02\0${MSG_SIZE}${PROMPT}\0" | socat ABSTRACT-CONNECT:/org/freedesktop/plymouthd STDIO,ignoreeof | read_password
}

SSHPASS=$(ask_for_password)

I'm not expert with socat, maybe there is a way to tell socat to close socket if read_password returns? That would avoid to kill socat from read_password...

BTW, If don't put \0 at end of prompt, a random chat is displayed at end of prompt. certainly a buffer (prompt) that is not zeroed, thus the string is not null terminated. Maybe some potential buffer overflow?

Comment 9 Ray Strode [halfline] 2018-07-17 14:32:20 UTC
(In reply to Olivier LAHAYE from comment #8)
> I'm not expert with socat, maybe there is a way to tell socat to close
> socket if read_password returns? That would avoid to kill socat from
> read_password...
tbh, i'm not either. i just spent a minute with the man page to try to come up the beginnings of a workaround.

Not sure, but you could try closing stdin with

0<&-

and see if that makes socat die with EPIPE ?

or throw named pipe into the mix (untested, just an idea):

mkfifo password_pipe

printf ... | socat ... STDIO,ignoreeof > password_pipe &
socatpid=$!

exec 0<password_pipe
read_password 
0<&-
kill -HUP $socatpid

can't really test right now, so these are just ideas that might not pan out.

> BTW, If don't put \0 at end of prompt, a random chat is displayed at end of
> prompt. certainly a buffer (prompt) that is not zeroed, thus the string is
> not null terminated. Maybe some potential buffer overflow?
okay will investigate.

Comment 10 Ray Strode [halfline] 2018-07-20 16:41:34 UTC
*** Bug 1605220 has been marked as a duplicate of this bug. ***

Comment 13 RHEL Program Management 2021-02-15 07:40:34 UTC
After evaluating this issue, there are no plans to address it further or fix it in an upcoming release.  Therefore, it is being closed.  If plans change such that this issue will be fixed in an upcoming release, then the bug can be reopened.