把密码短语写入一个处于等待状态的cryptsetup进程

编程语言 2026-07-11

在基于BusyBox的 initramfs(Arch Linux mkinitcpio),我有 cryptsetup 等待来自控制台输入密码

ps | grep cryptsetup
200 root     11752 S    cryptsetup open --type luks /dev/vda2 root

它处于 S 模式(可中断睡眠),如果可能的话,我不想在我的职责范围之外修改这个钩子。

由于我也希望能够通过网络解密根设备,我设法为initramfs提供了一个最小的DHCP环境,并通过这个钩子启动了一个Dropbear服务器:

run_hook ()
{
  [ -d /dev/pts ] || mkdir -p /dev/pts
  mount -t devpts devpts /dev/pts

  echo "Starting dropbear"
  /usr/bin/dropbear -s -j -k -p 2222
}

到目前为止,一切还算顺利。我现在苦恼的是如何把口令传给等待中的200号进程,以便解锁分区并继续引导。

我做了一些基于向该进程的标准输入写入的简单尝试

printf "password\n" > /proc/200/fd/0

# EOL variant
cat > /proc/200/fd/0 << EOF
password
EOF

但失败了(与 /dev/console /proc/200/fd/0 指向的情况相同):明文被写入,但解密没有被触发。

~ # ls -la /proc/200/fd
dr-x------    2 root     0                7 Mar 11 16:01 .
dr-xr-xr-x    9 root     0                0 Mar 11 15:49 ..
lrwx------    1 root     0               64 Mar 11 16:05 0 -> /dev/console
lrwx------    1 root     0               64 Mar 11 16:05 1 -> /dev/console

由于预期输入是一个不应被打印的口令,且/或因为进程处于 S 模式,我猜想 cryptsetup 要么监听另一台设备,要么某个事件应触发将输入转发到它的STDIN。我尝试了 /dev/tty0,一些 /dev/tty*,以及 /dev/pts 的条目。这个 interactive_pass 部分暗示 /dev/tty0

    /* Read and write to /dev/tty if available */
    infd = open("/dev/tty", O_RDWR);
    if (infd == -1) {
        infd = STDIN_FILENO;
        outfd = STDERR_FILENO;
    } else {
        outfd = infd;
        close_fd = true;
    }

作为一个合适的候选者,/proc/200/stat 也是如此,但因为我在initramfs中没有 strace 或任何类似工具,所以我不确定这个函数可以使用哪一个tty。

对名义情况下的工作原理进行解释/澄清将对我有很大帮助。当 cryptsetup open --type luks /dev/vda2 触发时,我理解进程处于睡眠模式,等待一个回答。当我输入口令并按回车时,这些字符会通过哪条路径传达到等待中的 interactive_pass?是不是应该先把它从睡眠状态唤醒?

解决方案

我最终利用了Linux内核仍然以 TIOCSTI 标志编译这一事实。

inject_to_tty.c

#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char *argv[]) {
    if (argc < 2) return 1;
    if (strlen(argv[1]) > 32) return 1;
    int fd = open("/dev/tty0", O_RDWR);
    if (fd == -1) {
      return 1; 
    }
    for (char *s = argv[1]; *s; s++)
        ioctl(fd, TIOCSTI, s);
    char nl = '\n';
    ioctl(fd, TIOCSTI, &nl);
    close(fd);
    return 0;
}

使用我自定义的 /etc/initcpio/install/dropbear 将其编译并加载到initramfs,且我在dropbear会话中启动的解锁脚本只需要

#!/bin/sh

echo "Please provide the password to unlock the system partition:"
read -s PASSWORD

/usr/bin/inject_to_tty $PASSWORD

这样,我就不会修改任何现存的钩子。其他设置步骤(允许shell、在initramfs中创建 root 用户等)在这里有详细说明:这里

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章