summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMilan Broz <gmazyland@gmail.com>2013-06-30 10:46:21 +0200
committerMilan Broz <gmazyland@gmail.com>2013-06-30 10:46:21 +0200
commit3be96efe0b6f37ad5ce93398ebf768dd614b89bd (patch)
tree5cf03a26e940c204613f8211c01caac22da5887e
parent99a2486b09889e7d381d045c9ab9eccde1dd1d29 (diff)
downloadcryptsetup-3be96efe0b6f37ad5ce93398ebf768dd614b89bd.tar.gz
cryptsetup-3be96efe0b6f37ad5ce93398ebf768dd614b89bd.tar.bz2
cryptsetup-3be96efe0b6f37ad5ce93398ebf768dd614b89bd.zip
Map TCRYPT system encryption through partition.
Kernel doesn't allow mapping through whle device if some other partition an the device is used. So first try to find partition device which match system encryption (== TCRYPT partition system encryption) and use that.
-rw-r--r--lib/internal.h1
-rw-r--r--lib/tcrypt/tcrypt.c16
-rw-r--r--lib/utils_devpath.c102
3 files changed, 111 insertions, 8 deletions
diff --git a/lib/internal.h b/lib/internal.h
index e403db4..565260f 100644
--- a/lib/internal.h
+++ b/lib/internal.h
@@ -94,6 +94,7 @@ int crypt_confirm(struct crypt_device *cd, const char *msg);
char *crypt_lookup_dev(const char *dev_id);
int crypt_dev_is_rotational(int major, int minor);
int crypt_dev_is_partition(const char *dev_path);
+char *crypt_get_partition_device(const char *dev_path, uint64_t offset, uint64_t size);
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);
diff --git a/lib/tcrypt/tcrypt.c b/lib/tcrypt/tcrypt.c
index 70449a6..128e10b 100644
--- a/lib/tcrypt/tcrypt.c
+++ b/lib/tcrypt/tcrypt.c
@@ -641,7 +641,8 @@ int TCRYPT_activate(struct crypt_device *cd,
uint32_t flags)
{
char cipher[MAX_CIPHER_LEN], dm_name[PATH_MAX], dm_dev_name[PATH_MAX];
- struct device *device = NULL;
+ char *part_path;
+ struct device *device = NULL, *part_device = NULL;
unsigned int i;
int r;
struct tcrypt_algs *algs;
@@ -693,6 +694,18 @@ int TCRYPT_activate(struct crypt_device *cd,
else
device_check = DEV_EXCL;
+ if ((params->flags & CRYPT_TCRYPT_SYSTEM_HEADER) &&
+ (part_path = crypt_get_partition_device(device_path(dmd.data_device),
+ dmd.u.crypt.offset, dmd.size))) {
+ if (!device_alloc(&part_device, part_path)) {
+ log_verbose(cd, _("Activating TCRYPT system encryption for partition %s.\n"),
+ part_path);
+ dmd.data_device = part_device;
+ dmd.u.crypt.offset = 0;
+ }
+ free(part_path);
+ }
+
r = device_block_adjust(cd, dmd.data_device, device_check,
dmd.u.crypt.offset, &dmd.size, &dmd.flags);
if (r)
@@ -744,6 +757,7 @@ int TCRYPT_activate(struct crypt_device *cd,
r = -ENOTSUP;
}
+ device_free(part_device);
crypt_free_volume_key(dmd.u.crypt.vk);
return r;
}
diff --git a/lib/utils_devpath.c b/lib/utils_devpath.c
index 36b6638..7007f18 100644
--- a/lib/utils_devpath.c
+++ b/lib/utils_devpath.c
@@ -170,16 +170,12 @@ char *crypt_lookup_dev(const char *dev_id)
return devpath;
}
-static int _sysfs_get_uint64(int major, int minor, uint64_t *value, const char *attr)
+static int _read_uint64(const char *sysfs_path, uint64_t *value)
{
- char path[PATH_MAX], tmp[64] = {0};
+ char tmp[64] = {0};
int fd, r;
- if (snprintf(path, sizeof(path), "/sys/dev/block/%d:%d/%s",
- major, minor, attr) < 0)
- return 0;
-
- if ((fd = open(path, O_RDONLY)) < 0)
+ if ((fd = open(sysfs_path, O_RDONLY)) < 0)
return 0;
r = read(fd, tmp, sizeof(tmp));
close(fd);
@@ -193,6 +189,28 @@ static int _sysfs_get_uint64(int major, int minor, uint64_t *value, const char *
return 1;
}
+static int _sysfs_get_uint64(int major, int minor, uint64_t *value, const char *attr)
+{
+ char path[PATH_MAX];
+
+ if (snprintf(path, sizeof(path), "/sys/dev/block/%d:%d/%s",
+ major, minor, attr) < 0)
+ return 0;
+
+ return _read_uint64(path, value);
+}
+
+static int _path_get_uint64(const char *sysfs_path, uint64_t *value, const char *attr)
+{
+ char path[PATH_MAX];
+
+ if (snprintf(path, sizeof(path), "%s/%s",
+ sysfs_path, attr) < 0)
+ return 0;
+
+ return _read_uint64(path, value);
+}
+
int crypt_dev_is_rotational(int major, int minor)
{
uint64_t val;
@@ -220,3 +238,73 @@ int crypt_dev_is_partition(const char *dev_path)
return val ? 1 : 0;
}
+
+/* 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 link[PATH_MAX], path[PATH_MAX], part_path[PATH_MAX], *devname;
+ char *result = NULL;
+ struct stat st;
+ size_t devname_len;
+ ssize_t len;
+ struct dirent *entry;
+ DIR *dir;
+ uint64_t part_offset, part_size;
+
+ if (stat(dev_path, &st) < 0)
+ return NULL;
+
+ if (!S_ISBLK(st.st_mode))
+ 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++;
+
+ /* DM devices do not use kernel partitions. */
+ if (dm_is_dm_kernel_name(devname))
+ return NULL;
+
+ dir = opendir(path);
+ if (!dir)
+ return NULL;
+
+ devname_len = strlen(devname);
+ while((entry = readdir(dir))) {
+ if (strncmp(entry->d_name, devname, devname_len))
+ continue;
+
+ if (snprintf(part_path, sizeof(part_path), "%s/%s",
+ path, entry->d_name) < 0)
+ continue;
+
+ if (stat(part_path, &st) < 0)
+ continue;
+
+ if (S_ISDIR(st.st_mode)) {
+ if (!_path_get_uint64(part_path, &part_offset, "start") ||
+ !_path_get_uint64(part_path, &part_size, "size"))
+ continue;
+ if (part_offset == offset && part_size == size &&
+ snprintf(part_path, sizeof(part_path), "/dev/%s",
+ entry->d_name) > 0) {
+ result = strdup(part_path);
+ break;
+ }
+ }
+ }
+ closedir(dir);
+
+ return result;
+}