如何从USB加载LUKS密码,回到键盘?

时间:2013-10-31 18:21:50

标签: linux encryption disk luks

我想建立一个具有全磁盘加密功能的无头Linux(Debian Wheezy)PC,能够通过USB驱动器解锁磁盘,或者通过键盘输入密码。我的出发点是在Debian安装程序中使用基本的整个磁盘加密选项进行全新安装,除了/ boot作为LUKS加密的逻辑卷组之外,它还管理键盘选项。我将在答案中描述我当前的解决方案,希望它有用,其他人可以改进它。

以下是我遇到的一些问题:

  • 设置密码并将其放在USB驱动器上。

  • 及时加载USB模块。

  • 在尝试读取之前,等待USB驱动器被Linux识别。

  • 识别正确的USB驱动器(不是恰好插入的其他驱动器)。

  • 写一个“keyscript”来从USB驱动器中拔出密码。

  • 确保在所有USB故障情况下,键盘的后退都会出现。

我会接受一个有重大改进的答案,并提供有助于提供贡献的答案。

5 个答案:

答案 0 :(得分:20)

我的很多解决方案都来自帖子Using A USB Key For The LUKS Passphrase

  1. 创建随机密码:

    dd if=/dev/urandom bs=1 count=256 > passphrase
    
  2. 插入USB驱动器。 dmesg输出将显示设备名称;假设/dev/sdd。弄清楚它的大小:

    blockdev --getsize64 /dev/sdd
    
  3. 我决定在原始设备的末尾安装密码短语,以确定它可能会在任何意外使用USB驱动器后继续存在。

    dd if=passphrase of=/dev/sdd bs=1 seek=<size-256>
    
  4. 将密码短语添加到LUKS卷:

    cryptsetup luksAddKey /dev/sda5 passphrase
    

    这不会影响安装程序现有的手动输入密码。密码短语文件可以删除:

    rm passphrase
    
  5. 找到USB记忆棒的唯一名称,以便我们在出现时识别它:

    ls -l /dev/disk/by-id | grep -w sdd
    

    你应该看到一个符号链接。我会称之为/dev/disk/by-id/<ID>

  6. 修改/etc/crypttab。您应该看到如下行:

    sdc5_crypt UUID=b9570e0f-3bd3-40b0-801f-ee20ac460207 none luks
    

    将其修改为:

    sdc5_crypt UUID=b9570e0f-3bd3-40b0-801f-ee20ac460207 /dev/disk/by-id/<ID> luks,keyscript=/bin/passphrase-from-usb
    
  7. 上面提到的keyscript需要从USB设备读取密码。但是,它还需要做更多的事情。要了解它的使用方法,请检查/usr/share/initramfs-tools/scripts/local-top/cryptroot,即启动时运行的脚本以解锁根设备。请注意,当设置keyscript时,只需运行它,输出就会传送到luksOpen而不进行其他检查。无法发出错误信号(USB驱动器不存在)或回退到键盘输入。如果密码短语失败,则会在循环中再次运行keyscript,最多会运行一次;但是我们没有被告知我们正在进行哪次迭代。此外,我们无法控制keyscript何时运行,因此我们无法确定Linux是否识别了USB驱动器。

    我用一些黑客解决了这个问题:

    1. 轮询USB驱动器并等待3秒钟以显示它。这对我有用,但我很想知道更好的方法。

    2. 首次运行时创建一个虚拟文件/passphrase-from-usb-tried,表示我们至少运行过一次。

    3. 如果我们至少运行过一次,或者找不到USB驱动器,请运行askpass用于键盘输入的cryptroot程序。

    4. 最终剧本:

      #!/bin/sh
      
      set -e
      
      if ! [ -e /passphrase-from-usb-tried ]; then
          touch /passphrase-from-usb-tried
          if ! [ -e "$CRYPTTAB_KEY" ]; then
              echo "Waiting for USB stick to be recognized..." >&2
              sleep 3
          fi
          if [ -e "$CRYPTTAB_KEY" ]; then
              echo "Unlocking the disk $CRYPTTAB_SOURCE ($CRYPTTAB_NAME) from USB key" >&2
              dd if="$CRYPTTAB_KEY" bs=1 skip=129498880 count=256 2>/dev/null
              exit
          else
              echo "Can't find $CRYPTTAB_KEY; USB stick not present?" >&2
          fi
      fi
      
      /lib/cryptsetup/askpass "Unlocking the disk $CRYPTTAB_SOURCE ($CRYPTTAB_NAME)\nEnter passphrase: "
      

      最后,我们需要确保initramfs中提供此脚本。创建包含以下内容的/etc/initramfs-tools/hooks/passphrase-from-usb

      #!/bin/sh
      
      PREREQ=""
      
      prereqs() {
              echo "$PREREQ"
      }
      
      case "$1" in
              prereqs)
                      prereqs
                      exit 0
              ;;
      esac
      
      . "${CONFDIR}/initramfs.conf"
      . /usr/share/initramfs-tools/hook-functions
      
      copy_exec /bin/passphrase-from-usb /bin
      
    5. 我的initramfs中没有USB驱动程序。 (默认情况下,它们在Debian的更高版本中显示。)我必须通过添加/etc/initramfs-tools/modules来添加它们:

      uhci_hcd
      ehci_hcd
      usb_storage
      
    6. 完成所有操作后,请更新initramfs:

      update-initramfs -u
      

答案 1 :(得分:4)

如果我可以简单地使用一个包含密码的小型USB记忆棒,那将是理想的选择 解锁磁盘。这不仅对服务器很方便(你可以把USB棒放在那里) 服务器 - 目标是能够返回破损的硬盘而不必担心机密数据),这对我的笔记本电脑来说也很棒:在启动时插入USB记忆棒并在之后将其删除 解锁密码盘。

我现在已经编写了一个补丁,它将在所有设备的根目录中搜索文件&#39; cryptkey.txt&#39;并尝试解密 以每一行为关键。如果失败:返回键入密码短语。

它确实意味着密钥不能包含\ n,但这也适用于任何键入的密钥。好的部分是您可以使用相同的USB磁盘存储多台计算机的密钥:您不需要为每台计算机单独安装一个USB磁盘。因此,如果物理钥匙环中有USB驱动器,则可以在物理关闭时为所有启动的计算机使用相同的驱动器。

您可以使用以下内容添加密钥:

cryptsetup luksAddKey /dev/sda5

然后将相同的密钥作为一行放在名为&#39; cryptkey.txt&#39;的USB / MMC磁盘上的文件中。补丁在这里:

https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=864647

如果initramfs中没有USB驱动程序,MMC驱动程序或文件系统,则需要通过添加到/ etc / initramfs-tools / modules来添加它们:

uhci_hcd
ehci_hcd
usb_storage
nls_utf8
nls_cp437
vfat
fat
sd_mod
mmc_block
tifm_sd
tifm_core
mmc_core
tifm_7xx1
sdhci
sdhci_pci

完成所有操作后,更新initramfs:

update-initramfs -u

可以在https://gitlab.com/ole.tange/tangetools/tree/master/decrypt-root-with-usb

找到补丁和文件

答案 2 :(得分:1)

为了配合上面的优秀答案,请参阅可用于编写/生成和读取原始块设备密钥的C例程。 &#34; readkey.c&#34;从块设备中提取给定大小的密钥和&#34; writekey.c&#34;可以生成或写入原始设备的现有密钥。 &#34; readkey.c&#34;一旦编译就可以在自定义脚本中使用,从原始块设备中提取已知大小的密钥,如下所示:

readkey </path/to/device> <keysize>

要查看&#34; writekey&#34;的用法,在编译后运行它没有标志 要编译只需使用:

gcc readkey.c -o readkey

gcc writekey.c -o writekey

我在Verbatim 16GB USB 2.0 USB闪存盘上测试了自定义&#34; keyscript =&#34;在crypttab中也发表在下面。 &#34; crypto-usb.sh&#34;的想法来自&#34; debian etch&#34; cryptsetup指南。

crypto-usb.sh

#!/bin/sh
echo ">>> Trying to get the key from agreed space <<<" >&2
modprobe usb-storage >/dev/null 2>&1
sleep 4
OPENED=0
disk="/sys/block/sdb"
boot_dir="/boot"
readkey="/boot/key/readkey"
echo ">>> Trying device: $disk <<<" >&2
F=$disk/dev
if [ 0`cat $disk/removable` -eq 1 -a -f $F ]; then
    mkdir -p $boot_dir
    mount /dev/sda1 $boot_dir -t ext2 >&2
    echo ">>> Attempting key extraction <<<" >&2
    if [ -f $readkey ]; then
        # prints key array to the caller
        $readkey /dev/sdb 4096
        OPENED=1
    fi
    umount $boot_dir >&2
fi


if [ $OPENED -eq 0 ]; then
    echo "!!! FAILED to find suitable key !!!" >&2
    echo -n ">>> Try to enter your password: " >&2
    read -s -r A
    echo -n "$A"
else
    echo ">>> Success loading key <<<" >&2
fi

当必须提供生成密钥的密钥大小时,生成的密钥将保存到&#34; .tmpckey&#34;具有文件权限0600的文件供以后使用。在写入现有密钥时,通过测量现有密钥大小来确定大小。这看起来像复杂的方法,但一旦编译简单&#34; gcc&#34;它可以提供操作原始密钥内容的简便方法。

readkey.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void main(int argc, char *argv[])
{
    int blockSize = 512;
    int keySize = 2048; 

    FILE *device;       

    if (  argc == 3 
           && (sizeof(argv[1]) / sizeof(char)) > 1
           && (sizeof(argv[2]) / sizeof(char)) > 1
       && (atoi(argv[2]) % 512) == 0
       ) {
        device = fopen(argv[1], "r");
        if(device == NULL) { 
            printf("\nI got trouble opening the device %s\n", argv[1]);
            exit(EXIT_FAILURE);
        }
        keySize = atoi(argv[2]);        
    }
    else if (  argc == 2 
            && (sizeof(argv[1]) / sizeof(char)) > 1
        ) {
        device = fopen(argv[1], "r");
        if(device == NULL) { 
            printf("\nI got trouble opening the device %s\n", argv[1]);
            exit(EXIT_FAILURE);
        }

    }
    else {

        printf("\nUsage: \n");
        printf("\nKey Size Provided: \n");
        printf("\n\t\treadkey </path/to/device> <keysize> \n");
        printf("\nDefault key size: %d\n", keySize);
        printf("\n\t\treadkey </path/to/device>\n");
        exit(1);
    }

    int count;

    char *block;

    /* Verify if key is multiple of blocks */
    int numBlocks = 0;
    if (keySize % 512 != 0) {
       printf("\nSory but key size is not multiple of block size, try again. TA.\n");
       exit(1);
    }

    /* Seek till the end to get disk size and position to start */
    fseek(device, 0, SEEK_END);

    /* Determine where is the end */
    long endOfDisk = ftell(device);

    /* Make sure we start again */
    rewind(device); // Do I need it ???

    /* Get the required amount minus block size */
    long startFrom = endOfDisk - blockSize - keySize;

    /* Allocate space for bloc */
    block = calloc(keySize, sizeof(char));

    /* Start reading from specified block */
    fseek(device, startFrom, SEEK_SET);
    fread(block, 1, keySize, device);

    /* Do something with the data */
    for(count = 0; count < keySize/*sizeof(block)*/; count++){
        printf("%c", block[count]);
    }

    /* Close file */
    fclose(device);

    /* Make sure freed array is zeroed */
    memset(block, 0, keySize);
    free(block);
}

<强> writekey.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
    int blockSize = 512;
    int keySize = 2048;

    int count;

    unsigned char *block;

    /*
        Thing to always remember that argv starts from 0 - the name of the program, and argc starts from 1 i.e. 1 is the name of the program.
    */
    if ( argc == 3 
       && strcmp(argv[1], "genwrite") != 0
       && (sizeof(argv[2]) / sizeof(char)) > 2
       ) {
        char ch;
        FILE *keyF;
        keyF = fopen(argv[1], "r");
        if (keyF == NULL) exit(EXIT_FAILURE);

        /* Tell key Size */
        fseek(keyF, 0, SEEK_END);
        keySize = ftell(keyF);
        rewind(keyF);
        printf("\nKey Size: %d\n", keySize);

        block = calloc(keySize, sizeof(char));
        printf("\n-- Start Key --:\n");
                for(count = 0; count < keySize/*sizeof(block)*/; count++){
            char ch = fgetc(keyF);
                        block[count] = ch;
            /*
              Uncomment below to see your key on screen
            */
            // printf("%c",ch);

                }
        printf("\n-- End Key --:\n");
        fclose(keyF);
    }
    else if (  argc == 3 
        && strcmp(argv[1], "genwrite") == 0 
        && (sizeof(argv[2]) / sizeof(char)) > 2
        ) 
        {
        printf("\n-- Attempting to create random key(ish --) of size: %d\n", keySize);
        block = calloc(keySize, sizeof(char));
        int count;
        for(count = 0; count < keySize/*sizeof(block)*/; count++){
            block[count] = (char) rand();
        }
        FILE *tmpfile;
        tmpfile = fopen(".tmpckey", "w");
        if(tmpfile == NULL) exit(EXIT_FAILURE);
        fwrite(block, 1, keySize, tmpfile);
        fclose(tmpfile);
        chmod(".tmpckey", 0600);
    }
    else if (  argc == 4 
        && strcmp(argv[1], "genwrite") == 0
        && (sizeof(argv[2]) / sizeof(char)) > 2
        && ((atoi(argv[3]) % 512) == 0)
        ) 
        {
        keySize = atoi(argv[3]);
        printf("\n-- Attempting to create random key(ish --) of size: %d\n", keySize);
        block = calloc(keySize, sizeof(char));
        int count;
        for(count = 0; count < keySize/*sizeof(block)*/; count++){
            block[count] = (char) rand();
        }
        FILE *tmpfile;
        tmpfile = fopen(".tmpckey", "w");
        if(tmpfile == NULL) exit(EXIT_FAILURE);
        fwrite(block, 1, keySize, tmpfile);
        fclose(tmpfile);
        chmod(".tmpckey", 0600);
    }   
    else {
        printf("\n");
        printf("################################################################################\n");
        printf("#                                                                              #\n");
        printf("#                              Usage:                                          #\n");
        printf("#                                                                              #\n");
        printf("################################################################################\n");
        printf("#> To write existing key to device:                                            #\n");
        printf("#                                                                              #\n");
        printf("#     writekey </path/to/keyfile> </path/to/removable/sd*>                     #\n");
        printf("#                                                                              #\n");
        printf("#> To generate and write pseudo random key,                                    #\n");
        printf("#> key will be saved to temporary file .tmpckey                                #\n");
        printf("#                                                                              #\n");
        printf("#     writekey genwrite </path/to/removable/sd*> <keysize in multiples of 512> #\n");
        printf("#                                                                              #\n");
        printf("#> When keysize is not provided default size is set to %d.                     #\n", keySize);
        printf("#                                                                              #\n");
        printf("################################################################################\n");
        exit(1);
    }

    /*
        Some printf debugging below, uncomment when needed to see what is going on.
    */
    /*
    printf("\nNumber of Args: %d\n", argc);
    printf("\nCurrently block array contains: \n");
    for(count = 0; count < keySize; count++){
        printf("%c", block[count]);
    }
    printf("\n-- End block -- \n");
    */
    /* Open Device itp... */
    FILE *device = fopen(argv[2], "a");
    if(device == NULL) exit(EXIT_FAILURE);

    printf("\nDevice to write: %s\n", argv[2]);

    fseek(device, 0, SEEK_END);

    /* Determine where is the end */
    long endOfDisk = ftell(device);
    printf("\nDevice Size: %ld\n", endOfDisk);

    /* Verify if key is multiple of blocks */
    int numBlocks = 0;
    if (keySize % 512 != 0 || endOfDisk < (blockSize + keySize) ) {
            printf("\nSorry but key size is not multiple of block size or device you trying to write to is too small, try again. TA.\n");
        fclose(device);
            exit(1);
    }



    /* Make sure we start again */
    rewind(device);

    /* Get the required amount sunbstracting block size */
    long startFrom = endOfDisk - blockSize - keySize;

    /* Write some data to the disk */
    printf("\nWriting data starting from: %ld\n", startFrom);
    fseek(device, startFrom, SEEK_SET);
    fwrite(block, 1, keySize, device);
    printf("\nBlock Position after data write procedure : %ld\n", ftell(device));

    /*
        Below is just for convenience, to read what was written,
        can aid in debugging hence left commented for later.
    */
    /*
    printf("\nAmount of Data written : %ld\n", ftell(device) - startFrom);

    // Start reading from specified block 
    printf("\n>>>>>>>> DEBUGGING SECTION <<<<<<<<<\n");
    rewind(device); //
    fseek(device, startFrom, SEEK_SET);
    printf("\nBlock Position before read attempted: %d\n", ftell(device));
    printf("\nKey size: %d\n", keySize);
    fread(block, 1, keySize, device);

    // Do something with the data
    printf("\nBlock Position startFrom: %ld\n", startFrom);
    printf("\nBlock Position after read: %d\n", ftell(device));
    printf("\n-- Buffer Read: --\n");
    for(count = 0; count < keySize; count++){
        printf("%c", block[count]);
    }
    printf("\n-- End block -- \n");
    printf("\n--  -- \n");
    printf("\n--  -- \n");
    */

    /* Close file */
    fclose(device);

    /* Make sure freed array is zeroed */
    memset(block, 0, keySize);
    free(block);

/* Return success, might change it to be useful return not place holder */
return 0;
}

验证写入原始设备的密钥与文件中的密钥相同(如果密钥相同,下面将不输出任何内容):

diff -B <(./readkey </path/to/device> 4096) <(cat .tmpckey)

或者使用自己的方式生成的现有密钥:

diff -B <(./readkey </path/to/device> <generated elsewhere key size>) <(cat </path/to/keyfile>)

谢谢

答案 3 :(得分:1)

尽管@Andrew给出了很好的答案,该答案在以前的版本中仍然有效。该解决方案实际上已经过时了,需要针对Ubuntu 18.04和19.10进行大量调整。因此,我想分享我对此的研究。

有关crypttab的一些注意事项。 Sepcs实际上从14.04到18.04以及19.10发生了很大变化。它开始支持更多的cryptsetup参数。例如keyfile-offset,keyfile-size等。某些选项例如nobootwait不见了。某些参数已在其他发行版中受支持,但在ubuntu中尚不支持(例如,非常好的参数keyfile-timeout。这可以消除整个键盘脚本,因为它将在keyfile-timeout之后自动回退到键盘输入。)

ubuntu上crypttab的主要缺陷是它实际上由2个不同的进程处理。一个是传统的initramfs,另一个是现代systemd。 Systemd在许多方面都应该更加先进和灵活。但是, systemd对crypptab的支持很差,有很多选项,例如关键字脚本只是被默默地忽略了。,所以我不知道发生了什么,直到发现this post。几乎所有有关crypttab设置的在线帖子都是针对initramfs而不是针对systemd。因此,我们需要将initramfs添加到crypttab中的所有条目中,以避免出现问题。

我还发现了一种无需VM或反复重启即可调试我们的脚本和crypttab的好方法。是cryptdisks_start。在我们将更改实际传播到initramfs之前,我们应该始终使用此命令进行测试。否则,您必须最终将其锁定在系统之外,并且只能通过chroot环境进行恢复。

@andrew发布了一种在文件系统原始区域中使用数据隐藏的好方法。但是,我发现当我们想要自动创建分区并将原始数据添加到大量usbkey时非常烦人,我们必须计算所有不同文件系统和不同分区大小的偏移量。此外,如果用户不小心写入FS,则存在密钥被覆盖的风险。在这种情况下,没有任何FS的原始分区更有意义。但是原始分区没有UUID,这对于自动解锁不是很有用。因此,我想介绍一种只在usbkey文件系统上使用普通密码文件的方法。 passdev的主要问题是在读取文件期间不会查找/停止。因此,当我们要回退到键盘输入时,就不能使用keyfile-offset和keyfile-size选项。因为cryptsetup实际上会尝试跳过输入内容,并且如果内容短于keyfile-size,它将引发一个错误。这也意味着,如果偏移量很大,passdev可能会非常慢,因为它总是从头读取。但是,没有必要为文件系统上的实际文件实现偏移量和密钥文件大小。我相信这些都是为原始设备创建的。

crypttab

luks-part UUID="<uuid>" /dev/disk/by-uuid/<keyfile FS uuid>:/<keyfile path relative to usbkey root>:<timeout in sec> luks,keyfile-offset=<seek to the key>,keyfile-size=<>,keyscript=/bin/passphrase-from-usbfs.sh,tries=<number of times to try>,initramfs

关键脚本passphrase-from-usbfs.sh利用了/lib/cryptsetup/scripts/passdev,它将等待usb设备并挂载fs,然后输出文件内容。它支持CRYPTTAB_KEY格式的/device-path/<keyfile FS uuid>:/<keyfile path relative to usbkey root>:<timeout in sec>

#!/bin/sh
#all message need to echo to stderr, the stdout is used for passphrase
# TODO: we may need to do something about the plymouth
echo "CRYPTTAB_KEY=$CRYPTTAB_KEY" >&2
echo "CRYPTTAB_OPTION_keyfile_offset=$CRYPTTAB_OPTION_keyfile_offset" >&2
#set your offset and file size here if your system does not support those paramters
#CRYPTTAB_OPTION_keyfile_offset=
#CRYPTTAB_OPTION_keyfile_size=
echo "timeout=$CRYPTTAB_OPTION_keyfile_timeout" >&2
CRYPTTAB_OPTION_keyfile_timeout=10 # keyfile-timeout is not supported yet 
pass=$(/lib/cryptsetup/scripts/passdev $CRYPTTAB_KEY)
rc=$?
if ! [ $rc -eq 0 ]; then
    echo "Can't find $CRYPTTAB_KEY; USB stick not present?" >&2
    /lib/cryptsetup/askpass "Unlocking the disk $CRYPTTAB_SOURCE ($CRYPTTAB_NAME) Enter passphrase: "
else
    echo "successfully load passphrase." >&2
    echo -n $pass
fi

该钩子告诉update-initramfs复制我们的脚本。

#!/bin/sh

PREREQ=""

prereqs() {
        echo "$PREREQ"
}

case "$1" in
        prereqs)
                prereqs
                exit 0
        ;;
esac

. "${CONFDIR}/initramfs.conf"
. /usr/share/initramfs-tools/hook-functions
copy_exec /bin/passphrase-from-usbfs.sh
copy_exec /bin/passphrase-from-usb.sh
#when using passdev we need to hook additionaly FS and binary
copy_exec /lib/cryptsetup/scripts/passdev
manual_add_modules ext4 ext3 ext2 vfat btrfs reiserfs xfs jfs ntfs iso9660 udf

最后,我发布了passphrase-from-usb.sh的更新版本,该版本可以使用crypttab中的新参数:

答案 4 :(得分:1)

这里有一个类似于 one by Andrew 的解决方案,但是

  • 使用 Debian crypttab man page 中描述的 CRYPTTAB_TRIED 来区分尝试,以及

  • 在第一次尝试时调用现有的标准键脚本 /lib/cryptsetup/scripts/passdev

  1. 照常为 passdev 脚本创建您的密钥文件或密钥分区。

  2. 创建以下文件 /usr/local/bin/key-from-usb 并使其可执行。

    #!/bin/sh
    set -e
    if [ $CRYPTTAB_TRIED -ge 1 ]; then
      /lib/cryptsetup/askpass "Second try to unlock $CRYPTTAB_SOURCE ($CRYPTTAB_NAME). Please enter passphrase: "
    else
      /lib/cryptsetup/scripts/passdev $CRYPTTAB_KEY
    fi
    
  3. /etc/crypttab 中使用参数 keyscript=/usr/local/bin/key-from-usb

  4. 使用此内容创建 /etc/initramfs-tools/hooks/key-from-usb

    #!/bin/sh
    
    PREREQ=""
    
    prereqs() {
            echo "$PREREQ"
    }
    
    case "$1" in
             prereqs)
                     prereqs
                     exit 0
             ;;
    esac
    
    . "${CONFDIR}/initramfs.conf"
    . /usr/share/initramfs-tools/hook-functions
    
    manual_add_modules vfat
    
    copy_exec /usr/lib/cryptsetup/scripts/passdev /usr/lib/cryptsetup/scripts/passdev
    
    copy_exec /usr/local/bin/key-from-usb /usr/local/bin/key-from-usb
    

    此处需要第一个 copy_exec 行,因为如果 passdev 中未提及,则不会复制 crypttab。同样,manual_add_modules vfat 将确保仍然可以使用 vfat usb 磁盘。

提示:使用 lsinitramfs /boot/initrd.img-... 和 diff/compare 结果来检查是否包含脚本及其所有依赖项。