dm-integrity — 블록 레벨 무결성(Integrity) 보호
dm-integrity는 Device Mapper 프레임워크 위에서 읽기/쓰기 모두 지원하는 블록 레벨 무결성 보호를 제공합니다.
저널링(Journaling) 기반 무결성 태그로 crash-safety를 보장하며,
Bitmap 모드로 대용량 디스크에서 성능을 최적화하고,
dm-crypt와 AEAD 결합으로 암호화(Encryption)+무결성을 단일 레이어에서 달성합니다.
커널 내부 구현(drivers/md/dm-integrity.c)을 심층 분석합니다.
- dm-verity — Merkle Tree 기반 읽기 전용(Read-Only) 블록 검증
- dm-crypt — 블록 레벨 투명 암호화, LUKS, 성능 최적화
- Device Mapper / LVM — DM 프레임워크 기본
핵심 요약
- Device Mapper — 블록 디바이스 위에 가상 매핑(Mapping) 레이어를 제공하는 커널 프레임워크
- dm-integrity — 읽기/쓰기 모두 지원하는 무결성 태그 + 저널링
- Journal 모드 — 데이터+태그를 저널에 먼저 기록하여 crash-safety 완전 보장
- Bitmap 모드 — dirty 블록 추적으로 성능 향상, crash 후 부분 재검증
- AEAD 결합 — dm-crypt + dm-integrity를 결합한 인증 암호화 (AES-GCM)
단계별 이해
- Device Mapper 레이어 이해
커널의 블록 I/O 스택에서 DM은 bio를 가로채 target 드라이버에 전달합니다. - dm-integrity로 실시간 무결성
매 쓰기마다 무결성 태그를 계산하고 저널에 기록하여 crash-safety를 보장합니다. - 저널링과 crash-safety
저널은 순환 버퍼(Buffer)로 데이터+태그를 원자적(Atomic)으로 기록하며, 정전 후에도 일관성을 유지합니다. - AEAD 모드로 암호화 결합
dm-crypt + dm-integrity AEAD 모드로 암호화와 무결성을 동시에 달성합니다.
Device Mapper 연결 지점
이 문서는 Device Mapper 전체 구조를 반복 설명하기보다 dm-integrity target이 DM 코어와 만나는 지점만 짚습니다.
DM의 공통 자료구조(mapped_device, dm_table, dm_target)와 ioctl 흐름은
Device Mapper / LVM 문서에서 먼저 확인하세요.
- 테이블 로드:
integritytarget 인자는 태그 크기, 저널 모드, 내부 메타데이터 배치를 결정합니다. - I/O 매핑: 쓰기 경로는 데이터와 무결성 태그를 함께 갱신하고, 읽기 경로는 저장된 태그와 계산 결과를 비교합니다.
- 스택 배치: 암호화와 함께 사용할 때는
dm-integrity -> dm-crypt순서와 AEAD 모드의 성능 차이를 함께 평가해야 합니다.
map() 반환값, suspend/resume, table 교체 같은 공통 동작은 Device Mapper / LVM 문서로 모았습니다.
dm-integrity 개요
dm-integrity는 읽기/쓰기 모두 지원하는 블록 레벨 무결성 보호를 제공합니다.
dm-verity와 달리 쓰기 시에도 무결성 태그를 자동으로 계산하여 저장하며,
저널링을 통해 crash-safety를 보장합니다. 커널 소스 drivers/md/dm-integrity.c에 구현되어 있으며,
Journal, Bitmap, Direct(no-journal) 세 가지 모드를 제공합니다.
/* drivers/md/dm-integrity.c */
struct dm_integrity_c {
struct dm_dev *dev;
struct dm_dev *meta_dev; /* 별도 메타 디바이스 (선택) */
unsigned int tag_size; /* 태그 크기 (바이트) */
unsigned int sectors_per_block; /* 블록당 섹터 수 */
__u64 provided_data_sectors; /* 사용 가능 데이터 섹터 */
unsigned int journal_entries;
unsigned int journal_sections;
struct journal_entry *journal;
struct crypto_shash *internal_hash;
struct crypto_shash *journal_mac;
enum integrity_mode mode; /* J, B, D (journal/bitmap/direct) */
bool recalculate;
};
| 모드 | 저널 | Crash Safety | 성능 | 주요 용도 |
|---|---|---|---|---|
| Journal (J) | 전체 저널 | 완전 보장 | 쓰기 2x 오버헤드(Overhead) | 단독 사용 |
| Bitmap (B) | 비트맵(Bitmap)만 | dirty 블록 재검증 | 저널보다 빠름 | 대용량 디스크 |
| Direct (D) | 없음 | 비보장 | 최소 오버헤드 | AEAD 모드 전용 |
저널링 메커니즘
dm-integrity의 저널은 데이터와 무결성 태그를 원자적(Atomic)으로 기록하여 crash-safety를 보장합니다. 저널은 순환 버퍼(circular buffer)로 구현되며, commit 단위로 데이터+태그 쌍을 기록합니다. Bitmap 모드에서는 저널 대신 비트맵으로 dirty 블록을 추적하며, crash 후 복구 시 dirty 비트가 설정된 블록만 재검증합니다.
/* drivers/md/dm-integrity.c - 저널 엔트리 구조 */
struct journal_entry {
union {
struct {
__le64 sector; /* 대상 섹터 번호 */
__le32 data_csum; /* 데이터 체크섬 */
__le32 tag_csum; /* 태그 체크섬 */
} s;
__le64 commit_id; /* 커밋 ID */
} u;
};
--journal-watermark 옵션으로 저널 flush 임계값을 설정할 수 있습니다.
저널이 가득 차면 쓰기가 차단되므로, 워크로드에 맞는 적절한 크기 설정이 중요합니다.
dm-integrity 설정
dm-integrity는 integritysetup 도구로 설정합니다.
cryptsetup 패키지에 포함되어 있으며, 포맷 후 활성화하는 2단계로 진행합니다.
# 1. dm-integrity 포맷 (SHA-256 해시, 저널 모드)
$ integritysetup format /dev/sdb1 \
--integrity sha256 \
--tag-size 32 \
--sector-size 4096 \
--journal-size 64M
# 2. dm-integrity 디바이스 활성화
$ integritysetup open /dev/sdb1 integrity_disk \
--integrity sha256
# 3. 파일시스템 생성 및 마운트
$ mkfs.ext4 /dev/mapper/integrity_disk
$ mount /dev/mapper/integrity_disk /mnt/secure
# 4. Bitmap 모드로 설정 (성능 우선)
$ integritysetup format /dev/sdb1 \
--integrity sha256 \
--integrity-bitmap-mode \
--bitmap-sectors-per-bit 65536
$ integritysetup open /dev/sdb1 integrity_bitmap \
--integrity sha256 \
--integrity-bitmap-mode
| 옵션 | 설명 | 기본값 |
|---|---|---|
--integrity | 해시(Hash) 알고리즘 | sha256 |
--tag-size | 무결성 태그 크기 (바이트) | 알고리즘 출력 크기 |
--sector-size | 섹터 크기 | 512 |
--journal-size | 저널 크기 | 자동 계산 |
--journal-watermark | 저널 flush 임계값 (%) | 50% |
--journal-commit-time | 저널 commit 주기 (ms) | 10000 |
--integrity-bitmap-mode | 비트맵 모드 사용 | 비활성 |
dm-integrity 커널 내부 구현
dm-integrity의 커널 구현은 drivers/md/dm-integrity.c에 있으며,
약 4,500줄에 달하는 복잡한 코드입니다. 핵심 동작은 bio를 분할하여
데이터와 무결성 태그를 동시에 처리하는 것입니다.
/* drivers/md/dm-integrity.c - map 함수 */
static int integrity_map(struct dm_target *ti, struct bio *bio)
{
struct dm_integrity_c *ic = ti->private;
struct dm_integrity_io *dio;
dio = dm_per_bio_data(bio, ti->per_io_data_size);
dio->ic = ic;
dio->bi_sector = bio->bi_iter.bi_sector;
dio->bi_integrity = bio_integrity(bio);
if (bio_data_dir(bio) == WRITE) {
if (ic->mode == 'J') {
/* Journal 모드: 저널에 먼저 기록 */
integrity_journal_write(ic, dio);
} else if (ic->mode == 'B') {
/* Bitmap 모드: dirty 비트 설정 */
integrity_bitmap_write(ic, dio);
}
/* 무결성 태그 계산 및 저장 */
integrity_metadata_write(ic, dio);
} else {
/* READ: 데이터 읽기 후 태그 검증 */
integrity_metadata_read(ic, dio);
}
/* bio를 데이터 디바이스로 remap */
bio_set_dev(bio, ic->dev->bdev);
bio->bi_iter.bi_sector = integrity_data_sector(ic, dio->bi_sector);
return DM_MAPIO_REMAPPED;
}
/* 무결성 태그 검증 (읽기 시) */
static int integrity_check_tag(struct dm_integrity_c *ic,
u8 *data, u8 *stored_tag,
sector_t sector)
{
u8 computed_tag[MAX_TAG_SIZE];
int r;
/* 해시 계산 */
r = crypto_shash_digest(ic->internal_hash_desc,
data, ic->sectors_per_block << SECTOR_SHIFT,
computed_tag);
if (r)
return r;
/* 저장된 태그와 비교 */
if (memcmp(computed_tag, stored_tag, ic->tag_size)) {
DMERR("integrity checksum failed at sector %llu",
(unsigned long long)sector);
return -EILSEQ;
}
return 0;
}
dm-integrity의 I/O 경로에서 주의할 점은 메타데이터 I/O입니다.
데이터와 태그가 디스크 상에서 인터리빙되어 있기 때문에,
연속적인 데이터 I/O가 비연속적인 디스크 I/O로 변환될 수 있습니다.
이로 인해 HDD에서는 성능 저하가 심각할 수 있으며, SSD에서는 상대적으로 영향이 적습니다.
별도의 메타 디바이스(--data-device)를 사용하면 이 문제를 완화할 수 있습니다.
dm-integrity의 내부 동작을 더 깊이 살펴보면, 데이터 섹터와 태그 영역의 매핑이 핵심입니다.
논리 섹터 번호를 물리 섹터 번호로 변환할 때, 태그 영역의 크기를 고려하여 오프셋(Offset)을 계산합니다.
이 변환은 get_data_sector() 함수에서 수행됩니다.
/* drivers/md/dm-integrity.c - 섹터 변환 */
static sector_t get_data_sector(struct dm_integrity_c *ic,
area_t area, sector_t offset)
{
sector_t result;
/* 데이터 영역과 태그 영역이 인터리빙됨
* area = 논리 섹터 / interleave_sectors
* offset = 논리 섹터 % interleave_sectors */
result = area * (ic->interleave_sectors + ic->tag_area_sectors);
result += ic->initial_sectors; /* 슈퍼블록 + 저널 공간 */
result += offset;
return result;
}
/* 태그 읽기/쓰기 - 메타데이터 I/O */
static void rw_tag(struct dm_integrity_c *ic,
unsigned int tag_offset,
u8 *tag, unsigned int tag_size,
int op)
{
sector_t tag_sector;
unsigned int tag_sector_offset;
/* 태그의 디스크 위치 계산 */
tag_sector = tag_offset / (ic->tag_size * ic->journal_section_entries);
tag_sector_offset = tag_offset % (ic->tag_size * ic->journal_section_entries);
if (op == TAG_READ)
dm_bufio_read(ic->tag_bufio, tag_sector, ...);
else
dm_bufio_write_dirty(ic->tag_bufio, tag_sector, ...);
}
--data-device)를 사용하면
데이터와 태그를 물리적으로 분리하여 이 문제를 완화할 수 있습니다.
# 별도 메타 디바이스로 dm-integrity 설정 (성능 최적화)
$ integritysetup format --data-device /dev/nvme0n1p1 /dev/nvme1n1p1 --integrity sha256 --sector-size 4096
# 결과: 데이터는 nvme0n1p1, 태그는 nvme1n1p1에 저장
# 두 NVMe를 병렬로 사용하여 성능 극대화
| dm-integrity 커널 함수 | 역할 | 호출 시점 |
|---|---|---|
integrity_ctr() | target 생성, 슈퍼블록(Superblock) 로드 | 테이블 로드 |
integrity_dtr() | target 해제, 저널 flush | 디바이스 제거 |
integrity_map() | bio remap + 태그 처리 | 매 I/O |
integrity_end_io() | 읽기 태그 검증 | 읽기 완료 |
do_journal_write() | 저널 -> 실데이터 플러시(Flush) | 저널 watermark |
integrity_recalc() | 기존 데이터 태그 재계산 | recalculate 모드 |
integrity_bitmap_flush() | 비트맵 dirty 플러시 | bitmap 모드 |
dm-crypt + dm-integrity 결합
dm-crypt와 dm-integrity를 결합하면 인증 암호화(AEAD)를 구현할 수 있습니다. AES-GCM 또는 ChaCha20-Poly1305 같은 AEAD 알고리즘을 사용하여 암호화와 무결성 검증을 단일 연산으로 수행합니다. 이 결합 모드에서 dm-crypt는 암호화 담당, dm-integrity는 인증 태그 저장 담당입니다.
# AEAD 모드 LUKS2 볼륨 생성 (AES-GCM)
$ cryptsetup luksFormat --type luks2 \
--cipher aes-gcm-random \
--integrity aead \
--sector-size 4096 \
--key-size 256 \
/dev/sdb1
# HMAC 무결성 (비 AEAD, 별도 해시)
$ cryptsetup luksFormat --type luks2 \
--cipher aes-xts-plain64 \
--integrity hmac-sha256 \
--sector-size 4096 \
--key-size 512 \
/dev/sdb1
# dm-integrity 디바이스가 자동 생성됨
$ dmsetup ls
encrypted (254:1)
encrypted_dif (254:0) # dm-integrity 레이어
# 상태 확인
$ cryptsetup status encrypted
type: LUKS2
cipher: aes-gcm-random
keysize: 256 bits
integrity: aead
integrity keysize: 0 bits # AEAD는 별도 키 불필요
| 모드 | 암호화 | 무결성 | 태그 크기 | 성능 오버헤드 |
|---|---|---|---|---|
| AES-GCM (AEAD) | AES-GCM | GCM 내장 | 16B | ~15% |
| AES-XTS + HMAC | AES-XTS | HMAC-SHA256 | 32B | ~25% |
| ChaCha20-Poly1305 | ChaCha20 | Poly1305 | 16B | ~12% |
| AES-XTS 단독 | AES-XTS | 없음 | 0B | ~8% |
no-journal 모드로 동작합니다.
정전 시 데이터+태그 불일치로 해당 섹터가 읽기 불가능해질 수 있습니다.
UPS 또는 배터리 백업이 없는 환경에서는 저널 모드가 권장됩니다.
저널 Write-Ahead 로깅 상세
dm-integrity의 저널은 Write-Ahead Logging(WAL) 패턴을 따릅니다. 데이터와 무결성 태그를 실제 위치에 쓰기 전에 저널 영역에 먼저 기록함으로써 원자성(Atomicity)을 보장합니다. 정전 시 저널을 재생(replay)하여 일관성을 복구합니다.
/* drivers/md/dm-integrity.c - 저널 쓰기 핵심 경로 */
/* 저널 섹션 헤더 */
struct journal_section_header {
__le64 commit_id; /* 트랜잭션 식별자 */
__le64 commit_seq; /* 순서 번호 */
};
/* 저널 커밋 처리 */
static void integrity_commit(struct dm_integrity_c *ic)
{
struct journal_section_header *header;
unsigned int section;
section = ic->free_section;
header = journal_section_header(ic, section);
/* commit_id 기록 (홀수 = 커밋 완료 표시) */
header->commit_id = cpu_to_le64(ic->commit_id);
header->commit_seq = cpu_to_le64(ic->commit_seq);
/* 저널 MAC 계산 (선택적 보호) */
if (ic->journal_mac) {
crypto_shash_digest(ic->journal_mac_desc,
(u8 *)header,
ic->journal_section_size,
header->mac);
}
/* 저널 섹션을 디스크에 동기 쓰기 */
write_journal_section(ic, section);
flush_journal(ic);
ic->commit_seq++;
}
/* 저널 -> 실데이터 영역 플러시 */
static void do_journal_write(struct dm_integrity_c *ic)
{
unsigned int section, entry;
/* committed 섹션을 순서대로 처리 */
while (ic->flush_section != ic->free_section) {
section = ic->flush_section;
/* 섹션 내 각 엔트리 처리 */
for (entry = 0; entry < ic->journal_section_entries; entry++) {
struct journal_entry *je;
sector_t sector;
u8 *data, *tag;
je = journal_entry_get(ic, section, entry);
sector = le64_to_cpu(je->u.s.sector);
/* 데이터를 실제 위치에 쓰기 */
data = journal_data_get(ic, section, entry);
integrity_write_data(ic, sector, data);
/* 태그를 태그 영역에 쓰기 */
tag = journal_tag_get(ic, section, entry);
rw_tag(ic, sector, tag, ic->tag_size, TAG_WRITE);
}
/* 섹션 플러시 완료, flush_head 전진 */
ic->flush_section = (section + 1) % ic->journal_sections;
}
}
--journal-integrity 옵션으로 저널 자체의 무결성도 보호할 수 있습니다.
예: integritysetup format --journal-integrity hmac-sha256
이 옵션은 저널 섹션마다 HMAC을 추가하여 저널 변조를 탐지합니다.
--journal-crypt 옵션으로 저널을 암호화하여 기밀성도 제공 가능합니다.
Bitmap 모드 vs Journal 모드 비교
dm-integrity는 Journal 모드와 Bitmap 모드 두 가지 crash-safety 메커니즘을 제공합니다. Journal 모드는 완전한 crash-safety를 보장하지만 쓰기 증폭(Write Amplification)이 발생하며, Bitmap 모드는 dirty 블록만 추적하여 성능을 개선하지만 crash 후 재검증이 필요합니다.
/* drivers/md/dm-integrity.c - Bitmap 모드 핵심 */
/* 비트맵 dirty 비트 설정 */
static void integrity_bitmap_mark_dirty(struct dm_integrity_c *ic,
sector_t sector,
sector_t n_sectors)
{
unsigned long bit;
unsigned long end_bit;
/* 섹터를 비트맵 인덱스로 변환 */
bit = sector / ic->sectors_per_bitmap_bit;
end_bit = (sector + n_sectors - 1) / ic->sectors_per_bitmap_bit;
/* dirty 비트 설정 (원자적) */
while (bit <= end_bit) {
if (!test_and_set_bit(bit, ic->dirty_bitmap))
ic->dirty_bitmap_count++;
bit++;
}
}
/* Crash 후 비트맵 기반 재검증 */
static void integrity_bitmap_recalculate(struct dm_integrity_c *ic)
{
unsigned long bit;
/* dirty 비트가 설정된 블록만 재검증 */
for (bit = 0; bit < ic->bitmap_size; bit++) {
if (test_bit(bit, ic->dirty_bitmap)) {
sector_t start = bit * ic->sectors_per_bitmap_bit;
sector_t count = ic->sectors_per_bitmap_bit;
/* 데이터를 읽고 태그를 재계산 */
integrity_recalc_range(ic, start, count);
/* 재검증 완료 후 dirty 비트 해제 */
clear_bit(bit, ic->dirty_bitmap);
}
}
}
| 비교 항목 | Journal 모드 | Bitmap 모드 | No-journal (Direct) |
|---|---|---|---|
| 쓰기 증폭 | 2x (저널 + 실데이터) | 1x + 비트맵 I/O | 1x |
| Crash Safety | 완전 보장 | dirty 블록 재검증 | 비보장 |
| 복구 시간 | 수 초 (저널 replay) | 수 분~시간 | 없음 |
| 메모리 사용 | 저널 크기만큼 | 비트맵 크기 (작음) | 최소 |
| 순차 쓰기 처리량(Throughput) | 기준 대비 ~50% | 기준 대비 ~80% | 기준 대비 ~90% |
| 랜덤 쓰기 IOPS | 기준 대비 ~40% | 기준 대비 ~70% | 기준 대비 ~85% |
| 주요 용도 | 단독 사용, 데이터 보호 | 대용량 디스크 | AEAD 결합 전용 |
--bitmap-sectors-per-bit 값을 크게 설정하면 비트맵 I/O가 줄지만
crash 후 재검증 범위가 넓어집니다. 기본값 65536은 각 비트가 약 32MB 범위를 커버합니다.
Inline 모드 — 커널 6.11+
커널 6.11에서 dm-integrity에 Inline 모드(--integrity-inline / I)가 추가되었습니다. 기존 Journal·Bitmap 모드는 데이터와 별도의 메타데이터 영역에 태그를 저장했기 때문에 "쓰기 1회 = 디바이스 I/O 2회"의 원천적 증폭이 존재했습니다. Inline 모드는 디바이스가 하드웨어 수준의 섹터별 보호 정보(PI/DIF/DIX, T10-PI)를 지원할 때, 블록 계층이 제공하는 섹터 부가 필드에 HMAC 태그를 직접 기록합니다. 6.12에서는 inline 모드에서도 재계산(recalculate)이 지원되어, 디바이스 포맷을 바꾸지 않고 알고리즘 교체가 가능해졌습니다.
| 모드 | 태그 저장 위치 | 쓰기 증폭 | crash-safety | 요구 조건 |
|---|---|---|---|---|
| Journal(J) | 저널 영역 → 이후 메타데이터 영역 | 2x (저널 + 데이터) | 완전 보장 | 없음 |
| Bitmap(B) | 별도 메타데이터 영역 | 1.0~1.2x | 재검증 필요 | 없음 |
| Inline(I) | 하드웨어 PI/DIF 섹터 필드 | 1.0x | 디바이스 의존 | T10-PI 지원 드라이브 |
| None(D) | 없음 — AEAD 태그만 | 1.0x | 불가 | dm-crypt AEAD 전용 |
# 6.11+: inline 모드로 통합 — PI 지원 NVMe에서 쓰기 증폭 제거
$ integritysetup format /dev/nvme0n1 \
--integrity hmac-sha256 \
--integrity-inline \
--tag-size 8
$ integritysetup open /dev/nvme0n1 data --integrity hmac-sha256
# 디바이스 포맷(tag를 섹터 메타데이터로 수납) 확인
$ integritysetup dump /dev/nvme0n1
# mode: I ← Inline
# tag_size: 8 ← 섹터당 PI 필드에 저장
# 6.12+: inline 모드의 재계산 — 알고리즘 교체 시 데이터 유지
$ integritysetup format /dev/nvme0n1 \
--integrity hmac-sha512 --integrity-inline \
--integrity-recalculate
커널 내부 경로 요약:
struct superblock.flags에SB_FLAG_INLINE(0x20)이 추가되었습니다.- 블록 계층의
bi_integrity경로(T10-PI)와 공유하여, bio 제출 시bio_integrity_alloc()으로 integrity payload를 준비하고 드라이버가 NVMe PRACT/PRCHK 또는 SCSI PI 필드로 전달합니다. - HMAC/CRC 계산은 여전히 dm-integrity가 수행하지만, 저널 라운드가 사라져 write path가 "한 번의 쓰기 + in-band tag"로 단축됩니다.
- Inline 모드에서는 저널 섹션이 존재하지 않으므로 crash 후 unclean shutdown 시 드라이브 자체의 PI 메타데이터가 원자적 페어링을 보장해야 합니다. 비정상 전원 단절이 빈번한 환경에서는 Journal 모드를 유지하는 편이 안전합니다.
Inline 모드 덕분에 dm-crypt + dm-integrity(AEAD) 스택이 T10-PI 대응 기업용 NVMe에서 단일 I/O 비용으로 동작하게 되어, 저장소 암호화 + 무결성 조합의 실측 IOPS 페널티가 기존 ~40% 대에서 한 자릿수 % 수준으로 감소합니다.
내부 자료 구조 상세
dm-integrity의 커널 구현은 여러 핵심 자료 구조에 의존합니다.
dm_integrity_c는 target 인스턴스의 전체 상태를 관리하며,
dm_integrity_io는 개별 I/O 요청의 컨텍스트(Context)를 추적합니다.
디스크 상의 슈퍼블록 구조와 저널 엔트리 포맷도 중요한 구성 요소입니다.
/* drivers/md/dm-integrity.c - 슈퍼블록 디스크 포맷 */
struct superblock {
__u8 magic[8]; /* "integrt\1" 매직 넘버 */
__u8 version; /* 포맷 버전 (현재 5) */
__s8 log2_interleave_sectors; /* 인터리빙 크기 (log2) */
__le16 integrity_tag_size; /* 태그 크기 (바이트) */
__le32 journal_sections; /* 저널 섹션 수 */
__le64 provided_data_sectors; /* 제공 가능 데이터 섹터 */
__le32 flags; /* SB_FLAG_* */
__u8 log2_sectors_per_block; /* 블록당 섹터 수 (log2) */
__le64 recalc_sector; /* 재계산 진행 위치 */
__u8 pad[4];
__u8 salt[SALT_SIZE]; /* HMAC salt */
};
#define SB_FLAG_HAVE_JOURNAL_MAC 0x1
#define SB_FLAG_RECALCULATING 0x2
#define SB_FLAG_DIRTY_BITMAP 0x4
#define SB_FLAG_FIXED_PADDING 0x8
#define SB_FLAG_FIXED_HMAC 0x10
/* dm_integrity_c 구조체 상세 필드 */
struct dm_integrity_c {
struct dm_dev *dev; /* 데이터 디바이스 */
struct dm_dev *meta_dev; /* 별도 메타 디바이스 (선택) */
struct dm_target *ti;
/* 해시/암호 */
struct crypto_shash *internal_hash; /* 태그 해시 알고리즘 */
struct crypto_shash *journal_mac; /* 저널 MAC 알고리즘 */
struct crypto_skcipher *journal_crypt; /* 저널 암호화 */
/* 디스크 레이아웃 */
unsigned int tag_size; /* 태그 크기 (바이트) */
unsigned int sectors_per_block; /* 블록당 섹터 수 */
__u64 provided_data_sectors; /* 사용 가능 데이터 섹터 */
sector_t initial_sectors; /* SB + 저널 + 패딩 */
sector_t metadata_run; /* 태그 영역 크기 */
__s8 log2_interleave_sectors;
/* 저널 관련 */
unsigned int journal_entries;
unsigned int journal_sections;
unsigned int journal_section_entries;
unsigned int journal_section_sectors;
unsigned int free_section; /* 현재 쓰기 섹션 */
unsigned int flush_section; /* 플러시 대기 섹션 */
__u64 commit_id; /* 현재 커밋 ID */
__u64 commit_seq; /* 커밋 시퀀스 번호 */
/* 비트맵 모드 */
unsigned long *dirty_bitmap; /* dirty 블록 비트맵 */
unsigned long bitmap_size; /* 비트맵 크기 (비트) */
unsigned int sectors_per_bitmap_bit;
/* dm-bufio 캐시 */
struct dm_bufio_client *bufio; /* 태그 블록 캐시 */
struct dm_bufio_client *journal_bufio;
/* 워크큐 */
struct workqueue_struct *commit_wq;
struct workqueue_struct *writer_wq;
struct workqueue_struct *recalc_wq;
/* 성능 카운터 */
enum integrity_mode mode; /* 'J', 'B', 'D' */
bool recalculate; /* 태그 재계산 진행 중 */
atomic64_t number_of_mismatches; /* 불일치 카운터 */
};
/* I/O별 컨텍스트 */
struct dm_integrity_io {
struct dm_integrity_c *ic;
sector_t bi_sector; /* 원래 섹터 번호 */
struct bio_integrity_payload *bi_integrity;
struct completion comp; /* I/O 완료 대기 */
int bi_status;
struct work_struct work; /* 워크큐 처리용 */
unsigned int range_start;
unsigned int range_end;
};
AEAD 통합 상세
AEAD(Authenticated Encryption with Associated Data) 결합 모드에서
dm-crypt는 인증 암호화를 수행하고, dm-integrity는 인증 태그의 저장/조회만 담당합니다.
이 구조에서 dm-integrity는 no-journal(Direct) 모드로 동작하며,
태그 계산을 dm-crypt의 AEAD 알고리즘에 위임합니다.
/* dm-crypt + dm-integrity AEAD 결합 내부 동작 */
/* dm-crypt가 AEAD 모드로 bio를 처리하는 경우:
* 1. dm-crypt가 bio를 가로채 AEAD 암호화 수행
* 2. 암호화 결과: ciphertext + authentication tag (16B for GCM)
* 3. ciphertext는 bio 데이터에, auth tag는 bio_integrity에 저장
* 4. dm-integrity가 bio_integrity에서 tag를 추출하여 디스크에 기록 */
/* drivers/md/dm-crypt.c - AEAD 처리 */
static int crypt_convert_block_aead(
struct crypt_config *cc,
struct convert_context *ctx,
struct aead_request *req,
unsigned int tag_offset)
{
struct bio_integrity_payload *bip = ctx->bio_out->bi_integrity;
u8 *tag;
/* bio_integrity에서 태그 저장 위치 획득 */
tag = bip->bip_buf + tag_offset;
/* AEAD 요청 구성: src=평문, dst=암호문, assocdata=IV+섹터 */
aead_request_set_crypt(req, &src, &dst,
cc->sector_size, /* 평문 길이 */
iv);
aead_request_set_ad(req, cc->integrity_iv_size);
if (bio_data_dir(ctx->bio_out) == WRITE) {
/* 암호화: 암호문 + 인증 태그 생성 */
r = crypto_aead_encrypt(req);
/* tag에 인증 태그가 저장됨 (GCM: 16바이트) */
} else {
/* 복호화: 인증 태그 검증 + 복호화 */
r = crypto_aead_decrypt(req);
/* 태그 불일치 시 -EBADMSG 반환 */
}
return r;
}
/* dm-integrity 측: AEAD 태그 수신/저장 */
/* integrity_map()에서 bio_integrity payload를 통해
* dm-crypt가 생성한 인증 태그를 디스크에 기록
* 읽기 시에는 디스크에서 태그를 읽어 bio_integrity에 채움 */
static void integrity_aead_tag_io(struct dm_integrity_c *ic,
struct dm_integrity_io *dio,
int rw)
{
struct bio_integrity_payload *bip = dio->bi_integrity;
u8 *tag_buf = bip ? bip->bip_buf : NULL;
if (rw == WRITE && tag_buf) {
/* dm-crypt가 생성한 인증 태그를 디스크에 기록 */
rw_tag(ic, dio->bi_sector, tag_buf,
ic->tag_size, TAG_WRITE);
} else if (rw == READ && tag_buf) {
/* 디스크에서 인증 태그를 읽어 bio_integrity에 전달 */
rw_tag(ic, dio->bi_sector, tag_buf,
ic->tag_size, TAG_READ);
}
}
| AEAD 알고리즘 | 키 크기 | 태그 크기 | 특징 |
|---|---|---|---|
| AES-GCM | 128/256비트 | 16바이트 | AES-NI 가속, 널리 지원, nonce 재사용 취약 |
| AES-CCM | 128/256비트 | 16바이트 | 소프트웨어 구현 용이, GCM보다 느림 |
| ChaCha20-Poly1305 | 256비트 | 16바이트 | AES-NI 없는 환경에서 빠름, ARM 최적화 |
| Aegis128 | 128비트 | 16바이트 | AES-NI 환경에서 GCM보다 빠름 (커널 6.0+) |
dm-integrity + LUKS2 연동
LUKS2(Linux Unified Key Setup version 2)는 dm-crypt와 dm-integrity를 통합 관리하는
상위 레벨 인터페이스를 제공합니다. cryptsetup을 사용하면 dm-integrity 레이어가
자동으로 생성되며, 키 관리와 무결성 설정을 단일 명령으로 처리할 수 있습니다.
# LUKS2 + dm-integrity 결합 설정 가이드
## 방법 1: AEAD 모드 (암호화 + 무결성 단일 연산)
$ cryptsetup luksFormat --type luks2 \
--cipher aes-gcm-random \
--integrity aead \
--sector-size 4096 \
--key-size 256 \
/dev/sdb1
## 방법 2: HMAC 모드 (별도 해시, 더 강력한 무결성)
$ cryptsetup luksFormat --type luks2 \
--cipher aes-xts-plain64 \
--integrity hmac-sha256 \
--sector-size 4096 \
--key-size 512 \
/dev/sdb1
# HMAC 모드에서는 키가 2개: 256-bit 암호화 + 256-bit HMAC
# --key-size 512 = AES-XTS(256) + HMAC-SHA256(256)
## 방법 3: Poly1305 (ARM/소프트웨어 환경 최적)
$ cryptsetup luksFormat --type luks2 \
--cipher chacha20,aead \
--integrity poly1305 \
--sector-size 4096 \
--key-size 256 \
/dev/sdb1
## 볼륨 열기 및 마운트
$ cryptsetup open /dev/sdb1 secure_vol
$ mkfs.ext4 /dev/mapper/secure_vol
$ mount /dev/mapper/secure_vol /mnt/secure
## LUKS2 헤더에서 integrity 정보 확인
$ cryptsetup luksDump /dev/sdb1
# ...
# Segments:
# 0: crypt
# cipher: aes-xts-plain64
# integrity: hmac(sha256)
# sector: 4096 [bytes]
# ...
# Integrity:
# type: LUKS2_INTEGRITY
# journal_size: 67108864
# interleave_sectors: 32768
## dm-integrity 하위 디바이스 상태 확인
$ dmsetup ls
secure_vol (254:1)
secure_vol_dif (254:0) # dm-integrity 레이어
$ dmsetup status secure_vol_dif
# 0 4194304 integrity 0 0
## LUKS2 + integrity 볼륨의 크기 오버헤드 확인
$ integritysetup dump /dev/sdb1
# Info for integrity device /dev/sdb1
# superblock_version: 5
# log2_interleave_sectors: 15
# integrity_tag_size: 32
# journal_sections: 88
# provided_data_sectors: 4063232
# sector_size: 4096
## 성능 비교: 무결성 없음 vs AEAD vs HMAC
# AES-XTS만 (무결성 없음)
$ cryptsetup luksFormat --type luks2 --cipher aes-xts-plain64 \
--key-size 512 /dev/sdb1
# fio 순차 쓰기: ~1.8 GB/s
# AES-GCM AEAD
# fio 순차 쓰기: ~1.5 GB/s (약 17% 오버헤드)
# AES-XTS + HMAC-SHA256
# fio 순차 쓰기: ~1.2 GB/s (약 33% 오버헤드)
성능 최적화
dm-integrity의 성능은 저널 설정, 섹터 크기, 인터리빙 파라미터에 크게 좌우됩니다. 워크로드 특성에 맞는 적절한 튜닝이 필수적입니다.
# dm-integrity 성능 튜닝 가이드
## 1. journal_watermark 최적화
# 기본값 50%: 저널이 50% 차면 플러시 시작
# 높은 값: 배치 플러시로 처리량 증가, 지연시간 증가
# 낮은 값: 즉시 플러시, 지연시간 감소, 처리량 감소
$ integritysetup format /dev/sdb1 \
--integrity sha256 \
--journal-watermark 75 \
--journal-commit-time 5000
# 75%에서 플러시, 또는 5초마다 강제 커밋
## 2. journal_commit_time 조정
# 기본값 10000ms (10초)
# 순차 쓰기 워크로드: 30000ms (30초) - 배치 효과 극대화
# OLTP 워크로드: 1000ms (1초) - 지연시간 최소화
$ integritysetup format /dev/sdb1 \
--integrity sha256 \
--journal-commit-time 1000
## 3. 저널 크기 최적화
# 큰 저널: 더 많은 쓰기를 배치 처리, 메모리 사용 증가
# 작은 저널: 빈번한 플러시, 쓰기 차단 가능
$ integritysetup format /dev/sdb1 \
--integrity sha256 \
--journal-size 256M
# 고부하 쓰기 워크로드에서 256MB 저널 권장
## 4. 섹터 크기 조정
# 4096B 섹터: 태그 오버헤드 비율 감소 (32B/4096B = 0.78%)
# 512B 섹터: 태그 오버헤드 비율 증가 (32B/512B = 6.25%)
$ integritysetup format /dev/sdb1 \
--integrity sha256 \
--sector-size 4096
## 5. 별도 메타 디바이스 사용 (최고 성능)
# 데이터와 태그를 물리적으로 분리하여 병렬 I/O
$ integritysetup format \
--data-device /dev/nvme0n1p1 \
/dev/nvme1n1p1 \
--integrity sha256 \
--sector-size 4096
# 데이터: NVMe 0, 태그: NVMe 1 (병렬 접근)
## 6. Bitmap 모드로 쓰기 성능 개선
$ integritysetup format /dev/sdb1 \
--integrity sha256 \
--integrity-bitmap-mode \
--bitmap-sectors-per-bit 65536 \
--bitmap-flush-time 5000
## 7. 벤치마크 실행
# 순차 쓰기
$ fio --name=seq_write --filename=/dev/mapper/integrity_disk \
--rw=write --bs=128k --numjobs=4 --iodepth=16 \
--size=4G --direct=1 --group_reporting
# 랜덤 쓰기 (저널 모드 병목 테스트)
$ fio --name=rand_write --filename=/dev/mapper/integrity_disk \
--rw=randwrite --bs=4k --numjobs=4 --iodepth=32 \
--size=1G --direct=1 --group_reporting
# 혼합 읽기/쓰기
$ fio --name=mixed --filename=/dev/mapper/integrity_disk \
--rw=randrw --rwmixread=70 --bs=4k --numjobs=4 \
--iodepth=32 --size=1G --direct=1 --group_reporting
| 튜닝 파라미터 | 기본값 | 순차 쓰기 최적 | 랜덤 쓰기 최적 | 영향 |
|---|---|---|---|---|
journal-watermark | 50% | 80% | 30% | 플러시 빈도 조절 |
journal-commit-time | 10000ms | 30000ms | 1000ms | 커밋 주기 |
journal-size | 자동 | 256MB | 64MB | 배치 크기 |
sector-size | 512B | 4096B | 4096B | 태그 오버헤드 비율 |
bitmap-sectors-per-bit | 65536 | 131072 | 32768 | 재검증 범위 |
iostat -x 1로 디바이스 사용률을 확인하고,
%util이 100%에 근접하면 저널 크기 확대 또는 Bitmap 모드 전환을 고려하세요.
HDD에서는 인터리빙으로 인한 seek 오버헤드가 지배적이므로
--data-device 옵션으로 메타 디바이스를 분리하는 것이 가장 효과적입니다.
디버깅(Debugging) 및 모니터링
dm-integrity 문제 진단에는 dmsetup, integritysetup,
커널 로그, 그리고 성능 모니터링 도구를 활용합니다.
# 1. dm-integrity 상태 확인
$ dmsetup status integrity_disk
# 0 4194304 integrity 0 0
# 형식: start_sector num_sectors integrity mismatch_count provision_mode
# mismatch_count가 0이 아니면 무결성 오류 발생
# 2. integritysetup dump - 디스크 레이아웃 상세
$ integritysetup dump /dev/sdb1
# Info for integrity device /dev/sdb1
# superblock_version 5
# log2_interleave_sectors 15
# integrity_tag_size 32
# journal_sections 88
# provided_data_sectors 4063232
# sector_size 4096
# flags FIXED_HMAC
# 3. 커널 로그 확인
$ dmesg | grep -i integrity
# device-mapper: integrity: dm-0: started in journal mode
# device-mapper: integrity: dm-0: initialized with tag size 32
# device-mapper: integrity: dm-0: checksum failed at sector 12345
# 4. 무결성 오류 카운터 실시간 모니터링
$ watch -n 1 'dmsetup status integrity_disk | awk "{print \"mismatches:\", \$5}"'
# 5. I/O 성능 모니터링
# 실제 디바이스와 DM 디바이스의 I/O 비교
$ iostat -x 1 /dev/sdb /dev/dm-0
# sdb (물리)와 dm-0 (dm-integrity)의 처리량 차이 = 오버헤드
# 6. dmsetup table로 현재 설정 확인
$ dmsetup table integrity_disk
# 0 4063232 integrity /dev/sdb1 0 32 J 6 journal_sectors:180224 ...
# 7. 저널 상태 확인
# 저널 사용률 추정 (쓰기 지연과 상관)
$ dmsetup message integrity_disk 0 stats
# (커널 버전에 따라 지원 여부 다름)
# 8. ftrace로 dm-integrity I/O 경로 추적
$ echo function_graph | sudo tee /sys/kernel/tracing/current_tracer
$ echo integrity_map | sudo tee /sys/kernel/tracing/set_graph_function
$ echo 1 | sudo tee /sys/kernel/tracing/tracing_on
# ... I/O 발생 ...
$ cat /sys/kernel/tracing/trace
# integrity_map -> integrity_journal_write -> do_journal_write
# 9. 강제 무결성 검증 (전체 디스크)
# 모든 블록을 읽어 태그 검증
$ dd if=/dev/mapper/integrity_disk of=/dev/null bs=1M status=progress
# -EIO 발생 시 해당 블록에 무결성 오류 존재
# 10. 재계산 모드 활성화 (기존 데이터에 태그 추가)
$ integritysetup open /dev/sdb1 integrity_disk \
--integrity sha256 --integrity-recalculate
# 백그라운드에서 모든 블록의 태그를 재계산
# 진행 상황: dmesg에서 확인
| 증상 | 원인 | 해결 방법 |
|---|---|---|
| 읽기 시 -EIO (EILSEQ) | 데이터-태그 불일치 | 해당 블록 재기록, 백업에서 복구 |
| 쓰기 속도 급감 | 저널 full, 플러시 차단 | journal-size 증가, watermark 조정 |
| 부팅 시 오래 걸림 | bitmap 모드 재검증 | sectors-per-bit 증가, 또는 journal 모드 |
| recalculate 완료 안됨 | 대용량 디스크 재계산 | 정상 동작, 백그라운드 진행 대기 |
| mismatch_count 증가 | 하드웨어 결함 또는 AEAD 미커밋 | SMART 확인, UPS 사용, 백업 |
| 메타 디바이스 오류 | 태그 디바이스 장애 | 메타 디바이스 교체, 재포맷 |
에러 복구 메커니즘
dm-integrity의 에러 복구는 모드에 따라 다르게 동작합니다. Journal 모드는 crash-safety가 보장되므로 저널 replay로 복구되지만, Bitmap 모드와 No-journal 모드에서는 데이터 손실이 발생할 수 있습니다.
/* drivers/md/dm-integrity.c - 저널 replay 구현 */
static void replay_journal(struct dm_integrity_c *ic)
{
unsigned int section;
__u64 last_commit_id = 0;
/* 모든 저널 섹션을 스캔 */
for (section = 0; section < ic->journal_sections; section++) {
struct journal_section_header *header;
header = journal_section_header(ic, section);
/* commit_id 유효성 검증 */
if (le64_to_cpu(header->commit_id) != ic->commit_id)
continue; /* 미완료 트랜잭션: 건너뜀 */
/* journal MAC 검증 (설정된 경우) */
if (ic->journal_mac) {
r = verify_journal_mac(ic, section);
if (r) {
DMWARN("journal MAC mismatch in section %u",
section);
continue; /* 변조된 저널 엔트리 */
}
}
/* 유효한 엔트리를 실제 위치에 replay */
for (entry = 0; entry < ic->journal_section_entries; entry++) {
struct journal_entry *je;
je = journal_entry_get(ic, section, entry);
if (journal_entry_is_unused(je))
break;
/* 데이터를 실제 위치에 쓰기 */
write_journal_entry_to_disk(ic, je, section, entry);
}
}
/* commit_id 증가 (다음 사용 준비) */
ic->commit_id++;
write_superblock(ic);
DMINFO("journal replay completed, %u sections replayed",
replayed_count);
}
/* recalculate 모드 - 백그라운드 태그 재계산 */
static void integrity_recalc(struct work_struct *work)
{
struct dm_integrity_c *ic =
container_of(work, struct dm_integrity_c, recalc_work);
sector_t sector = ic->sb->recalc_sector;
while (sector < ic->provided_data_sectors) {
u8 data_buf[PAGE_SIZE];
u8 tag[MAX_TAG_SIZE];
/* 데이터 블록 읽기 */
integrity_read_data(ic, sector, data_buf);
/* 해시 태그 계산 */
crypto_shash_digest(ic->internal_hash_desc,
data_buf, ic->sectors_per_block << SECTOR_SHIFT,
tag);
/* 태그 저장 */
rw_tag(ic, sector, tag, ic->tag_size, TAG_WRITE);
/* 진행 상황 슈퍼블록에 기록 (체크포인트) */
if (!(sector % RECALC_CHECKPOINT_INTERVAL)) {
ic->sb->recalc_sector = cpu_to_le64(sector);
write_superblock(ic);
}
sector += ic->sectors_per_block;
cond_resched(); /* 다른 작업에 양보 */
}
/* 재계산 완료 */
ic->sb->flags &= ~cpu_to_le32(SB_FLAG_RECALCULATING);
write_superblock(ic);
DMINFO("integrity recalculation completed");
}
integrity-recalculate 옵션으로 전체 디스크의 태그를 재계산할 수도 있지만,
이는 기존 태그를 모두 덮어쓰므로 변조 탐지 기능이 일시적으로 무효화(Invalidation)됩니다.
dm-flakey / dm-dust
dm-flakey와 dm-dust는 테스트 및 결함 주입(fault injection)용 Device Mapper target입니다. 파일시스템(Filesystem)이나 스토리지 스택의 에러 처리 경로를 테스트하는 데 사용됩니다.
/* dm-flakey: 주기적으로 I/O 에러를 발생시킴 */
# 10초 정상 동작 후 5초간 모든 I/O에 에러 반환
$ echo "0 $(blockdev --getsz /dev/sdb1) flakey /dev/sdb1 0 10 5" | \
dmsetup create flakey_disk
# 옵션: 쓰기만 실패, 읽기는 정상
$ echo "0 $(blockdev --getsz /dev/sdb1) flakey /dev/sdb1 0 10 5 \
1 drop_writes" | dmsetup create flakey_write
# dm-flakey 커널 구현 (간략화)
static int flakey_map(struct dm_target *ti, struct bio *bio)
{
struct flakey_c *fc = ti->private;
unsigned elapsed = jiffies - fc->start_time;
if (elapsed % (fc->up_interval + fc->down_interval)
>= fc->up_interval) {
/* down 구간: 에러 반환 또는 데이터 변조 */
if (fc->drop_writes && bio_data_dir(bio) == WRITE) {
bio_endio(bio); /* 쓰기 무시 */
return DM_MAPIO_SUBMITTED;
}
bio->bi_status = BLK_STS_IOERR;
bio_endio(bio);
return DM_MAPIO_SUBMITTED;
}
/* up 구간: 정상 통과 */
flakey_map_bio(ti, bio);
return DM_MAPIO_REMAPPED;
}
/* dm-dust: 특정 블록에 읽기 에러를 주입 */
# dm-dust 디바이스 생성
$ echo "0 $(blockdev --getsz /dev/sdb1) dust /dev/sdb1 0 4096" | \
dmsetup create dusty_disk
# 특정 블록에 bad block 마킹
$ dmsetup message dusty_disk 0 addbadblock 100
$ dmsetup message dusty_disk 0 addbadblock 200
# bad block 활성화
$ dmsetup message dusty_disk 0 enable
# 블록 100, 200 읽기 시 -EIO 반환
# 파일시스템의 에러 핸들링 로직 테스트에 활용
# bad block 제거
$ dmsetup message dusty_disk 0 removebadblock 100
최신 커널 변경사항 (6.12 ~ 6.14+)
커널 6.12에서 dm-integrity의 Inline 모드가 한층 완성되었고, 내부 자료 구조 검증과 MAC 관련 안정성 패치(Patch)가 추가되었습니다. 기존 문서의 Inline 모드 (6.11+) 섹션에서 6.11 기반을 설명했으므로, 여기서는 그 이후 변경사항을 다룹니다.
6.12: Inline 모드 재계산(recalculate) 지원
커널 6.12부터: dm-integrity Inline 모드(I)에서 재계산(recalculate) 기능이 지원됩니다. 기존에는 Journal/Bitmap 모드에서만 가능하던 온라인 재계산을 Inline 모드에서도 수행할 수 있습니다.
재계산이란 dm-integrity 디바이스를 포맷하지 않고도 기존 데이터에 대한 무결성 태그를 백그라운드에서 재생성하는 기능입니다.
무결성 알고리즘을 교체(예: crc32c → hmac-sha256)하거나, 태그가 없는 기존 디바이스를 무결성 보호 디바이스로 전환할 때 사용합니다.
Inline 모드에서 재계산이 지원됨으로써 T10-PI 지원 NVMe 디바이스에서도 운영 중단 없이 무결성 알고리즘 마이그레이션이 가능해졌습니다.
# 6.12+: Inline 모드에서 재계산 활성화
# T10-PI 지원 NVMe에 crc32c로 포맷하고 재계산 활성화
$ integritysetup format /dev/nvme0n1 \
--integrity crc32c \
--integrity-inline \
--integrity-recalculate
# 재계산 진행 상황 모니터링
$ integritysetup status /dev/mapper/data
# mode: I
# recalculate: in progress
# integrity: crc32c
# 재계산 완료 후 무결성 검증 가능 상태 확인
$ dmsetup status data
# 0 ...: integrity 0 0 0 0 0
# (수정 섹터 수: 0 = 재계산 완료)
6.12: MAC 크기 및 해시 소화 크기 검증 강화
커널 6.12부터: dm-integrity 초기화 시 MAC(메시지 인증 코드, Message Authentication Code) 키 크기가 HASH_MAX_DIGESTSIZE를 초과하지 않도록 경계 검사가 추가되었습니다. 이로써 잘못 구성된 HMAC 알고리즘 조합에서 발생하던 잠재적 버퍼 경계 문제가 선제적으로 방어됩니다.
/* dm-integrity.c — 6.12 MAC 크기 검증 추가 (개념 요약) */
if (ic->tag_size > HASH_MAX_DIGESTSIZE) {
ti->error = "Tag size too large";
return -EINVAL;
}
6.12: IPE LSM — dm-verity와 연계한 무결성 정책 생태계 완성
커널 6.12에서 IPE(무결성 정책 강제, Integrity Policy Enforcement) LSM이 메인라인에 병합되었습니다.
IPE는 dm-verity와 직접 연동하지만, dm-integrity 기반 무결성도 정책 체계에서 고려됩니다.
dm-integrity + dm-crypt AEAD 스택으로 보호된 블록 디바이스 위의 파일시스템은
IPE 정책에서 dm_verity=YES 유사한 방식으로 나중 버전에서 참조될 기반이 마련되었습니다.
현재는 dm-verity 연동이 주요 경로이지만 dm-integrity 단독 운용 환경에서도 IMA/EVM와 결합하여 유사한 보호를 구현할 수 있습니다.
6.14: dm-crypt + dm-integrity 결합 모드 버그 수정
커널 6.14부터: dm-crypt와 dm-integrity가 AEAD 결합 모드로 운영될 때 무결성 시드(integrity seed) 초기화 로직의 결함이 수정되었습니다. 또한 atomic 플래그의 초기화 순서와 bio 이터레이터(iterator) 완전 초기화 문제가 함께 패치되었습니다. 이 수정은 dm-crypt 사이드에서 이루어졌지만 dm-integrity의 AEAD 경로를 통해 데이터 신뢰성에도 영향을 미칩니다.
관련 문서
- dm-verity — Merkle Tree 기반 읽기 전용 블록 검증, Android Verified Boot
- dm-crypt — 블록 레벨 투명 암호화, LUKS, AES-XTS, 성능 최적화
- Device Mapper / LVM — DM 프레임워크 기본, dm-linear, dm-thin, LVM2
- 블록 I/O — 블록 레이어 아키텍처, bio 구조, I/O 경로
- 파일시스템 개요 — VFS, 마운트(Mount), superblock
- I/O 스케줄러(Scheduler) — mq-deadline, BFQ, kyber
- NVMe — NVMe 프로토콜, SQ/CQ, 멀티큐
- Linux Crypto Framework — 커널 암호 API, skcipher, AEAD, ahash
- 커널 문서:
Documentation/admin-guide/device-mapper/(integrity) - cryptsetup/LUKS2: gitlab.com/cryptsetup
- dm-integrity 커널 소스:
drivers/md/dm-integrity.c - 커널 문서 — dm-integrity: kernel.org dm-integrity 문서
- dm-integrity 커널 소스 (Bootlin): dm-integrity.c
- LWN.net — dm-integrity 소개: dm-integrity: a new device-mapper target
- cryptsetup 매뉴얼 페이지(Page): man cryptsetup(8)