Fix TCRYPT system encryption mapping for multiple partitions.

Since this commit, one can use partition directly as device parameter.

Should fix Issue#183 and Issue#188.
This commit is contained in:
Milan Broz
2013-12-07 23:58:56 +01:00
parent df27f04f61
commit c57071a43a
4 changed files with 129 additions and 29 deletions

View File

@@ -95,6 +95,8 @@ char *crypt_lookup_dev(const char *dev_id);
int crypt_dev_is_rotational(int major, int minor); int crypt_dev_is_rotational(int major, int minor);
int crypt_dev_is_partition(const char *dev_path); int crypt_dev_is_partition(const char *dev_path);
char *crypt_get_partition_device(const char *dev_path, uint64_t offset, uint64_t size); char *crypt_get_partition_device(const char *dev_path, uint64_t offset, uint64_t size);
char *crypt_get_base_device(const char *dev_path);
uint64_t crypt_dev_partition_offset(const char *dev_path);
ssize_t write_blockwise(int fd, int bsize, void *buf, size_t count); ssize_t write_blockwise(int fd, int bsize, void *buf, size_t count);
ssize_t read_blockwise(int fd, int bsize, void *_buf, size_t count); ssize_t read_blockwise(int fd, int bsize, void *_buf, size_t count);

View File

@@ -573,8 +573,9 @@ int TCRYPT_read_phdr(struct crypt_device *cd,
struct tcrypt_phdr *hdr, struct tcrypt_phdr *hdr,
struct crypt_params_tcrypt *params) struct crypt_params_tcrypt *params)
{ {
struct device *device = crypt_metadata_device(cd); struct device *base_device, *device = crypt_metadata_device(cd);
ssize_t hdr_size = sizeof(struct tcrypt_phdr); ssize_t hdr_size = sizeof(struct tcrypt_phdr);
char *base_device_path;
int devfd = 0, r, bs; int devfd = 0, r, bs;
assert(sizeof(struct tcrypt_phdr) == 512); assert(sizeof(struct tcrypt_phdr) == 512);
@@ -586,7 +587,23 @@ int TCRYPT_read_phdr(struct crypt_device *cd,
if (bs < 0) if (bs < 0)
return bs; return bs;
if (params->flags & CRYPT_TCRYPT_SYSTEM_HEADER &&
crypt_dev_is_partition(device_path(device))) {
base_device_path = crypt_get_base_device(device_path(device));
log_dbg("Reading TCRYPT system header from device %s.", base_device_path ?: "?");
if (!base_device_path)
return -EINVAL;
r = device_alloc(&base_device, base_device_path);
if (r < 0)
return r;
devfd = device_open(base_device, O_RDONLY);
free(base_device_path);
device_free(base_device);
} else
devfd = device_open(device, O_RDONLY); devfd = device_open(device, O_RDONLY);
if (devfd == -1) { if (devfd == -1) {
log_err(cd, _("Cannot open device %s.\n"), device_path(device)); log_err(cd, _("Cannot open device %s.\n"), device_path(device));
return -EINVAL; return -EINVAL;
@@ -694,25 +711,23 @@ int TCRYPT_activate(struct crypt_device *cd,
if (!algs) if (!algs)
return -EINVAL; return -EINVAL;
if (params->flags & CRYPT_TCRYPT_HIDDEN_HEADER) if (params->flags & CRYPT_TCRYPT_SYSTEM_HEADER)
dmd.size = 0;
else if (params->flags & CRYPT_TCRYPT_HIDDEN_HEADER)
dmd.size = hdr->d.hidden_volume_size / hdr->d.sector_size; dmd.size = hdr->d.hidden_volume_size / hdr->d.sector_size;
else else
dmd.size = hdr->d.volume_size / hdr->d.sector_size; dmd.size = hdr->d.volume_size / hdr->d.sector_size;
/* if (dmd.flags & CRYPT_ACTIVATE_SHARED)
* System encryption use the whole device mapping, there can
* be active partitions.
* FIXME: This will allow multiple mappings unexpectedly.
*/
if ((dmd.flags & CRYPT_ACTIVATE_SHARED) ||
(params->flags & CRYPT_TCRYPT_SYSTEM_HEADER))
device_check = DEV_SHARED; device_check = DEV_SHARED;
else else
device_check = DEV_EXCL; device_check = DEV_EXCL;
if ((params->flags & CRYPT_TCRYPT_SYSTEM_HEADER) && if ((params->flags & CRYPT_TCRYPT_SYSTEM_HEADER) &&
(part_path = crypt_get_partition_device(device_path(dmd.data_device), !crypt_dev_is_partition(device_path(dmd.data_device))) {
dmd.u.crypt.offset, dmd.size))) { part_path = crypt_get_partition_device(device_path(dmd.data_device),
dmd.u.crypt.offset, dmd.size);
if (part_path) {
if (!device_alloc(&part_device, part_path)) { if (!device_alloc(&part_device, part_path)) {
log_verbose(cd, _("Activating TCRYPT system encryption for partition %s.\n"), log_verbose(cd, _("Activating TCRYPT system encryption for partition %s.\n"),
part_path); part_path);
@@ -720,6 +735,12 @@ int TCRYPT_activate(struct crypt_device *cd,
dmd.u.crypt.offset = 0; dmd.u.crypt.offset = 0;
} }
free(part_path); free(part_path);
} else
/*
* System encryption use the whole device mapping, there can
* be active partitions.
*/
device_check = DEV_SHARED;
} }
r = device_block_adjust(cd, dmd.data_device, device_check, r = device_block_adjust(cd, dmd.data_device, device_check,
@@ -924,8 +945,11 @@ uint64_t TCRYPT_get_data_offset(struct crypt_device *cd,
goto hdr_offset; goto hdr_offset;
/* Mapping through whole device, not partition! */ /* Mapping through whole device, not partition! */
if (params->flags & CRYPT_TCRYPT_SYSTEM_HEADER) if (params->flags & CRYPT_TCRYPT_SYSTEM_HEADER) {
if (crypt_dev_is_partition(device_path(crypt_metadata_device(cd))))
return 0;
goto hdr_offset; goto hdr_offset;
}
if (params->mode && !strncmp(params->mode, "xts", 3)) { if (params->mode && !strncmp(params->mode, "xts", 3)) {
if (hdr->d.version < 3) if (hdr->d.version < 3)
@@ -955,15 +979,21 @@ hdr_offset:
uint64_t TCRYPT_get_iv_offset(struct crypt_device *cd, uint64_t TCRYPT_get_iv_offset(struct crypt_device *cd,
struct tcrypt_phdr *hdr, struct tcrypt_phdr *hdr,
struct crypt_params_tcrypt *params struct crypt_params_tcrypt *params)
)
{ {
if (params->mode && !strncmp(params->mode, "xts", 3)) uint64_t iv_offset;
return TCRYPT_get_data_offset(cd, hdr, params);
else if (params->mode && !strncmp(params->mode, "lrw", 3))
return 0;
return hdr->d.mk_offset / hdr->d.sector_size; if (params->mode && !strncmp(params->mode, "xts", 3))
iv_offset = TCRYPT_get_data_offset(cd, hdr, params);
else if (params->mode && !strncmp(params->mode, "lrw", 3))
iv_offset = 0;
else
iv_offset = hdr->d.mk_offset / hdr->d.sector_size;
if (params->flags & CRYPT_TCRYPT_SYSTEM_HEADER)
iv_offset += crypt_dev_partition_offset(device_path(crypt_metadata_device(cd)));
return iv_offset;
} }
int TCRYPT_get_volume_key(struct crypt_device *cd, int TCRYPT_get_volume_key(struct crypt_device *cd,

View File

@@ -236,6 +236,24 @@ int crypt_dev_is_partition(const char *dev_path)
return val ? 1 : 0; return val ? 1 : 0;
} }
uint64_t crypt_dev_partition_offset(const char *dev_path)
{
uint64_t val;
struct stat st;
if (!crypt_dev_is_partition(dev_path))
return 0;
if (stat(dev_path, &st) < 0)
return 0;
if (!_sysfs_get_uint64(major(st.st_rdev), minor(st.st_rdev),
&val, "start"))
return 0;
return val;
}
/* Try to find partition which match offset and size on top level device */ /* Try to find partition which match offset and size on top level device */
char *crypt_get_partition_device(const char *dev_path, uint64_t offset, uint64_t size) char *crypt_get_partition_device(const char *dev_path, uint64_t offset, uint64_t size)
{ {
@@ -305,3 +323,42 @@ char *crypt_get_partition_device(const char *dev_path, uint64_t offset, uint64_t
return result; return result;
} }
/* Try to find base device from partition */
char *crypt_get_base_device(const char *dev_path)
{
char link[PATH_MAX], path[PATH_MAX], part_path[PATH_MAX], *devname;
struct stat st;
ssize_t len;
if (!crypt_dev_is_partition(dev_path))
return NULL;
if (stat(dev_path, &st) < 0)
return NULL;
if (snprintf(path, sizeof(path), "/sys/dev/block/%d:%d",
major(st.st_rdev), minor(st.st_rdev)) < 0)
return NULL;
len = readlink(path, link, sizeof(link) - 1);
if (len < 0)
return NULL;
/* Get top level disk name for sysfs search */
link[len] = '\0';
devname = strrchr(link, '/');
if (!devname)
return NULL;
*devname = '\0';
devname = strrchr(link, '/');
if (!devname)
return NULL;
devname++;
if (dm_is_dm_kernel_name(devname))
return NULL;
snprintf(part_path, sizeof(part_path), "/dev/%s", devname);
return strdup(part_path);
}

View File

@@ -423,8 +423,19 @@ The \fBtcryptDump\fR command should work for all recognized TCRYPT devices
and doesn't require superuser privilege. and doesn't require superuser privilege.
To map system device (device with boot loader where the whole encrypted To map system device (device with boot loader where the whole encrypted
system resides) use \fB\-\-tcrypt\-system\fR option. Use the whole system resides) use \fB\-\-tcrypt\-system\fR option.
device not the system partition as the device parameter. You can use partition device as the parameter (parameter must be real partition
device, not image in file), then only this partition is mapped.
If you have whole TCRYPT device as a file image and you want to map multiple
partition encrypted with system encryption, please create loopback mapping
with partitions first (\fBlosetup -P\fR, see \fPlosetup(8)\fR man page for more info),
and use loop partition as the device parameter.
If you use whole base device as parameter, one device for the whole system
encryption is mapped. This mode is available only for backward compatibility
with older cryptsetup versions which mapped TCRYPT system encryption
using whole device.
To use hidden header (and map hidden device, if available), To use hidden header (and map hidden device, if available),
use \fB\-\-tcrypt\-hidden\fR option. use \fB\-\-tcrypt\-hidden\fR option.