Commit f80b506b authored by Milan Broz's avatar Milan Broz

* Allow different data offset setting for detached header.

git-svn-id: https://cryptsetup.googlecode.com/svn/trunk@576 36d66b0a-2a48-0410-832c-cd162a569da5
parent f7f9e291
......@@ -5,6 +5,7 @@
* Support retries and timeout parameters for luksSuspend.
* 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.
* Allow different data offset setting for detached header.
2011-07-07 Milan Broz <mbroz@redhat.com>
* Remove old API functions (all functions using crypt_options).
......
Version 1.4.0:
- Support separation of metadata device
- Wipe device flag
- Support K/M suffixes for align payload (new switch?).
......@@ -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 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_size(const char *device, uint64_t *size);
enum devcheck { DEV_OK = 0, DEV_EXCL = 1, DEV_SHARED = 2 };
int device_check_and_adjust(struct crypt_device *cd,
......
......@@ -183,6 +183,7 @@ struct crypt_params_plain {
struct crypt_params_luks1 {
const char *hash; /* hash used in LUKS header */
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 {
......
......@@ -19,8 +19,6 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <errno.h>
......@@ -313,7 +311,6 @@ int LUKS_read_phdr(const char *device,
{
ssize_t hdr_size = sizeof(struct luks_phdr);
int devfd = 0, r = 0;
uint64_t size;
log_dbg("Reading LUKS header of size %d from device %s",
hdr_size, device);
......@@ -329,15 +326,7 @@ int LUKS_read_phdr(const char *device,
else
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);
return r;
}
......@@ -413,6 +402,7 @@ int LUKS_generate_phdr(struct luks_phdr *header,
unsigned int alignOffset,
uint32_t iteration_time_ms,
uint64_t *PBKDF2_per_sec,
const char *metadata_device,
struct crypt_device *ctx)
{
unsigned int i=0;
......@@ -422,7 +412,8 @@ int LUKS_generate_phdr(struct luks_phdr *header,
int currentSector;
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;
if (PBKDF2_HMAC_ready(hashSpec) < 0) {
......@@ -486,10 +477,15 @@ int LUKS_generate_phdr(struct luks_phdr *header,
currentSector = round_up_modulo(currentSector + blocksPerStripeSet,
LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE);
}
currentSector = round_up_modulo(currentSector, alignPayload);
/* alignOffset - offset from natural device alignment provided by topology info */
header->payloadOffset = currentSector + alignOffset;
if (metadata_device) {
/* 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);
......
......@@ -88,6 +88,7 @@ int LUKS_generate_phdr(
unsigned int alignOffset,
uint32_t iteration_time_ms,
uint64_t *PBKDF2_per_sec,
const char *metadata_device,
struct crypt_device *ctx);
int LUKS_read_phdr(
......
......@@ -476,6 +476,27 @@ bad:
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)
{
char *data_device;
......@@ -506,7 +527,7 @@ int crypt_set_data_device(struct crypt_device *cd, const char *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,
......@@ -707,10 +728,14 @@ static int _crypt_format_luks1(struct crypt_device *cd,
if(!cd->volume_key)
return -ENOMEM;
//FIXME: external metadata, ignore alignment
if (params && params->data_alignment)
if (params && params->data_device) {
cd->metadata_device = cd->device;
if (!(cd->device = strdup(params->data_device)))
return -ENOMEM;
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,
&alignment_offset, DEFAULT_DISK_ALIGNMENT);
......@@ -719,7 +744,8 @@ static int _crypt_format_luks1(struct crypt_device *cd,
uuid, LUKS_STRIPES,
required_alignment / 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)
return r;
......@@ -839,14 +865,18 @@ int crypt_load(struct crypt_device *cd,
return r;
r = LUKS_read_phdr(mdata_device(cd), &hdr, 1, cd);
if (r < 0)
return r;
if (!r) {
memcpy(&cd->hdr, &hdr, sizeof(hdr));
free(cd->type);
cd->type = strdup(CRYPT_LUKS1);
if (!cd->type)
r = -ENOMEM;
}
r = crypt_check_data_device_size(cd);
if (r < 0)
return r;
memcpy(&cd->hdr, &hdr, sizeof(hdr));
free(cd->type);
cd->type = strdup(CRYPT_LUKS1);
if (!cd->type)
r = -ENOMEM;
return r;
}
......
......@@ -336,6 +336,21 @@ int device_ready(struct crypt_device *cd, const char *device, int mode)
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,
int *readonly, uint64_t *size)
{
......
......@@ -357,6 +357,9 @@ If not specified, cryptsetup tries to use topology info provided by kernel
for underlying device to get optimal alignment.
If not available (or calculated value is multiple of default) data is by
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
.B "\-\-uuid=\fIUUID\fR"
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 option is only relevant for LUKS devices and can be used in \fIluksOpen\fR,
\fIluksSuspend\fR, \fIluksResume\fR and \fIresize\fR commands.
This option is only relevant for LUKS devices and can be used in \fIluksFormat\fR,
\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
path to metadata device (not to the ciphertext device).
......
......@@ -449,6 +449,7 @@ fail:
static int action_luksFormat(int arg __attribute__((unused)))
{
int r = -EINVAL, keysize;
const char *header_device;
char *msg = NULL, *key = NULL, cipher [MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
char *password = NULL;
size_t passwordLen;
......@@ -456,9 +457,13 @@ static int action_luksFormat(int arg __attribute__((unused)))
struct crypt_params_luks1 params = {
.hash = opt_hash ?: DEFAULT_LUKS1_HASH,
.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"));
r = -ENOMEM;
goto out;
......@@ -475,7 +480,7 @@ static int action_luksFormat(int arg __attribute__((unused)))
goto out;
}
if ((r = crypt_init(&cd, action_argv[0])))
if ((r = crypt_init(&cd, header_device)))
goto out;
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)))
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_password_retry(cd, opt_tries);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment