LWN: 存储设备直接进行文件数据加密

640

点击上方蓝色“Linux News搬运工”关注我们~



Inline encryption for filesystems

By Jonathan Corbet
August 27, 2019


小至移动设备,大到数据中心,都越来越需要把数据加密作为一个强制性要求了。Linux在filesystem文件系统层和block-storage层都早已支持加密,不过这是有代价的:要么用CPU来做很多数据的加解密与搬移,要么就把这个工作offload(迁移)到专门的硬件上去做。因此,慢慢的大家就发现最好能把这个工作交给存储设备本身来做。Satya Tangirala提出了一个inline encryption patch set,希望能让kernel来更好的利用支持inline encryption的硬件设备。


Linux storage stack包含很多层代码,inline encryption的改动也需要改动好几层。Hardware-offloaded encryption不仅需要有相应的设备驱动支持,还需要知道相应的加密秘钥,而这个秘钥正是从storage stack最顶层——文件系统层拿到的。因此从最顶层打通到最底层,需要不少工作。


Low-level support


最底层就是设备驱动了,支持inline encryption的设备驱动都会提供下面这个结构来指定相应的操作函数列表:

   struct keyslot_mgmt_ll_ops {

 
 

    int (*keyslot_program)(void *ll_priv_data, const u8 *key,
          enum blk_crypto_mode_num crypto_mode,
          unsigned int data_unit_size,
          unsigned int slot);
    int (*keyslot_evict)(void *ll_priv_data, const u8 *key,
        enum blk_crypto_mode_num crypto_mode,
        unsigned int data_unit_size,
        unsigned int slot);
    bool (*crypto_mode_supported)(void *ll_priv_data,
         enum blk_crypto_mode_num crypto_mode,
         unsigned int data_unit_size);
    int (*keyslot_find)(void *ll_priv_data, const u8 *key,
       enum blk_crypto_mode_num crypto_mode,
       unsigned int data_unit_size);
   };


这个接口是根据硬件设备来设计的,通常硬件设备都提供固定数量的“key slots”,每个key slot都包含一组加解密上下文,里面包括需要用什么算法,相关的参数(例如block size),还有秘钥。上面这些函数分别用于把这些加解密上下文信息写入硬件;从硬件里移除;查询支持哪些加解密上下文;查询哪个slot用了我们指定的上下文。驱动程序会注册上面这个struct,以及提供总共有多少个slot可用。


硬件所能支持的key slot数量是固定的,所以有可能在短时间内全部用光,无法支撑所有正在进行的I/O请求。如果这个存储设备本身被一个独立的加密文件系统完全占用的话,那就完全没问题了。不过如果它里面有很多文件系统,甚至有per-directory encryption(每个目录可以使用不同的秘钥,ext4文件系统可以支持),那就比较麻烦了。kernel因此需要有办法来对这些key slot的使用进行仲裁协调,最好能尽量减少key slot的内容更新替换(因为会很耗时间)。


这个仲裁是由一个抽象对象“key-slot manager”来完成的,它会持续监控哪些key slot可用,以及查看正在工作中的key slot有多少个引用(代表有多少个I/O操作正在使用它)。key-slot manager也被用于分配slot,写入加解密上下文。通常来说,很多I/O请求都实际上是在用同一个上下文,因此key-slot manager就会尽量确保最频繁用到的key要一直保留在硬件里,同时当然也要避免把同一个key写入多个slot里面。


在设备驱动往上的一层,也需要改动代码,给BIO结构(代表一个I/O request)新增了一个bio_crypt_ctx结构。文件系统代码发起一次I/O请求的时候,就可以附带上相关的加解密上下文信息,BIO结构就会一直带着这个信息送到block device这层来完成I/O请求。所以也会需要改变block layer的很多代码,例如从前两个相邻的request可以被合并,但是现在需要判断一下他们是否使用相同的加解密上下文,否则绝对不能合并。


blk-crypto


给BIO结构增加秘钥信息还是不够的,仍然需要注意slot management以及把加解密上下文写入硬件的过程。虽然filesystem可以做这个工作,不过更合理的做法是应该在block layer这一层自己处理掉。这里还是有一点需要注意:文件系统发布的I/O request的目标设备可能不是最终真正完成这个request的设备。举例来说,文件系统可能是基于一个device-mapper layer创建的RAID设备,文件系统层的代码完全不知道真实硬件是什么样,只能看到device-mapper映射出来的虚拟设备。因此文件系统没法直接处理最终key-slot管理的的工作。


解决方案是利用blk-crypto subsystem来处理key slot的管理,以及把key信息传给正确的设备驱动。

每次有BIO请求提出的时候,blk-crypto代码都会从目标设备相关key-slot manager这里分配一个slot来管理加解密上下文信息。所以device mapper就需要实现一个简单的key-slot manager,虽然它自己本身不需要参与加密操作,原因后面会讲到。


像device manager这样的中间层虚拟设备需要修改它收到的BIO(甚至可能会把收到的BIO切分成多个BIO),然后重新提交修改之后的BIO给底层设备。在这个过程中,blk-crypto layer会把中间层的key slot释放掉,然后新分配一个底层设备的slot,把key的信息迁移过去。这个动作可以做多次,直到BIO被传递给真正做I/O的设备上。


blk-crypto代码还有个有用的功能:如果目标设备其实不支持文件系统要求的加密方式(或者干脆就不支持加解密),那么blk-crypto可以退而求其次来直接使用kernel的crypto layer。这样文件系统根本不用管底层是否支持inline encryption加密,都可以强行要求对存储中的数据进行加解密。这个功能最终可能会替代ext4和F2FS目前在用的fscrypt代码,彻底接管文件加密操作。


crypto-layer回退到kernel crypto处理,也就解释了为什么中间层block layer(例如device mapper映射出来的虚拟设备)也需要提供key-slot manager功能。block layer不了解手头在处理的BIO最终是否会被提交给底层设备,所以它肯定都会假设当前BIO就是最后一步了。因此,如果加解密是由kernel的crypto layer来实现的,那么就一定要在把BIO提交给设备之前完成,在此之后就再也没有机会来做加解密了。

如果某个设备没有key-slot manager,block layer就会认为底层不支持inline encryption,这样crypto-layer就会直接把加解密动作完成掉,在这个动作之后,哪怕最终发现inline encryption设备是可用的,也不会再用它处理当前BIO了。对device mapper layer增加一个key-slot manager是一个很好的方法来避免block layer太早放弃inline encryption。


这组patch set还包含了Universal Flash Storage设备的底层实现,以及针对F2FS的支持。大家已经能看出来了,这个工作是为了Android使用场景而做的,加密文件系统对Android设备来说非常重要,而如果能够把真正的加密动作offload到真正的硬件去操作,就能节省CPU时间和功耗。


这个功能很有价值,因此此前已经有过几次尝试希望能加到kernel里了。这个patch set就提到了此前的三组方案,包括有一个针对某种硬件特有的方案,不够通用;一个方案实现在了crypto layer,这个位置不对,因为这不是一个通用加解密操作原语;一个方案需要使用到device mapper。

本文提到的patch是希望能避免上述这些问题,提供一个通用解决方案。目前已经review到第四版了,可能很快会被mainline接受。


全文完

LWN文章遵循CC BY-SA 4.0许可协议。

极度欢迎将文章分享到朋友圈 
热烈欢迎转载以及基于现有协议修改再创作~


长按下面二维码关注:Linux News搬运工,希望每周的深度文章以及开源社区的各种新近言论,能够让大家满意~


640?wx_fmt=jpeg

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值