* Allow different data offset setting for detached header.

git-svn-id: https://cryptsetup.googlecode.com/svn/trunk@576 36d66b0a-2a48-0410-832c-cd162a569da5
This commit is contained in:
Milan Broz
2011-07-20 17:39:38 +00:00
parent f7f9e291f4
commit f80b506b65
10 changed files with 93 additions and 32 deletions

View File

@@ -5,6 +5,7 @@
* Support retries and timeout parameters for luksSuspend. * Support retries and timeout parameters for luksSuspend.
* Add --header option for detached metadata (on-disk LUKS header) device. * Add --header option for detached metadata (on-disk LUKS header) device.
* Add crypt_init_by_name_and_header() and crypt_set_data_device() to API. * Add crypt_init_by_name_and_header() and crypt_set_data_device() to API.
* Allow different data offset setting for detached header.
2011-07-07 Milan Broz <mbroz@redhat.com> 2011-07-07 Milan Broz <mbroz@redhat.com>
* Remove old API functions (all functions using crypt_options). * Remove old API functions (all functions using crypt_options).

1
TODO
View File

@@ -1,4 +1,3 @@
Version 1.4.0: Version 1.4.0:
- Support separation of metadata device
- Wipe device flag - Wipe device flag
- Support K/M suffixes for align payload (new switch?). - Support K/M suffixes for align payload (new switch?).

View File

@@ -55,6 +55,7 @@ ssize_t write_blockwise(int fd, void *buf, size_t count);
ssize_t read_blockwise(int fd, void *_buf, size_t count); ssize_t read_blockwise(int fd, void *_buf, size_t count);
ssize_t write_lseek_blockwise(int fd, char *buf, size_t count, off_t offset); ssize_t write_lseek_blockwise(int fd, char *buf, size_t count, off_t offset);
int device_ready(struct crypt_device *cd, const char *device, int mode); int device_ready(struct crypt_device *cd, const char *device, int mode);
int device_size(const char *device, uint64_t *size);
enum devcheck { DEV_OK = 0, DEV_EXCL = 1, DEV_SHARED = 2 }; enum devcheck { DEV_OK = 0, DEV_EXCL = 1, DEV_SHARED = 2 };
int device_check_and_adjust(struct crypt_device *cd, int device_check_and_adjust(struct crypt_device *cd,

View File

@@ -183,6 +183,7 @@ struct crypt_params_plain {
struct crypt_params_luks1 { struct crypt_params_luks1 {
const char *hash; /* hash used in LUKS header */ const char *hash; /* hash used in LUKS header */
size_t data_alignment; /* in sectors, data offset is multiple of this */ size_t data_alignment; /* in sectors, data offset is multiple of this */
const char *data_device; /* detached ciphertext device or NULL */
}; };
struct crypt_params_loopaes { struct crypt_params_loopaes {

View File

@@ -19,8 +19,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <fcntl.h> #include <fcntl.h>
#include <errno.h> #include <errno.h>
@@ -313,7 +311,6 @@ int LUKS_read_phdr(const char *device,
{ {
ssize_t hdr_size = sizeof(struct luks_phdr); ssize_t hdr_size = sizeof(struct luks_phdr);
int devfd = 0, r = 0; int devfd = 0, r = 0;
uint64_t size;
log_dbg("Reading LUKS header of size %d from device %s", log_dbg("Reading LUKS header of size %d from device %s",
hdr_size, device); hdr_size, device);
@@ -329,15 +326,7 @@ int LUKS_read_phdr(const char *device,
else else
r = _check_and_convert_hdr(device, hdr, require_luks_device, ctx); r = _check_and_convert_hdr(device, hdr, require_luks_device, ctx);
#ifdef BLKGETSIZE64
if (r == 0 && (ioctl(devfd, BLKGETSIZE64, &size) < 0 ||
size < (uint64_t)hdr->payloadOffset)) {
log_err(ctx, _("LUKS header detected but device %s is too small.\n"), device);
r = -EINVAL;
}
#endif
close(devfd); close(devfd);
return r; return r;
} }
@@ -413,6 +402,7 @@ int LUKS_generate_phdr(struct luks_phdr *header,
unsigned int alignOffset, unsigned int alignOffset,
uint32_t iteration_time_ms, uint32_t iteration_time_ms,
uint64_t *PBKDF2_per_sec, uint64_t *PBKDF2_per_sec,
const char *metadata_device,
struct crypt_device *ctx) struct crypt_device *ctx)
{ {
unsigned int i=0; unsigned int i=0;
@@ -422,7 +412,8 @@ int LUKS_generate_phdr(struct luks_phdr *header,
int currentSector; int currentSector;
char luksMagic[] = LUKS_MAGIC; char luksMagic[] = LUKS_MAGIC;
if (alignPayload == 0) /* For separate metadata device allow zero alignment */
if (alignPayload == 0 && !metadata_device)
alignPayload = DEFAULT_DISK_ALIGNMENT / SECTOR_SIZE; alignPayload = DEFAULT_DISK_ALIGNMENT / SECTOR_SIZE;
if (PBKDF2_HMAC_ready(hashSpec) < 0) { if (PBKDF2_HMAC_ready(hashSpec) < 0) {
@@ -486,10 +477,15 @@ int LUKS_generate_phdr(struct luks_phdr *header,
currentSector = round_up_modulo(currentSector + blocksPerStripeSet, currentSector = round_up_modulo(currentSector + blocksPerStripeSet,
LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE); LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE);
} }
currentSector = round_up_modulo(currentSector, alignPayload);
/* alignOffset - offset from natural device alignment provided by topology info */ if (metadata_device) {
header->payloadOffset = currentSector + alignOffset; /* for separate metadata device use alignPayload directly */
header->payloadOffset = alignPayload;
} else {
/* alignOffset - offset from natural device alignment provided by topology info */
currentSector = round_up_modulo(currentSector, alignPayload);
header->payloadOffset = currentSector + alignOffset;
}
uuid_unparse(partitionUuid, header->uuid); uuid_unparse(partitionUuid, header->uuid);

View File

@@ -88,6 +88,7 @@ int LUKS_generate_phdr(
unsigned int alignOffset, unsigned int alignOffset,
uint32_t iteration_time_ms, uint32_t iteration_time_ms,
uint64_t *PBKDF2_per_sec, uint64_t *PBKDF2_per_sec,
const char *metadata_device,
struct crypt_device *ctx); struct crypt_device *ctx);
int LUKS_read_phdr( int LUKS_read_phdr(

View File

@@ -476,6 +476,27 @@ bad:
return r; return r;
} }
static int crypt_check_data_device_size(struct crypt_device *cd)
{
int r;
uint64_t size, size_min;
/* Check data device size, require at least one sector */
size_min = crypt_get_data_offset(cd) ?: SECTOR_SIZE;
r = device_size(crypt_get_device_name(cd), &size);
if (r < 0)
return r;
if (size < size_min) {
log_err(cd, _("LUKS header detected but device %s is too small.\n"),
crypt_get_device_name(cd));
return -EINVAL;
}
return r;
}
int crypt_set_data_device(struct crypt_device *cd, const char *device) int crypt_set_data_device(struct crypt_device *cd, const char *device)
{ {
char *data_device; char *data_device;
@@ -506,7 +527,7 @@ int crypt_set_data_device(struct crypt_device *cd, const char *device)
cd->device = data_device; cd->device = data_device;
return 0; return crypt_check_data_device_size(cd);
} }
int crypt_init_by_name_and_header(struct crypt_device **cd, int crypt_init_by_name_and_header(struct crypt_device **cd,
@@ -707,10 +728,14 @@ static int _crypt_format_luks1(struct crypt_device *cd,
if(!cd->volume_key) if(!cd->volume_key)
return -ENOMEM; return -ENOMEM;
//FIXME: external metadata, ignore alignment if (params && params->data_device) {
if (params && params->data_alignment) cd->metadata_device = cd->device;
if (!(cd->device = strdup(params->data_device)))
return -ENOMEM;
required_alignment = params->data_alignment * SECTOR_SIZE; required_alignment = params->data_alignment * SECTOR_SIZE;
else } else if (params && params->data_alignment) {
required_alignment = params->data_alignment * SECTOR_SIZE;
} else
get_topology_alignment(cd->device, &required_alignment, get_topology_alignment(cd->device, &required_alignment,
&alignment_offset, DEFAULT_DISK_ALIGNMENT); &alignment_offset, DEFAULT_DISK_ALIGNMENT);
@@ -719,7 +744,8 @@ static int _crypt_format_luks1(struct crypt_device *cd,
uuid, LUKS_STRIPES, uuid, LUKS_STRIPES,
required_alignment / SECTOR_SIZE, required_alignment / SECTOR_SIZE,
alignment_offset / SECTOR_SIZE, alignment_offset / SECTOR_SIZE,
cd->iteration_time, &cd->PBKDF2_per_sec, cd); cd->iteration_time, &cd->PBKDF2_per_sec,
cd->metadata_device, cd);
if(r < 0) if(r < 0)
return r; return r;
@@ -839,14 +865,18 @@ int crypt_load(struct crypt_device *cd,
return r; return r;
r = LUKS_read_phdr(mdata_device(cd), &hdr, 1, cd); r = LUKS_read_phdr(mdata_device(cd), &hdr, 1, cd);
if (r < 0)
return r;
if (!r) { r = crypt_check_data_device_size(cd);
memcpy(&cd->hdr, &hdr, sizeof(hdr)); if (r < 0)
free(cd->type); return r;
cd->type = strdup(CRYPT_LUKS1);
if (!cd->type) memcpy(&cd->hdr, &hdr, sizeof(hdr));
r = -ENOMEM; free(cd->type);
} cd->type = strdup(CRYPT_LUKS1);
if (!cd->type)
r = -ENOMEM;
return r; return r;
} }

View File

@@ -336,6 +336,21 @@ int device_ready(struct crypt_device *cd, const char *device, int mode)
return r; return r;
} }
int device_size(const char *device, uint64_t *size)
{
int devfd, r = 0;
devfd = open(device, O_RDONLY);
if(devfd == -1)
return -EINVAL;
if (ioctl(devfd, BLKGETSIZE64, size) < 0)
r = -EINVAL;
close(devfd);
return r;
}
static int get_device_infos(const char *device, enum devcheck device_check, static int get_device_infos(const char *device, enum devcheck device_check,
int *readonly, uint64_t *size) int *readonly, uint64_t *size)
{ {

View File

@@ -357,6 +357,9 @@ If not specified, cryptsetup tries to use topology info provided by kernel
for underlying device to get optimal alignment. for underlying device to get optimal alignment.
If not available (or calculated value is multiple of default) data is by If not available (or calculated value is multiple of default) data is by
default aligned to 1 MiB boundary (2048 512-byte sectors). default aligned to 1 MiB boundary (2048 512-byte sectors).
For detached LUKS header it specifies offset on data device.
See also \-\-header option.
.TP .TP
.B "\-\-uuid=\fIUUID\fR" .B "\-\-uuid=\fIUUID\fR"
Use provided \fIUUID\fR in \fIluksFormat\fR command instead of generating Use provided \fIUUID\fR in \fIluksFormat\fR command instead of generating
@@ -382,8 +385,11 @@ Set detached (separated) metadata device or file with LUKS header.
This options allows separation of ciphertext device and on-disk metadata header. This options allows separation of ciphertext device and on-disk metadata header.
This option is only relevant for LUKS devices and can be used in \fIluksOpen\fR, This option is only relevant for LUKS devices and can be used in \fIluksFormat\fR,
\fIluksSuspend\fR, \fIluksResume\fR and \fIresize\fR commands. \fIluksOpen\fR, \fIluksSuspend\fR, \fIluksResume\fR and \fIresize\fR commands.
If used with \fIluksFormat\fR the \-\-align-payload option is taken
as absolute sector alignment on ciphertext device and can be zero.
For other commands with separated metadata device you have to always specify For other commands with separated metadata device you have to always specify
path to metadata device (not to the ciphertext device). path to metadata device (not to the ciphertext device).

View File

@@ -449,6 +449,7 @@ fail:
static int action_luksFormat(int arg __attribute__((unused))) static int action_luksFormat(int arg __attribute__((unused)))
{ {
int r = -EINVAL, keysize; int r = -EINVAL, keysize;
const char *header_device;
char *msg = NULL, *key = NULL, cipher [MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN]; char *msg = NULL, *key = NULL, cipher [MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
char *password = NULL; char *password = NULL;
size_t passwordLen; size_t passwordLen;
@@ -456,9 +457,13 @@ static int action_luksFormat(int arg __attribute__((unused)))
struct crypt_params_luks1 params = { struct crypt_params_luks1 params = {
.hash = opt_hash ?: DEFAULT_LUKS1_HASH, .hash = opt_hash ?: DEFAULT_LUKS1_HASH,
.data_alignment = opt_align_payload, .data_alignment = opt_align_payload,
.data_device = opt_header_device ? action_argv[0] : NULL,
}; };
if(asprintf(&msg, _("This will overwrite data on %s irrevocably."), action_argv[0]) == -1) { header_device = opt_header_device ?: action_argv[0];
if(asprintf(&msg, _("This will overwrite data on %s irrevocably."),
header_device) == -1) {
log_err(_("memory allocation error in action_luksFormat")); log_err(_("memory allocation error in action_luksFormat"));
r = -ENOMEM; r = -ENOMEM;
goto out; goto out;
@@ -475,7 +480,7 @@ static int action_luksFormat(int arg __attribute__((unused)))
goto out; goto out;
} }
if ((r = crypt_init(&cd, action_argv[0]))) if ((r = crypt_init(&cd, header_device)))
goto out; goto out;
keysize = (opt_key_size ?: DEFAULT_LUKS1_KEYBITS) / 8; keysize = (opt_key_size ?: DEFAULT_LUKS1_KEYBITS) / 8;
@@ -543,6 +548,12 @@ static int action_luksOpen(int arg __attribute__((unused)))
(r = crypt_set_data_device(cd, data_device))) (r = crypt_set_data_device(cd, data_device)))
goto out; goto out;
if (!data_device && (crypt_get_data_offset(cd) < 8)) {
log_err(_("Reduced data offset is allowed only for detached LUKS header.\n"));
r = -EINVAL;
goto out;
}
crypt_set_timeout(cd, opt_timeout); crypt_set_timeout(cd, opt_timeout);
crypt_set_password_retry(cd, opt_tries); crypt_set_password_retry(cd, opt_tries);