如何向 initramfs 中等待输入的 cryptsetup 提供口令?
结论
向 /proc/200/fd/0 写入口令,不会把口令作为终端输入交给 cryptsetup。这种写入会向对应设备写入数据;终端输入则通过 TTY 的输入侧传给正在读取的进程。S 表示进程处于可中断睡眠状态,通常是正在等待读取。输入到达它实际读取的终端后,内核会唤醒读取操作,无须先结束进程的睡眠状态。
正常输入如何到达 cryptsetup
interactive_pass 会尝试打开 /dev/tty。进程有控制终端时,/dev/tty 指向该控制终端,不一定是 /dev/tty0。只有打开失败时,代码才会回退到标准输入。题中进程的标准输入指向 /dev/console,但这无法判断它是否成功打开了 /dev/tty;/proc/200/fd 也不会显示那次打开所用的所有文件描述符。
正常情况下,键盘或终端模拟器会把按键送到相应 TTY 的输入端。TTY 驱动处理字符后,等待 read() 的进程才能收到输入。输入是否回显由终端设置决定,口令通常会关闭回显。向该设备写入字符不会把字符注入 TTY 的输入队列。
SSH 会话有自己的终端路径。如果 Dropbear 为登录会话分配了 PTY,在 SSH shell 中键入的口令会进入该会话的 PTY,不会自动转发给正在 /dev/console 或其他控制终端上等待的 cryptsetup。即使把 /proc/200/fd/0 写成 /dev/console,也不会建立这种转发关系。
经 SSH 解锁
可以在 SSH 会话的交互式终端中运行解锁命令,让新启动的 cryptsetup 从该会话对应的终端读取口令:
cryptsetup open --type luks /dev/vda2 root
这会启动新的解锁操作,不能向进程 200 正在等待的读取操作提供输入。如果原进程仍在等待,而新命令也尝试创建名为 root 的映射,两者可能发生冲突。如何让 initramfs 的启动流程继续运行,取决于 hook 调用和等待 cryptsetup 的方式。需要让解锁操作与该流程配合,例如在 hook 中集成远程解锁步骤,或根据实际流程停止等待中的操作后重新执行解锁。现有描述不足以判断哪种方式适合该 hook。
关于进程状态和终端定位
S 表示可中断睡眠状态。进程阻塞在读取操作上时处于睡眠状态很正常;正确终端收到输入后,读取操作便可继续。/proc/200/stat 中的终端信息有助于判断进程是否关联了控制终端,但无法将 SSH PTY 的输入转发到另一个终端。
因此,需要让解锁命令从可访问的 SSH PTY 读取口令,并与 initramfs 的解锁和启动流程配合。向进程文件描述符对应的设备写入数据,无法模拟用户按键。
备注:内容仅供参考。
