dm-integrity¶
dm-integrity 目标模拟一个块设备,该设备具有额外的每扇区标签,可用于存储完整性信息。
将完整性标签与每个扇区一起存储的一个普遍问题是,写入扇区和完整性标签必须是原子的 - 即,在崩溃的情况下,要么写入扇区和完整性标签,要么都不写入。
为了保证写入原子性,dm-integrity 目标使用日志,它将扇区数据和完整性标签写入日志,提交日志,然后将数据和完整性标签复制到它们各自的位置。
dm-integrity 目标可以与 dm-crypt 目标一起使用 - 在这种情况下,dm-crypt 目标创建完整性数据,并通过附加到 bio 的 bio_integrity_payload 将它们传递给 dm-integrity 目标。 在这种模式下,dm-crypt 和 dm-integrity 目标提供经过身份验证的磁盘加密 - 如果攻击者修改了加密设备,则会返回 I/O 错误而不是随机数据。
dm-integrity 目标也可以用作独立目标,在这种模式下,它会在内部计算并验证完整性标签。 在这种模式下,dm-integrity 目标可用于检测磁盘上或 I/O 路径中的静默数据损坏。
还有一种替代操作模式,其中 dm-integrity 使用位图而不是日志。 如果位图中的某个位为 1,则相应的区域的数据和完整性标签未同步 - 如果机器崩溃,则将重新计算未同步的区域。 位图模式比日志模式更快,因为我们不必两次写入数据,但它也更不可靠,因为如果在机器崩溃时发生数据损坏,则可能无法检测到。
首次加载目标时,内核驱动程序将格式化设备。 但只有当超级块包含零时,它才会格式化设备。 如果超级块既不是有效也不是零,则无法加载 dm-integrity 目标。
使用 dm-bufio 缓冲对包含校验和(又名标签)的磁盘元数据区域的访问。 当访问任何给定的元数据区域时,每个唯一的元数据区域都有自己的缓冲区。 缓冲区大小上限为元数据区域的大小,但可能会更小,因此需要多个缓冲区来表示完整的元数据区域。 较小的缓冲区大小将为小的读/写操作产生对元数据区域的较小读/写操作。 即使在对单个缓冲区覆盖的数据进行完整写入时,仍然会读取元数据。
首次使用目标
用零覆盖超级块
加载单扇区大小的 dm-integrity 目标,内核驱动程序将格式化设备
卸载 dm-integrity 目标
从超级块读取 “provided_data_sectors” 值
加载目标大小为 “provided_data_sectors” 的 dm-integrity 目标
如果要将 dm-integrity 与 dm-crypt 一起使用,请加载大小为 “provided_data_sectors” 的 dm-crypt 目标
目标参数
底层块设备
设备开头保留扇区的数量 - dm-integrity 将不会读取或写入这些扇区
完整性标签的大小(如果使用“-”,则从内部哈希算法中获取大小)
模式
- D - 直接写入(不带日志)
在此模式下,不使用日志记录,并且数据扇区和完整性标签是单独写入的。 如果发生崩溃,则数据和完整性标签可能不匹配。
- J - 日志写入
数据和完整性标签被写入日志,并保证原子性。 如果发生崩溃,则写入数据和标签,或者两者都不写入。 日志模式使写入吞吐量降低一倍,因为数据必须写入两次。
- B - 位图模式 - 数据和元数据在没有任何
同步的情况下写入,驱动程序维护一个数据和元数据不匹配的脏区域的位图。 此模式只能与内部哈希一起使用。
- R - 恢复模式 - 在此模式下,不重放日志,
不检查校验和,并且不允许写入设备。 如果设备无法以任何其他标准模式激活,则此模式对于数据恢复很有用。
其他参数的数量
其他参数
- journal_sectors:number
日志的大小,此参数仅在格式化设备时使用。 如果设备已格式化,则使用超级块中的值。
- interleave_sectors:number(默认 32768)
交错扇区的数量。 此值向下舍入为 2 的幂。 如果设备已格式化,则使用超级块中的值。
- meta_device:device
不要在设备上交错数据和元数据。 对元数据使用单独的设备。
- buffer_sectors:number(默认 128)
一个元数据缓冲区中的扇区数。 该值向下舍入为 2 的幂。
- journal_watermark:number(默认 50)
日志水印(以百分比表示)。 当日志大小超过此水印时,将启动刷新日志的线程。
- commit_time:number(默认 10000)
提交时间,以毫秒为单位。 当此时间过去时,将写入日志。 如果收到 FLUSH 请求,也会立即写入日志。
- internal_hash:algorithm(:key) (密钥是可选的)
使用内部哈希或 crc。 当使用此参数时,dm-integrity 目标将不接受来自上层目标的完整性标签,但它将自动生成和验证完整性标签。
您可以使用 crc 算法(例如 crc32),然后完整性目标将保护数据免受意外损坏。 您还可以使用 hmac 算法(例如 “hmac(sha256):0123456789abcdef”),在此模式下,它将提供数据的加密身份验证,而无需加密。
当不使用此参数时,将从上层目标(例如 dm-crypt)接受完整性标签。 上层目标应检查完整性标签的有效性。
- recalculate
自动重新计算完整性标签。 它仅在使用内部哈希时有效。
- journal_crypt:algorithm(:key) (密钥是可选的)
使用给定的算法加密日志,以确保攻击者无法读取日志。 您可以在此处使用块密码(例如 “cbc(aes)”)或流密码(例如 “chacha20” 或 “ctr(aes)”)。
日志记录了对块设备的最后写入历史,攻击者读取日志可以看到最后写入的扇区号。从扇区号中,攻击者可以推断出写入的文件大小。为了防止这种情况,您可以加密日志。
- journal_mac:算法(:密钥) (密钥是可选的)
保护日志中的扇区号免受意外或恶意修改。为了防止意外修改,请使用crc算法;为了防止恶意修改,请使用带有密钥的hmac算法。
当使用internal-hash时,此选项不是必需的,因为在这种模式下,在重放日志时会检查日志条目的完整性。因此,在这种情况下会检测到修改后的扇区号。
- block_size:数字 (默认512)
数据块的大小,以字节为单位。块大小越大,每个块的完整性元数据开销就越小。支持的值为512、1024、2048和4096字节。
- sectors_per_bit:数字
在位图模式下,此参数指定一个位图位对应的512字节扇区数。
- bitmap_flush_interval:数字
位图刷新间隔,以毫秒为单位。当此间隔到期时,将同步元数据缓冲区。
- allow_discards
允许完整性设备的块丢弃请求(又名TRIM)。仅允许使用内部哈希的设备进行丢弃。
- fix_padding
使用更小的标签区域填充,这样可以更节省空间。如果此选项不存在,则使用较大的填充,以便与旧内核兼容。
- fix_hmac
提高internal_hash和journal_mac的安全性
节号会混合到mac中,这样攻击者就无法将扇区从一个日志节复制到另一个日志节
超级块受到journal_mac的保护
存储在超级块中的16字节盐会混合到mac中,这样攻击者就无法检测到两个磁盘具有相同的hmac密钥,并且也不允许攻击者将扇区从一个磁盘移动到另一个磁盘
- legacy_recalculate
允许重新计算带有HMAC密钥的卷。出于安全原因,默认情况下禁用此选项 - 攻击者可能会修改卷,将recalc_sector设置为零,而内核不会检测到修改。
当重新加载目标时(加载一个非活动表,并使用挂起和恢复来交换表),可以更改日志模式 (D/J)、buffer_sectors、journal_watermark、commit_time 和 allow_discards。重新加载目标时,不应更改其他参数,因为磁盘数据的布局取决于这些参数,并且重新加载的目标将无法正常工作。
例如,在默认的交错扇区interleave_sectors为32768、块大小block_size为512以及带有4字节标签大小的crc32c的internal_hash的设备上,将需要128 KiB的标签来跟踪完整的数据区域,每个数据区域需要256个扇区的元数据。使用默认的buffer_sectors为128,这意味着每个元数据区域将有2个缓冲区,或每16 MiB的数据有2个缓冲区。
状态行
完整性不匹配的数量
提供的可用数据扇区 - 即用户可以使用的扇区数
当前的重新计算位置(如果未重新计算,则为“-”)
格式化块设备的布局
- 保留扇区
(这些扇区未被此目标使用,它们可以用于存储LUKS元数据或其他目的),保留区域的大小在目标参数中指定
- 超级块 (4kiB)
魔术字符串 - 标识设备已格式化
版本
log2(交错扇区数)
完整性标签大小
日志节数
提供的可用数据扇区 - 此目标提供的扇区数(即设备大小减去所有元数据和填充的大小)。此目标的用户不应发送访问超出“提供的可用数据扇区”限制的数据的bios。
- 标志
- SB_FLAG_HAVE_JOURNAL_MAC
如果使用了journal_mac,则会设置一个标志
- SB_FLAG_RECALCULATING
正在重新计算
- SB_FLAG_DIRTY_BITMAP
日志区域包含脏块的位图
log2(每个块的扇区数)
重新计算完成的位置
- 日志
日志分为多个节,每个节包含
元数据区域 (4kiB),其中包含日志条目
每个日志条目包含
逻辑扇区(指定应写入数据和标签的位置)
数据的最后8个字节
完整性标签(大小在超级块中指定)
每个元数据扇区都以
mac (8字节) 结尾,8个元数据扇区中的所有mac构成一个64字节的值。它用于存储日志节中扇区号的hmac,以防止攻击者篡改日志中的扇区号。
提交ID
数据区域(大小可变;取决于有多少日志条目适合元数据区域)
数据区域中的每个扇区都包含
数据(504字节的数据,最后8个字节存储在日志条目中)
提交ID
为了测试整个日志节是否正确写入,日志的每个512字节扇区都以8字节的提交ID结尾。如果一个日志节中所有扇区的提交ID都匹配,则假定该节已正确写入。如果提交ID不匹配,则该节是部分写入的,不应重放。
- 一个或多个交错的标签和数据运行。
每个运行包含
标签区域 - 它包含完整性标签。数据区域中的每个扇区都有一个标签。此区域的大小始终为4KiB或更大。
数据区域 - 它包含数据扇区。一次运行中的数据扇区数必须是2的幂。此值的log2存储在超级块中。