mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-06 08:20:07 +01:00
Autodetect optimal encryption sector size on LUKS2 format.
This commit is contained in:
@@ -120,6 +120,7 @@ int device_check_size(struct crypt_device *cd,
|
||||
struct device *device,
|
||||
uint64_t req_offset, int falloc);
|
||||
void device_set_block_size(struct device *device, size_t size);
|
||||
size_t device_optimal_encryption_sector_size(struct crypt_device *cd, struct device *device);
|
||||
|
||||
int device_open_locked(struct crypt_device *cd, struct device *device, int flags);
|
||||
int device_read_lock(struct crypt_device *cd, struct device *device);
|
||||
|
||||
@@ -599,7 +599,7 @@ struct crypt_params_luks2 {
|
||||
const struct crypt_params_integrity *integrity_params; /**< Data integrity parameters or @e NULL*/
|
||||
size_t data_alignment; /**< data area alignment in 512B sectors, data offset is multiple of this */
|
||||
const char *data_device; /**< detached encrypted data device or @e NULL */
|
||||
uint32_t sector_size; /**< encryption sector size */
|
||||
uint32_t sector_size; /**< encryption sector size, 0 triggers auto-detection for optimal encryption sector size */
|
||||
const char *label; /**< header label or @e NULL*/
|
||||
const char *subsystem; /**< header subsystem label or @e NULL*/
|
||||
};
|
||||
|
||||
@@ -7,6 +7,7 @@ CRYPTSETUP_2.4 {
|
||||
crypt_activate_by_token_type;
|
||||
crypt_activate_by_token_pin;
|
||||
crypt_dump_json;
|
||||
crypt_format;
|
||||
};
|
||||
|
||||
CRYPTSETUP_2.0 {
|
||||
|
||||
76
lib/setup.c
76
lib/setup.c
@@ -1706,12 +1706,13 @@ static int _crypt_format_luks2(struct crypt_device *cd,
|
||||
const char *uuid,
|
||||
const char *volume_key,
|
||||
size_t volume_key_size,
|
||||
struct crypt_params_luks2 *params)
|
||||
struct crypt_params_luks2 *params,
|
||||
bool sector_size_autodetect)
|
||||
{
|
||||
int r, integrity_key_size = 0;
|
||||
unsigned long required_alignment = DEFAULT_DISK_ALIGNMENT;
|
||||
unsigned long alignment_offset = 0;
|
||||
unsigned int sector_size = params ? params->sector_size : SECTOR_SIZE;
|
||||
unsigned int sector_size;
|
||||
const char *integrity = params ? params->integrity : NULL;
|
||||
uint64_t dev_size;
|
||||
uint32_t dmc_flags;
|
||||
@@ -1733,15 +1734,30 @@ static int _crypt_format_luks2(struct crypt_device *cd,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (params && params->sector_size)
|
||||
sector_size_autodetect = false;
|
||||
|
||||
if (sector_size_autodetect) {
|
||||
sector_size = device_optimal_encryption_sector_size(cd, crypt_data_device(cd));
|
||||
log_dbg(cd, "Auto-detected optimal encryption sector size for device %s is %d bytes.",
|
||||
device_path(crypt_data_device(cd)), sector_size);
|
||||
} else
|
||||
sector_size = params ? params->sector_size : SECTOR_SIZE;
|
||||
|
||||
if (sector_size < SECTOR_SIZE || sector_size > MAX_SECTOR_SIZE ||
|
||||
NOTPOW2(sector_size)) {
|
||||
log_err(cd, _("Unsupported encryption sector size."));
|
||||
return -EINVAL;
|
||||
}
|
||||
if (sector_size != SECTOR_SIZE && !dm_flags(cd, DM_CRYPT, &dmc_flags) &&
|
||||
!(dmc_flags & DM_SECTOR_SIZE_SUPPORTED))
|
||||
!(dmc_flags & DM_SECTOR_SIZE_SUPPORTED)) {
|
||||
if (sector_size_autodetect) {
|
||||
log_dbg(cd, "dm-crypt does not support encryption sector size option. Reverting to 512 bytes.");
|
||||
sector_size = SECTOR_SIZE;
|
||||
} else
|
||||
log_std(cd, _("WARNING: The device activation will fail, dm-crypt is missing "
|
||||
"support for requested encryption sector size.\n"));
|
||||
}
|
||||
|
||||
if (integrity) {
|
||||
if (params->integrity_params) {
|
||||
@@ -1813,6 +1829,21 @@ static int _crypt_format_luks2(struct crypt_device *cd,
|
||||
&required_alignment,
|
||||
&alignment_offset, DEFAULT_DISK_ALIGNMENT);
|
||||
|
||||
r = device_size(crypt_data_device(cd), &dev_size);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
if (sector_size_autodetect) {
|
||||
if (cd->data_offset && MISALIGNED(cd->data_offset, sector_size)) {
|
||||
log_dbg(cd, "Data offset not alligned to sector size. Reverting to 512 bytes.");
|
||||
sector_size = SECTOR_SIZE;
|
||||
} else if (MISALIGNED(dev_size - (uint64_t)required_alignment - (uint64_t)alignment_offset, sector_size)) {
|
||||
/* underflow does not affect misalignment checks */
|
||||
log_err(cd, "Device size is not aligned to sector size. Reverting to 512 bytes.");
|
||||
sector_size = SECTOR_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: allow this later also for normal ciphers (check AF_ALG availability. */
|
||||
if (integrity && !integrity_key_size) {
|
||||
r = crypt_cipher_check_kernel(cipher, cipher_mode, integrity, volume_key_size);
|
||||
@@ -1842,10 +1873,6 @@ static int _crypt_format_luks2(struct crypt_device *cd,
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = device_size(crypt_data_device(cd), &dev_size);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
if (dev_size < (crypt_get_data_offset(cd) * SECTOR_SIZE))
|
||||
log_std(cd, _("WARNING: Data offset is outside of currently available data device.\n"));
|
||||
|
||||
@@ -2241,14 +2268,15 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
int crypt_format(struct crypt_device *cd,
|
||||
static int _crypt_format(struct crypt_device *cd,
|
||||
const char *type,
|
||||
const char *cipher,
|
||||
const char *cipher_mode,
|
||||
const char *uuid,
|
||||
const char *volume_key,
|
||||
size_t volume_key_size,
|
||||
void *params)
|
||||
void *params,
|
||||
bool sector_size_autodetect)
|
||||
{
|
||||
int r;
|
||||
|
||||
@@ -2276,7 +2304,7 @@ int crypt_format(struct crypt_device *cd,
|
||||
uuid, volume_key, volume_key_size, params);
|
||||
else if (isLUKS2(type))
|
||||
r = _crypt_format_luks2(cd, cipher, cipher_mode,
|
||||
uuid, volume_key, volume_key_size, params);
|
||||
uuid, volume_key, volume_key_size, params, sector_size_autodetect);
|
||||
else if (isLOOPAES(type))
|
||||
r = _crypt_format_loopaes(cd, cipher, uuid, volume_key_size, params);
|
||||
else if (isVERITY(type))
|
||||
@@ -2297,6 +2325,34 @@ int crypt_format(struct crypt_device *cd,
|
||||
return r;
|
||||
}
|
||||
|
||||
int crypt_format(struct crypt_device *cd,
|
||||
const char *type,
|
||||
const char *cipher,
|
||||
const char *cipher_mode,
|
||||
const char *uuid,
|
||||
const char *volume_key,
|
||||
size_t volume_key_size,
|
||||
void *params)
|
||||
{
|
||||
return _crypt_format(cd, type, cipher, cipher_mode, uuid, volume_key, volume_key_size, params, true);
|
||||
}
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define CRYPT_EXPORT_SYMBOL(func, maj, min) \
|
||||
__asm__(".symver " #func "_v" #maj "_" #min ", " #func "@CRYPTSETUP_" #maj "." #min)
|
||||
int crypt_format_v2_0(struct crypt_device *cd, const char *type, const char *cipher,
|
||||
const char *cipher_mode,const char *uuid, const char *volume_key,
|
||||
size_t volume_key_size, void *params);
|
||||
|
||||
int crypt_format_v2_0(struct crypt_device *cd, const char *type, const char *cipher,
|
||||
const char *cipher_mode,const char *uuid, const char *volume_key,
|
||||
size_t volume_key_size, void *params)
|
||||
{
|
||||
return _crypt_format(cd, type, cipher, cipher_mode, uuid, volume_key, volume_key_size, params, false);
|
||||
}
|
||||
CRYPT_EXPORT_SYMBOL(crypt_format, 2, 0);
|
||||
#endif
|
||||
|
||||
int crypt_repair(struct crypt_device *cd,
|
||||
const char *requested_type,
|
||||
void *params __attribute__((unused)))
|
||||
|
||||
@@ -112,6 +112,23 @@ static size_t device_block_size_fd(int fd, size_t *min_size)
|
||||
return bsize;
|
||||
}
|
||||
|
||||
static size_t device_block_phys_size_fd(int fd)
|
||||
{
|
||||
struct stat st;
|
||||
int arg;
|
||||
size_t bsize = SECTOR_SIZE;
|
||||
|
||||
if (fstat(fd, &st) < 0)
|
||||
return bsize;
|
||||
|
||||
if (S_ISREG(st.st_mode))
|
||||
bsize = MAX_SECTOR_SIZE;
|
||||
else if (ioctl(fd, BLKPBSZGET, &arg) >= 0)
|
||||
bsize = (size_t)arg;
|
||||
|
||||
return bsize;
|
||||
}
|
||||
|
||||
static size_t device_alignment_fd(int devfd)
|
||||
{
|
||||
long alignment = DEFAULT_MEM_ALIGNMENT;
|
||||
@@ -570,6 +587,42 @@ size_t device_block_size(struct crypt_device *cd, struct device *device)
|
||||
return device->block_size;
|
||||
}
|
||||
|
||||
size_t device_optimal_encryption_sector_size(struct crypt_device *cd, struct device *device)
|
||||
{
|
||||
int fd;
|
||||
size_t phys_block_size;
|
||||
|
||||
if (!device)
|
||||
return SECTOR_SIZE;
|
||||
|
||||
fd = open(device->file_path ?: device->path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
log_dbg(cd, "Cannot get optimal encryption sector size for device %s.", device_path(device));
|
||||
return SECTOR_SIZE;
|
||||
}
|
||||
|
||||
/* cache device block size */
|
||||
device->block_size = device_block_size_fd(fd, NULL);
|
||||
if (!device->block_size) {
|
||||
close(fd);
|
||||
log_dbg(cd, "Cannot get block size for device %s.", device_path(device));
|
||||
return SECTOR_SIZE;
|
||||
}
|
||||
|
||||
if (device->block_size >= MAX_SECTOR_SIZE) {
|
||||
close(fd);
|
||||
return MISALIGNED(device->block_size, MAX_SECTOR_SIZE) ? SECTOR_SIZE : MAX_SECTOR_SIZE;
|
||||
}
|
||||
|
||||
phys_block_size = device_block_phys_size_fd(fd);
|
||||
close(fd);
|
||||
|
||||
if (device->block_size >= phys_block_size || phys_block_size <= SECTOR_SIZE || phys_block_size > MAX_SECTOR_SIZE || MISALIGNED(phys_block_size, device->block_size))
|
||||
return device->block_size;
|
||||
|
||||
return phys_block_size;
|
||||
}
|
||||
|
||||
int device_read_ahead(struct device *device, uint32_t *read_ahead)
|
||||
{
|
||||
int fd, r = 0;
|
||||
|
||||
@@ -1328,8 +1328,15 @@ action asks for passphrase to proceed further.
|
||||
.TP
|
||||
.B "\-\-sector\-size <bytes>"
|
||||
Set sector size for use with disk encryption. It must be power of two
|
||||
and in range 512 - 4096 bytes. The default is 512 bytes sectors.
|
||||
This option is available only in the LUKS2 mode.
|
||||
and in range 512 - 4096 bytes. This option is available only in the LUKS2
|
||||
or plain modes.
|
||||
|
||||
The default for plain mode is 512 bytes. For LUKS2 devices it's established
|
||||
during luksFormat operation based on parameters provided by underlying data device.
|
||||
For native 4K block devices it's 4096 bytes. For 4K/512e (4K physical sector size
|
||||
with 512 bytes emulation) it's 4096 bytes. For drives reporting only 512 bytes
|
||||
block size it remains 512 bytes. If data device is regular file put in filesystem
|
||||
it's 4096 bytes.
|
||||
|
||||
Note that if sector size is higher than underlying device hardware sector
|
||||
and there is not integrity protection that uses data journal, using
|
||||
|
||||
@@ -1288,7 +1288,7 @@ static int _luksFormat(struct crypt_device **r_cd, char **r_password, size_t *r_
|
||||
struct crypt_params_luks2 params2 = {
|
||||
.data_alignment = params1.data_alignment,
|
||||
.data_device = params1.data_device,
|
||||
.sector_size = ARG_UINT32(OPT_SECTOR_SIZE_ID) ?: SECTOR_SIZE,
|
||||
.sector_size = ARG_UINT32(OPT_SECTOR_SIZE_ID),
|
||||
.label = ARG_STR(OPT_LABEL_ID),
|
||||
.subsystem = ARG_STR(OPT_SUBSYSTEM_ID)
|
||||
};
|
||||
|
||||
@@ -711,7 +711,7 @@ echo $PWD1 | $CRYPTSETUP luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV --head
|
||||
echo $PWD1 | $CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV --header $HEADER_IMG --align-payload 8192 || fail
|
||||
echo $PWD1 | $CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV --header $HEADER_IMG --align-payload 4096 >/dev/null || fail
|
||||
$CRYPTSETUP luksDump $HEADER_IMG | grep -e "0: crypt" -A1 | grep -qe $((4096*512)) || fail
|
||||
echo $PWD1 | $CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV --header $HEADER_IMG --align-payload 0 || fail
|
||||
echo $PWD1 | $CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV --header $HEADER_IMG --align-payload 0 --sector-size 512 || fail
|
||||
echo $PWD1 | $CRYPTSETUP luksOpen $LOOPDEV-missing --header $HEADER_IMG $DEV_NAME 2>/dev/null && fail
|
||||
echo $PWD1 | $CRYPTSETUP luksOpen $LOOPDEV --header $HEADER_IMG $DEV_NAME || fail
|
||||
echo $PWD1 | $CRYPTSETUP -q resize $DEV_NAME --size 100 --header $HEADER_IMG || fail
|
||||
|
||||
@@ -917,7 +917,7 @@ $CRYPTSETUP close $DEV_NAME || fail
|
||||
$CRYPTSETUP close $DEV_NAME2 || fail
|
||||
|
||||
echo "[5] Decryption with detached header"
|
||||
echo $PWD1 | $CRYPTSETUP luksFormat --type luks2 -c aes-cbc-essiv:sha256 -s 128 --header $IMG_HDR -q $FAST_PBKDF_ARGON $DEV || fail
|
||||
echo $PWD1 | $CRYPTSETUP luksFormat --type luks2 --sector-size 512 -c aes-cbc-essiv:sha256 -s 128 --header $IMG_HDR -q $FAST_PBKDF_ARGON $DEV || fail
|
||||
wipe $PWD1 $IMG_HDR
|
||||
echo $PWD1 | $CRYPTSETUP reencrypt -q --decrypt --header $IMG_HDR $DEV || fail
|
||||
check_hash_dev $DEV $HASH3
|
||||
@@ -935,7 +935,7 @@ echo $PWD1 | $CRYPTSETUP reencrypt -q --decrypt --resilience checksum --header $
|
||||
check_hash_dev $DEV $HASH3
|
||||
|
||||
# check deferred remove works as expected after decryption
|
||||
echo $PWD1 | $CRYPTSETUP luksFormat --type luks2 -c serpent-xts-plain --header $IMG_HDR -q $FAST_PBKDF_ARGON $DEV || fail
|
||||
echo $PWD1 | $CRYPTSETUP luksFormat --type luks2 --sector-size 512 -c serpent-xts-plain --header $IMG_HDR -q $FAST_PBKDF_ARGON $DEV || fail
|
||||
open_crypt $PWD1 $IMG_HDR
|
||||
dmsetup create $DEV_NAME2 --table "0 1 linear /dev/mapper/$DEV_NAME 0" || fail
|
||||
echo $PWD1 | $CRYPTSETUP reencrypt -q --decrypt --resilience checksum --header $IMG_HDR --active-name $DEV_NAME || fail
|
||||
|
||||
@@ -462,7 +462,7 @@ check_hash $PWD1 $HASH1
|
||||
$CRYPTSETUP -q convert --type luks2 $IMG || fail
|
||||
echo $PWD1 | $REENC $IMG -q $FAST_PBKDF_PBKDF2 || fail
|
||||
check_hash $PWD1 $HASH1
|
||||
echo $PWD1 | $CRYPTSETUP -q luksFormat --type luks2 $FAST_PBKDF_PBKDF2 $IMG --offset 8192 || fail
|
||||
echo $PWD1 | $CRYPTSETUP -q luksFormat --sector-size 512 --type luks2 $FAST_PBKDF_PBKDF2 $IMG --offset 8192 || fail
|
||||
wipe $PWD1
|
||||
check_hash $PWD1 $HASH5
|
||||
$CRYPTSETUP -q convert --type luks1 $IMG || fail
|
||||
|
||||
Reference in New Issue
Block a user