Fix partial reads from TTY (interactive terminal).

Some stable kernels started to return buffer from terminal
in partial buffers of maximal size 64 bytes.

This breaks all passphrases longer than 64 characters entered
through interactive input (for all crypto formats).

(The problem is probably fixed in more recent kernels, but
the read() call can always return a partial read here.)

This patch also fixes wrong password limit, the last character
of passphrase of maximal size was never handled.
Now the maximal passphrase length is really 512 characters.

Fixes: #627.
This commit is contained in:
Milan Broz
2021-03-06 22:37:00 +01:00
parent 6df6c0a363
commit 5a032abc33
2 changed files with 65 additions and 7 deletions

View File

@@ -102,18 +102,41 @@ static int tools_check_password(const char *password)
}
/* Password reading helpers */
static ssize_t read_tty_eol(int fd, char *pass, size_t maxlen)
{
bool eol = false;
size_t read_size = 0;
ssize_t r;
do {
r = read(fd, pass, maxlen - read_size);
if ((r == -1 && errno != EINTR) || quit)
return -1;
if (r >= 0) {
if (!r || pass[r-1] == '\n')
eol = true;
read_size += (size_t)r;
pass = pass + r;
}
} while (!eol && read_size != maxlen);
return (ssize_t)read_size;
}
/* The pass buffer is zeroed and has trailing \0 already " */
static int untimed_read(int fd, char *pass, size_t maxlen)
{
ssize_t i;
i = read(fd, pass, maxlen);
i = read_tty_eol(fd, pass, maxlen);
if (i > 0) {
pass[i-1] = '\0';
if (pass[i-1] == '\n')
pass[i-1] = '\0';
i = 0;
} else if (i == 0) { /* EOF */
*pass = 0;
} else if (i == 0) /* empty input */
i = -1;
}
return i;
}
@@ -200,10 +223,9 @@ static int crypt_get_key_tty(const char *prompt,
log_err(_("Error reading passphrase from terminal."));
goto out_err;
}
pass[key_size_max] = '\0';
if (verify) {
pass_verify = crypt_safe_alloc(key_size_max);
pass_verify = crypt_safe_alloc(key_size_max + 1);
if (!pass_verify) {
log_err(_("Out of memory while reading passphrase."));
r = -ENOMEM;

View File

@@ -1023,5 +1023,41 @@ EOF
[ $? -eq 0 ] || fail "Expect script failed."
$CRYPTSETUP remove $DEV_NAME || fail
prepare "[40] Long passphrase from TTY." wipe
EXPECT_DEV=$(losetup $LOOPDEV | sed -e "s/.*(\(.*\))/\1/")
# Password of maximal length 512 characters
LONG_PWD=\
"0123456789abcdef0123456789ABCDEF0123456789abcdef0123456789ABCDEF"\
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do "\
"eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut e"\
"nim ad minim veniam, quis nostrud exercitation ullamco laboris n"\
"isi ut aliquip ex ea commodo consequat. Duis aute irure dolor in"\
" reprehenderit in voluptate velit esse cillum dolore eu fugiat n"\
"ulla pariatur. Excepteur sint occaecat cupidatat non proident, s"\
"unt in culpa qui officia deserunt mollit anim id est laborum.DEF"
echo -n "$LONG_PWD" >$KEYE
expect_run - >/dev/null <<EOF
proc abort {} { send_error "Timeout. "; exit 2 }
set timeout 10
eval spawn $CRYPTSETUP_RAW luksFormat --type luks1 $FAST_PBKDF_OPT -v $LOOPDEV
expect timeout abort "Are you sure? (Type 'yes' in capital letters):"
send "YES\n"
expect timeout abort "Enter passphrase for $EXPECT_DEV:"
sleep 0.1
send "$LONG_PWD\n"
expect timeout abort "Verify passphrase:"
sleep 0.1
send "$LONG_PWD\n"
expect timeout abort "Command successful."
expect timeout abort eof
eval spawn $CRYPTSETUP_RAW luksOpen -v $LOOPDEV --test-passphrase --key-file $KEYE
expect timeout abort "Command successful."
expect timeout abort eof
EOF
[ $? -eq 0 ] || fail "Expect script failed."
remove_mapping
exit 0