使用syscall()链接initramfs中的密钥环

时间:2019-03-29 14:34:55

标签: c linux security system-calls

我想将IMA / EVM的证书加载到Linux密钥环中。

相关的shell命令是

ima_id=`keyctl newring _ima @u`
evm_id=`keyctl newring _evm @u`
evmctl import  /etc/keys/x509_ima.der $ima_id
evmctl import  /etc/keys/x509_evm.der $evm_id

除了权限问题之外,这几乎可以正常工作。

# keyctl show @u
Keyring
 272896171 --alswrv      0 65534  keyring: _uid.0
 406281657 --alswrv      0     0   \_ keyring: _ima
keyctl_read: Permission denied

在网络上搜索,我发现:https://github.com/systemd/systemd/issues/5522

解决方法是链接密钥环:

keyctl link @us @s

如果我在引导后在外壳上输入以下命令,则可以看到这些键:

# keyctl show @u
Keyring
 272896171 --alswrv      0 65534  keyring: _uid.0
 406281657 --alswrv      0     0   \_ keyring: _ima
 647882074 --als--v      0     0   |   \_ asymmetric: abc: gerhard signing key: 15733607aff5480b5eb8b59b501760f9c5d33965
  19332842 --alswrv      0     0   \_ keyring: _evm
 470827275 --als--v      0     0       \_ asymmetric: abc: gerhard signing key: 7e5959ee64090c7fabb6dd803e7d1f48e83c5970

到目前为止一切都很好...

要有用,我需要将这些内容放入initramfs中。 我正在处理的系统是嵌入式Linux,在initramfs期间我没有外壳。

因此,我使用syscall来完成需要做的事情...

创建密钥环并导入密钥可以正常工作。 但是链接钥匙圈没有。

启动后,出现与上述相同的“权限被拒绝”错误。当我尝试执行具有IMA签名的文件时,也会收到错误消息。它说未找到“ _ima”钥匙圈。

如果我手动输入keyctl link @us @s,一切都会恢复。

我的假设是在initramfs期间与密钥环相关的内容尚未到位,但我无法掌握。

我用于链接的syscall如下:

ret = syscall(__NR_keyctl, KEYCTL_LINK, KEY_SPEC_USER_SESSION_KEYRING, KEY_SPEC_SESSION_KEYRING, 0, 0);

我没有从通话中得到任何负面结果。

更新

我在此页面上找到了一些提示:https://mjg59.dreamwidth.org/37333.html

因此,顺序应如下:

$ keyctl add user testkey testdata @s
$ keyctl setperm 678913344 0x3f3f0000
$ keyctl link 678913344 @u
$ keyctl unlink 678913344 @s

这对密钥有效,但据我了解,对密钥环也应有效。

static void create_ima_keyring(void)
{
    char *name = "_ima";
    char *filename = "/etc/keys/x509_ima.der";

    int ringid = syscall(__NR_add_key, "keyring", name, NULL, 0, KEY_SPEC_SESSION_KEYRING);
    {
        // Set permission for keyring ...
        int ret = syscall(__NR_keyctl, KEYCTL_SETPERM, ringid, 0x3f3f0000, 0, 0);

        // ... and link to @u
        syscall(__NR_keyctl, KEYCTL_LINK, ringid, KEY_SPEC_USER_KEYRING);

        int len;
        unsigned char *pub = file2bin(filename, &len);
        if (pub != NULL)
        {
            int keyid = syscall(__NR_add_key, "asymmetric", NULL, pub, len, ringid);
            if (keyid >= 0)
            {
                int ret = syscall(__NR_keyctl, KEYCTL_SETPERM, keyid, 0x3f3f0000, 0, 0);
            }
            free(pub);
        }

        // TODO: Unlink from @s
    }
}

在此示例中删除了错误处理。我没有得到任何错误结果。

现在,我从keyctl show @u获得了预期的结果,但是仍无法识别密钥环。 执行签名的文件会再次导致错误消息:

digsig: no _ima keyring: -126

2 个答案:

答案 0 :(得分:1)

对于您填充initramfs的实际步骤,我还不太清楚...尝试检查内容:(假设gzip压缩,也可以尝试xz / lz4 / none)

gzip -dkcq -S img '/path/to/initramfs.img' | cpio -t

我的第一个猜测是,您将发现initramfs img中不存在/etc/keys/x509-blahblah。尤其是因为它们在启动时“未找到”,但在登录后仍可以工作。它还可能缺少必要的二进制文件/库或内核模块。

如果仅是密钥本身,则在允许的情况下将它们添加到任何initramfs生成工具的配置中应该相当简单。如果keyctl需要到同一物理存储的符号链接,则需要安排initramfs在挂载real_root之后运行任务,但是cpio可以在其中安装一个。 如果需要您手动添加加密模块,则可能会很有趣。

内核(从2.something?开始)还可以接受多个initramfs文件,它将合并。上次我查看大多数针对台式机的引导加载程序 did 可以执行此操作时,尽管在此问题上完全沉默,但...仅用键构建单独的initramfs映像就足够了并同时通过。以下应该可以创建一个。

cd /etc/keys
mkdir mkimg
find ./ -maxdepth 1 -type f | 
   sed 's/^[.]\///' |
   cpio -o -H newc --no-absolute-filenames --renumber-inodes |
   gzip -9qc - > ./mkimg/bootkeys.img'

我编写密钥的方式将在启动时将密钥转储到initramfs的根目录中,据我的经验,这比尝试合并目录要简单,但是可以根据需要进行更改。

编辑:我假设您的系统未配置为在pivot_root或某些类似的嵌入式人员事件之后联合安装rootfs?

答案 1 :(得分:0)

更多地阅读并深入研究配置后,发现还需要一个额外的配置标志。

我必须启用CONFIG_PERSISTENT_KEYRINGS=y,现在可以使用该标志将密钥加载到initramfs中,并在登录后稍后使用。

不再有“没有_ima keyring”投诉。