mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-05 16:00:05 +01:00
Integritysetup: implement new bitmap mode.
This commit is contained in:
committed by
Ondrej Kozina
parent
1923928fdc
commit
448fca1fdf
@@ -41,7 +41,8 @@ static int INTEGRITY_read_superblock(struct crypt_device *cd,
|
||||
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
|
||||
device_alignment(device), sb, sizeof(*sb), offset) != sizeof(*sb) ||
|
||||
memcmp(sb->magic, SB_MAGIC, sizeof(sb->magic)) ||
|
||||
(sb->version != SB_VERSION_1 && sb->version != SB_VERSION_2)) {
|
||||
(sb->version != SB_VERSION_1 && sb->version != SB_VERSION_2 &&
|
||||
sb->version != SB_VERSION_3)) {
|
||||
log_std(cd, "No integrity superblock detected on %s.\n",
|
||||
device_path(device));
|
||||
r = -EINVAL;
|
||||
@@ -90,9 +91,11 @@ int INTEGRITY_dump(struct crypt_device *cd, struct device *device, uint64_t offs
|
||||
log_std(cd, "sector_size %u\n", SECTOR_SIZE << sb.log2_sectors_per_block);
|
||||
if (sb.version == SB_VERSION_2 && (sb.flags & SB_FLAG_RECALCULATING))
|
||||
log_std(cd, "recalc_sector %" PRIu64 "\n", sb.recalc_sector);
|
||||
log_std(cd, "flags %s%s\n",
|
||||
log_std(cd, "log2_blocks_per_bitmap %u\n", sb.log2_blocks_per_bitmap_bit);
|
||||
log_std(cd, "flags %s%s%s\n",
|
||||
sb.flags & SB_FLAG_HAVE_JOURNAL_MAC ? "have_journal_mac " : "",
|
||||
sb.flags & SB_FLAG_RECALCULATING ? "recalculating " : "");
|
||||
sb.flags & SB_FLAG_RECALCULATING ? "recalculating " : "",
|
||||
sb.flags & SB_FLAG_DIRTY_BITMAP ? "dirty_bitmap " : "");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -33,9 +33,11 @@ struct crypt_dm_active_device;
|
||||
#define SB_MAGIC "integrt"
|
||||
#define SB_VERSION_1 1
|
||||
#define SB_VERSION_2 2
|
||||
#define SB_VERSION_3 3
|
||||
|
||||
#define SB_FLAG_HAVE_JOURNAL_MAC (1 << 0)
|
||||
#define SB_FLAG_RECALCULATING (1 << 1) /* V2 only */
|
||||
#define SB_FLAG_DIRTY_BITMAP (1 << 2) /* V3 only */
|
||||
|
||||
struct superblock {
|
||||
uint8_t magic[8];
|
||||
@@ -46,7 +48,8 @@ struct superblock {
|
||||
uint64_t provided_data_sectors;
|
||||
uint32_t flags;
|
||||
uint8_t log2_sectors_per_block;
|
||||
uint8_t pad[3];
|
||||
uint8_t log2_blocks_per_bitmap_bit; /* V3 only */
|
||||
uint8_t pad[2];
|
||||
uint64_t recalc_sector; /* V2 only */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
@@ -546,11 +546,15 @@ struct crypt_params_tcrypt {
|
||||
*
|
||||
* @see crypt_format, crypt_load
|
||||
*
|
||||
* @note In bitmap tracking mode, the journal is implicitly disabled.
|
||||
* As an ugly workaround for compatibility, journal_watermark is overloaded
|
||||
* to mean 512-bytes sectors-per-bit and journal_commit_time means bitmap flush time.
|
||||
* All other journal parameters are not applied in the bitmap mode.
|
||||
*/
|
||||
struct crypt_params_integrity {
|
||||
uint64_t journal_size; /**< size of journal in bytes */
|
||||
unsigned int journal_watermark; /**< journal flush watermark in percents */
|
||||
unsigned int journal_commit_time; /**< journal commit time in ms */
|
||||
unsigned int journal_watermark; /**< journal flush watermark in percents; in bitmap mode sectors-per-bit */
|
||||
unsigned int journal_commit_time; /**< journal commit time (or bitmap flush time) in ms */
|
||||
uint32_t interleave_sectors; /**< number of interleave sectors (power of two) */
|
||||
uint32_t tag_size; /**< tag size per-sector in bytes */
|
||||
uint32_t sector_size; /**< sector size in bytes */
|
||||
@@ -1059,6 +1063,8 @@ int crypt_keyslot_destroy(struct crypt_device *cd, int keyslot);
|
||||
#define CRYPT_ACTIVATE_REFRESH (1 << 18)
|
||||
/** Use global lock to serialize memory hard KDF on activation (OOM workaround) */
|
||||
#define CRYPT_ACTIVATE_SERIALIZE_MEMORY_HARD_PBKDF (1 << 19)
|
||||
/** dm-integrity: direct writes, use bitmap to track dirty sectors */
|
||||
#define CRYPT_ACTIVATE_NO_JOURNAL_BITMAP (1 << 20)
|
||||
|
||||
/**
|
||||
* Active device runtime attributes
|
||||
|
||||
@@ -215,6 +215,9 @@ static void _dm_set_integrity_compat(struct crypt_device *cd,
|
||||
if (_dm_satisfies_version(1, 2, 0, integrity_maj, integrity_min, integrity_patch))
|
||||
_dm_flags |= DM_INTEGRITY_RECALC_SUPPORTED;
|
||||
|
||||
if (_dm_satisfies_version(1, 3, 0, integrity_maj, integrity_min, integrity_patch))
|
||||
_dm_flags |= DM_INTEGRITY_BITMAP_SUPPORTED;
|
||||
|
||||
_dm_integrity_checked = true;
|
||||
}
|
||||
|
||||
@@ -724,13 +727,17 @@ static char *get_dm_integrity_params(const struct dm_target *tgt, uint32_t flags
|
||||
}
|
||||
if (tgt->u.integrity.journal_watermark) {
|
||||
num_options++;
|
||||
snprintf(feature, sizeof(feature), "journal_watermark:%u ",
|
||||
snprintf(feature, sizeof(feature),
|
||||
/* bitmap oveloaded values */
|
||||
(flags & CRYPT_ACTIVATE_NO_JOURNAL_BITMAP) ? "sectors_per_bit:%u " : "journal_watermark:%u ",
|
||||
tgt->u.integrity.journal_watermark);
|
||||
strncat(features, feature, sizeof(features) - strlen(features) - 1);
|
||||
}
|
||||
if (tgt->u.integrity.journal_commit_time) {
|
||||
num_options++;
|
||||
snprintf(feature, sizeof(feature), "commit_time:%u ",
|
||||
snprintf(feature, sizeof(feature),
|
||||
/* bitmap oveloaded values */
|
||||
(flags & CRYPT_ACTIVATE_NO_JOURNAL_BITMAP) ? "bitmap_flush_interval:%u " : "commit_time:%u ",
|
||||
tgt->u.integrity.journal_commit_time);
|
||||
strncat(features, feature, sizeof(features) - strlen(features) - 1);
|
||||
}
|
||||
@@ -824,7 +831,9 @@ static char *get_dm_integrity_params(const struct dm_target *tgt, uint32_t flags
|
||||
strncat(features, feature, sizeof(features) - strlen(features) - 1);
|
||||
}
|
||||
|
||||
if (flags & CRYPT_ACTIVATE_RECOVERY)
|
||||
if (flags & CRYPT_ACTIVATE_NO_JOURNAL_BITMAP)
|
||||
mode = 'B';
|
||||
else if (flags & CRYPT_ACTIVATE_RECOVERY)
|
||||
mode = 'R';
|
||||
else if (flags & CRYPT_ACTIVATE_NO_JOURNAL)
|
||||
mode = 'D';
|
||||
@@ -1528,6 +1537,10 @@ int dm_create_device(struct crypt_device *cd, const char *name,
|
||||
if (r == -EINVAL && dmd->segment.type == DM_INTEGRITY && (dmd->flags & CRYPT_ACTIVATE_RECALCULATE) &&
|
||||
!(dmt_flags & DM_INTEGRITY_RECALC_SUPPORTED))
|
||||
log_err(cd, _("Requested automatic recalculation of integrity tags is not supported."));
|
||||
|
||||
if (r == -EINVAL && dmd->segment.type == DM_INTEGRITY && (dmd->flags & CRYPT_ACTIVATE_NO_JOURNAL_BITMAP) &&
|
||||
!(dmt_flags & DM_INTEGRITY_BITMAP_SUPPORTED))
|
||||
log_err(cd, _("Requested dm-integtity bitmap mode is not supported."));
|
||||
out:
|
||||
dm_exit_context();
|
||||
return r;
|
||||
@@ -2165,12 +2178,16 @@ static int _dm_target_query_integrity(struct crypt_device *cd,
|
||||
|
||||
/* journal */
|
||||
c = toupper(*(++params));
|
||||
if (!*params || *(++params) != ' ' || (c != 'D' && c != 'J' && c != 'R'))
|
||||
if (!*params || *(++params) != ' ' || (c != 'D' && c != 'J' && c != 'R' && c != 'B'))
|
||||
goto err;
|
||||
if (c == 'D')
|
||||
*act_flags |= CRYPT_ACTIVATE_NO_JOURNAL;
|
||||
if (c == 'R')
|
||||
*act_flags |= CRYPT_ACTIVATE_RECOVERY;
|
||||
if (c == 'B') {
|
||||
*act_flags |= CRYPT_ACTIVATE_NO_JOURNAL;
|
||||
*act_flags |= CRYPT_ACTIVATE_NO_JOURNAL_BITMAP;
|
||||
}
|
||||
|
||||
tgt->u.integrity.sector_size = SECTOR_SIZE;
|
||||
|
||||
@@ -2192,7 +2209,15 @@ static int _dm_target_query_integrity(struct crypt_device *cd,
|
||||
tgt->u.integrity.journal_size = val * SECTOR_SIZE;
|
||||
else if (sscanf(arg, "journal_watermark:%u", &val) == 1)
|
||||
tgt->u.integrity.journal_watermark = val;
|
||||
else if (sscanf(arg, "commit_time:%u", &val) == 1)
|
||||
else if (sscanf(arg, "sectors_per_bit:%" PRIu64, &val64) == 1) {
|
||||
if (val64 > UINT_MAX)
|
||||
goto err;
|
||||
/* overrloaded value for bitmap mode */
|
||||
tgt->u.integrity.journal_watermark = (unsigned int)val64;
|
||||
} else if (sscanf(arg, "commit_time:%u", &val) == 1)
|
||||
tgt->u.integrity.journal_commit_time = val;
|
||||
else if (sscanf(arg, "bitmap_flush_interval:%u", &val) == 1)
|
||||
/* overrloaded value for bitmap mode */
|
||||
tgt->u.integrity.journal_commit_time = val;
|
||||
else if (sscanf(arg, "interleave_sectors:%u", &val) == 1)
|
||||
tgt->u.integrity.interleave_sectors = val;
|
||||
|
||||
@@ -62,6 +62,7 @@ static inline uint32_t act2dmflags(uint32_t act_flags)
|
||||
#define DM_CAPI_STRING_SUPPORTED (1 << 14) /* support for cryptoapi format cipher definition */
|
||||
#define DM_DEFERRED_SUPPORTED (1 << 15) /* deferred removal of device */
|
||||
#define DM_INTEGRITY_RECALC_SUPPORTED (1 << 16) /* dm-integrity automatic recalculation supported */
|
||||
#define DM_INTEGRITY_BITMAP_SUPPORTED (1 << 17) /* dm-integrity bitmap mode supported */
|
||||
|
||||
typedef enum { DM_CRYPT = 0, DM_VERITY, DM_INTEGRITY, DM_LINEAR, DM_ERROR, DM_UNKNOWN } dm_target_type;
|
||||
enum tdirection { TARGET_SET = 1, TARGET_QUERY };
|
||||
|
||||
@@ -125,6 +125,21 @@ The file with the integrity key.
|
||||
.TP
|
||||
.B "\-\-integrity\-no\-journal, \-D"
|
||||
Disable journal for integrity device.
|
||||
.TP
|
||||
.B "\-\-integrity\-bitmap\-mode. \-B"
|
||||
Use alternate bitmap mode (available since Linux kernel 5.2) where dm-integrity uses bitmap
|
||||
instead of a journal. If a bit in the bitmap is 1, the corresponding region's data and integrity tags
|
||||
are not synchronized - if the machine crashes, the unsynchronized regions will be recalculated.
|
||||
The bitmap mode is faster than the journal mode, because we don't have to write the data
|
||||
twice, but it is also less reliable, because if data corruption happens
|
||||
when the machine crashes, it may not be detected.
|
||||
.TP
|
||||
.B "\-\-bitmap\-sectors\-per\-bit SECTORS"
|
||||
Number of 512-byte sectors per bitmap bit, the value must be power of two.
|
||||
.TP
|
||||
.B "\-\-bitmap\-flush\-time MS"
|
||||
Bitmap flush time in milliseconds.
|
||||
.TP
|
||||
|
||||
\fBWARNING:\fR
|
||||
In case of a crash, it is possible that the data and integrity tag doesn't match
|
||||
|
||||
@@ -32,7 +32,9 @@ static const char *opt_journal_size_str = NULL;
|
||||
static uint64_t opt_journal_size = 0;
|
||||
static int opt_interleave_sectors = 0;
|
||||
static int opt_journal_watermark = 0;
|
||||
static int opt_bitmap_sectors_per_bit = 0;
|
||||
static int opt_journal_commit_time = 0;
|
||||
static int opt_bitmap_flush_time = 0;
|
||||
static int opt_tag_size = 0;
|
||||
static int opt_sector_size = 0;
|
||||
static int opt_buffer_sectors = 0;
|
||||
@@ -55,6 +57,7 @@ static int opt_journal_crypt_key_size = 0;
|
||||
|
||||
static int opt_integrity_nojournal = 0;
|
||||
static int opt_integrity_recovery = 0;
|
||||
static int opt_integrity_bitmap = 0;
|
||||
|
||||
static int opt_integrity_recalculate = 0;
|
||||
|
||||
@@ -175,8 +178,9 @@ static int action_format(int arg)
|
||||
struct crypt_params_integrity params = {
|
||||
.journal_size = opt_journal_size,
|
||||
.interleave_sectors = opt_interleave_sectors,
|
||||
.journal_watermark = opt_journal_watermark,
|
||||
.journal_commit_time = opt_journal_commit_time,
|
||||
/* in bitmap mode we have to overload these values... */
|
||||
.journal_watermark = opt_integrity_bitmap ? opt_bitmap_sectors_per_bit : opt_journal_watermark,
|
||||
.journal_commit_time = opt_integrity_bitmap ? opt_bitmap_flush_time : opt_journal_commit_time,
|
||||
.buffer_sectors = opt_buffer_sectors,
|
||||
.tag_size = opt_tag_size,
|
||||
.sector_size = opt_sector_size ?: SECTOR_SIZE,
|
||||
@@ -261,8 +265,9 @@ static int action_open(int arg)
|
||||
{
|
||||
struct crypt_device *cd = NULL;
|
||||
struct crypt_params_integrity params = {
|
||||
.journal_watermark = opt_journal_watermark,
|
||||
.journal_commit_time = opt_journal_commit_time,
|
||||
/* in bitmap mode we have to overload these values... */
|
||||
.journal_watermark = opt_integrity_bitmap ? opt_bitmap_sectors_per_bit : opt_journal_watermark,
|
||||
.journal_commit_time = opt_integrity_bitmap ? opt_bitmap_flush_time : opt_journal_commit_time,
|
||||
.buffer_sectors = opt_buffer_sectors,
|
||||
};
|
||||
uint32_t activate_flags = 0;
|
||||
@@ -298,10 +303,12 @@ static int action_open(int arg)
|
||||
params.journal_crypt = journal_crypt;
|
||||
}
|
||||
|
||||
if (opt_integrity_nojournal)
|
||||
if (opt_integrity_nojournal || opt_integrity_bitmap)
|
||||
activate_flags |= CRYPT_ACTIVATE_NO_JOURNAL;
|
||||
if (opt_integrity_recovery)
|
||||
activate_flags |= CRYPT_ACTIVATE_RECOVERY;
|
||||
if (opt_integrity_bitmap)
|
||||
activate_flags |= CRYPT_ACTIVATE_NO_JOURNAL_BITMAP;
|
||||
|
||||
if (opt_integrity_recalculate)
|
||||
activate_flags |= CRYPT_ACTIVATE_RECALCULATE;
|
||||
@@ -415,7 +422,10 @@ static int action_status(int arg)
|
||||
cad.flags & CRYPT_ACTIVATE_RECOVERY ? " recovery" : "");
|
||||
log_std(" failures: %" PRIu64 "\n",
|
||||
crypt_get_active_integrity_failures(cd, action_argv[0]));
|
||||
if (cad.flags & CRYPT_ACTIVATE_NO_JOURNAL) {
|
||||
if (cad.flags & CRYPT_ACTIVATE_NO_JOURNAL_BITMAP) {
|
||||
log_std(" bitmap 512-byte sectors per bit: %u\n", ip.journal_watermark);
|
||||
log_std(" bitmap flush interval: %u ms\n", ip.journal_commit_time);
|
||||
} if (cad.flags & CRYPT_ACTIVATE_NO_JOURNAL) {
|
||||
log_std(" journal: not active\n");
|
||||
} else {
|
||||
log_std(" journal size: %" PRIu64 " bytes\n", ip.journal_size);
|
||||
@@ -531,6 +541,8 @@ int main(int argc, const char **argv)
|
||||
{ "interleave-sectors", '\0', POPT_ARG_INT, &opt_interleave_sectors, 0, N_("Interleave sectors"), N_("SECTORS") },
|
||||
{ "journal-watermark", '\0', POPT_ARG_INT, &opt_journal_watermark, 0, N_("Journal watermark"),N_("percent") },
|
||||
{ "journal-commit-time",'\0', POPT_ARG_INT, &opt_journal_commit_time,0, N_("Journal commit time"), N_("ms") },
|
||||
{ "bitmap-sectors-per-bit",'\0', POPT_ARG_INT,&opt_bitmap_sectors_per_bit, 0, N_("Number of 512-byte sectors per bit (bitmap mode)."), NULL },
|
||||
{ "bitmap-flush-time", '\0', POPT_ARG_INT, &opt_bitmap_flush_time, 0, N_("Bitmap mode flush time"), N_("ms") },
|
||||
{ "tag-size", 't', POPT_ARG_INT, &opt_tag_size, 0, N_("Tag size (per-sector)"), N_("bytes") },
|
||||
{ "sector-size", 's', POPT_ARG_INT, &opt_sector_size, 0, N_("Sector size"), N_("bytes") },
|
||||
{ "buffer-sectors", '\0', POPT_ARG_INT, &opt_buffer_sectors, 0, N_("Buffers size"), N_("SECTORS") },
|
||||
@@ -549,6 +561,7 @@ int main(int argc, const char **argv)
|
||||
|
||||
{ "integrity-no-journal", 'D', POPT_ARG_NONE, &opt_integrity_nojournal, 0, N_("Disable journal for integrity device"), NULL },
|
||||
{ "integrity-recovery-mode", 'R', POPT_ARG_NONE, &opt_integrity_recovery, 0, N_("Recovery mode (no journal, no tag checking)"), NULL },
|
||||
{ "integrity-bitmap-mode", 'B', POPT_ARG_NONE, &opt_integrity_bitmap, 0, N_("Use bitmap to track changes and disable journal for integrity device"), NULL },
|
||||
{ "integrity-recalculate", '\0', POPT_ARG_NONE, &opt_integrity_recalculate, 0, N_("Recalculate initial tags automatically."), NULL },
|
||||
POPT_TABLEEND
|
||||
};
|
||||
@@ -635,7 +648,7 @@ int main(int argc, const char **argv)
|
||||
opt_journal_commit_time < 0 || opt_tag_size < 0 ||
|
||||
opt_sector_size < 0 || opt_buffer_sectors < 0 ||
|
||||
opt_integrity_key_size < 0 || opt_journal_integrity_key_size < 0 ||
|
||||
opt_journal_crypt_key_size < 0)
|
||||
opt_journal_crypt_key_size < 0 || opt_bitmap_flush_time < 0 || opt_bitmap_sectors_per_bit < 0)
|
||||
usage(popt_context, EXIT_FAILURE,
|
||||
_("Negative number for option not permitted."),
|
||||
poptGetInvocationName(popt_context));
|
||||
@@ -676,6 +689,18 @@ int main(int argc, const char **argv)
|
||||
usage(popt_context, EXIT_FAILURE, _("Journal encryption algorithm must be specified if journal encryption key is used."),
|
||||
poptGetInvocationName(popt_context));
|
||||
|
||||
if (opt_integrity_recovery && opt_integrity_bitmap)
|
||||
usage(popt_context, EXIT_FAILURE, _("Recovery and bitmap mode options are mutually exclusive."),
|
||||
poptGetInvocationName(popt_context));
|
||||
|
||||
if (opt_integrity_bitmap && (opt_journal_integrity_key_file || opt_journal_crypt || opt_journal_watermark || opt_journal_commit_time))
|
||||
usage(popt_context, EXIT_FAILURE, _("Journal options cannot be used in bitmap mode."),
|
||||
poptGetInvocationName(popt_context));
|
||||
|
||||
if (!opt_integrity_bitmap && (opt_bitmap_flush_time || opt_bitmap_sectors_per_bit))
|
||||
usage(popt_context, EXIT_FAILURE, _("Bitmap options can be used only in bitmap mode."),
|
||||
poptGetInvocationName(popt_context));
|
||||
|
||||
if (opt_debug) {
|
||||
opt_verbose = 1;
|
||||
crypt_set_debug_level(-1);
|
||||
|
||||
Reference in New Issue
Block a user