Commit 65f97565 authored by Milan Broz's avatar Milan Broz

New device access backend.

Allocate loop device late (only when real block device needed).
Rework underlying device/file access functions.
Move all device (and ioctl) access to utils_device.c.

Allows using file where appropriate without allocation loop device.
parent 0c1efd1f
2012-08-12 Milan Broz <gmazyland@gmail.com>
* Allocate loop device late (only when real block device needed).
* Rework underlying device/file access functions.
2012-07-10 Milan Broz <gmazyland@gmail.com>
* Version 1.5.0.
......
......@@ -59,6 +59,7 @@ libcryptsetup_la_SOURCES = \
utils_wipe.c \
utils_fips.c \
utils_fips.h \
utils_device.c \
libdevmapper.c \
utils_dm.h \
volumekey.c \
......
......@@ -63,29 +63,43 @@ struct volume_key *crypt_alloc_volume_key(unsigned keylength, const char *key);
struct volume_key *crypt_generate_volume_key(struct crypt_device *cd, unsigned keylength);
void crypt_free_volume_key(struct volume_key *vk);
/* Device backend */
struct device;
int device_alloc(struct device **device, const char *path);
void device_free(struct device *device);
const char *device_path(const struct device *device);
const char *device_block_path(const struct device *device);
void device_topology_alignment(struct device *device,
unsigned long *required_alignment, /* bytes */
unsigned long *alignment_offset, /* bytes */
unsigned long default_alignment);
int device_block_size(struct device *device);
int device_read_ahead(struct device *device, uint32_t *read_ahead);
int device_size(struct device *device, uint64_t *size);
enum devcheck { DEV_OK = 0, DEV_EXCL = 1, DEV_SHARED = 2 };
int device_block_adjust(struct crypt_device *cd,
struct device *device,
enum devcheck device_check,
uint64_t device_offset,
uint64_t *size,
uint32_t *flags);
/* Receive backend devices from context helpers */
struct device *crypt_metadata_device(struct crypt_device *cd);
struct device *crypt_data_device(struct crypt_device *cd);
int crypt_confirm(struct crypt_device *cd, const char *msg);
char *crypt_lookup_dev(const char *dev_id);
int crypt_sysfs_check_crypt_segment(const char *device, uint64_t offset, uint64_t size);
int crypt_sysfs_get_rotational(int major, int minor, int *rotational);
int sector_size_for_device(const char *device);
int device_read_ahead(const char *dev, uint32_t *read_ahead);
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);
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 write_lseek_blockwise(int fd, int bsize, char *buf, size_t count, off_t offset);
unsigned crypt_getpagesize(void);
enum devcheck { DEV_OK = 0, DEV_EXCL = 1, DEV_SHARED = 2 };
int device_check_and_adjust(struct crypt_device *cd,
const char *device,
enum devcheck device_check,
uint64_t *size,
uint64_t *offset,
uint32_t *flags);
void logger(struct crypt_device *cd, int class, const char *file, int line, const char *format, ...);
#define log_dbg(x...) logger(NULL, CRYPT_LOG_DEBUG, __FILE__, __LINE__, x)
......@@ -98,11 +112,6 @@ int crypt_get_debug_level(void);
int crypt_memlock_inc(struct crypt_device *ctx);
int crypt_memlock_dec(struct crypt_device *ctx);
void get_topology_alignment(const char *device,
unsigned long *required_alignment, /* bytes */
unsigned long *alignment_offset, /* bytes */
unsigned long default_alignment);
int crypt_random_init(struct crypt_device *ctx);
int crypt_random_get(struct crypt_device *ctx, char *buf, size_t len, int quality);
void crypt_random_exit(void);
......@@ -131,7 +140,7 @@ typedef enum {
* random algorithm */
} crypt_wipe_type;
int crypt_wipe(const char *device,
int crypt_wipe(struct device *device,
uint64_t offset,
uint64_t sectors,
crypt_wipe_type type,
......
......@@ -287,14 +287,16 @@ static char *get_dm_crypt_params(struct crypt_dm_active_device *dmd)
hex_key(hexkey, dmd->u.crypt.vk->keylength, dmd->u.crypt.vk->key);
max_size = strlen(hexkey) + strlen(dmd->u.crypt.cipher) +
strlen(dmd->data_device) + strlen(features) + 64;
strlen(device_block_path(dmd->data_device)) +
strlen(features) + 64;
params = crypt_safe_alloc(max_size);
if (!params)
goto out;
r = snprintf(params, max_size, "%s %s %" PRIu64 " %s %" PRIu64 "%s",
dmd->u.crypt.cipher, hexkey, dmd->u.crypt.iv_offset,
dmd->data_device, dmd->u.crypt.offset, features);
device_block_path(dmd->data_device), dmd->u.crypt.offset,
features);
if (r < 0 || r >= max_size) {
crypt_safe_free(params);
params = NULL;
......@@ -328,8 +330,8 @@ static char *get_dm_verity_params(struct crypt_params_verity *vp,
strncpy(hexsalt, "-", 2);
max_size = strlen(hexroot) + strlen(hexsalt) +
strlen(dmd->data_device) +
strlen(dmd->u.verity.hash_device) +
strlen(device_block_path(dmd->data_device)) +
strlen(device_block_path(dmd->u.verity.hash_device)) +
strlen(vp->hash_name) + 128;
params = crypt_safe_alloc(max_size);
......@@ -338,8 +340,8 @@ static char *get_dm_verity_params(struct crypt_params_verity *vp,
r = snprintf(params, max_size,
"%u %s %s %u %u %" PRIu64 " %" PRIu64 " %s %s %s",
vp->hash_type, dmd->data_device,
dmd->u.verity.hash_device,
vp->hash_type, device_block_path(dmd->data_device),
device_block_path(dmd->u.verity.hash_device),
vp->data_block_size, vp->hash_block_size,
vp->data_size, dmd->u.verity.hash_offset,
vp->hash_name, hexroot, hexsalt);
......@@ -491,7 +493,7 @@ static void dm_prepare_uuid(const char *name, const char *type, const char *uuid
}
static int _dm_create_device(const char *name, const char *type,
const char *device, uint32_t flags,
struct device *device, uint32_t flags,
const char *uuid, uint64_t size,
char *params, int reload)
{
......@@ -708,6 +710,7 @@ static int _dm_query_crypt(uint32_t get_flags,
uint64_t val64;
char *rcipher, *key_, *rdevice, *endp, buffer[3], *arg;
unsigned int i;
int r;
memset(dmd, 0, sizeof(*dmd));
dmd->target = DM_CRYPT;
......@@ -730,8 +733,13 @@ static int _dm_query_crypt(uint32_t get_flags,
/* device */
rdevice = strsep(&params, " ");
if (get_flags & DM_ACTIVE_DEVICE)
dmd->data_device = crypt_lookup_dev(rdevice);
if (get_flags & DM_ACTIVE_DEVICE) {
arg = crypt_lookup_dev(rdevice);
r = device_alloc(&dmd->data_device, arg);
free(arg);
if (r < 0 && r != -ENOTBLK)
return r;
}
/*offset */
if (!params)
......@@ -805,6 +813,7 @@ static int _dm_query_verity(uint32_t get_flags,
uint64_t val64;
ssize_t len;
char *str, *str2;
int r;
if (get_flags & DM_ACTIVE_VERITY_PARAMS)
vp = dmd->u.verity.vp;
......@@ -826,15 +835,25 @@ static int _dm_query_verity(uint32_t get_flags,
str = strsep(&params, " ");
if (!params)
return -EINVAL;
if (get_flags & DM_ACTIVE_DEVICE)
dmd->data_device = crypt_lookup_dev(str);
if (get_flags & DM_ACTIVE_DEVICE) {
str2 = crypt_lookup_dev(str);
r = device_alloc(&dmd->data_device, str2);
free(str2);
if (r < 0 && r != -ENOTBLK)
return r;
}
/* hash device */
str = strsep(&params, " ");
if (!params)
return -EINVAL;
if (get_flags & DM_ACTIVE_VERITY_HASH_DEVICE)
dmd->u.verity.hash_device = crypt_lookup_dev(str);
if (get_flags & DM_ACTIVE_VERITY_HASH_DEVICE) {
str2 = crypt_lookup_dev(str);
r = device_alloc(&dmd->u.verity.hash_device, str2);
free(str2);
if (r < 0 && r != -ENOTBLK)
return r;
}
/* data block size*/
val32 = strtoul(params, &params, 10);
......@@ -1072,27 +1091,3 @@ int dm_is_dm_kernel_name(const char *name)
{
return strncmp(name, "dm-", 3) ? 0 : 1;
}
int dm_check_segment(const char *name, uint64_t offset, uint64_t size)
{
struct crypt_dm_active_device dmd;
int r;
log_dbg("Checking segments for device %s.", name);
r = dm_query_device(name, 0, &dmd);
if (r < 0)
return r;
if (offset >= (dmd.u.crypt.offset + dmd.size) ||
(offset + size) <= dmd.u.crypt.offset)
r = 0;
else
r = -EBUSY;
log_dbg("seg: %" PRIu64 " - %" PRIu64 ", new %" PRIu64 " - %" PRIu64 "%s",
dmd.u.crypt.offset, dmd.u.crypt.offset + dmd.size, offset, offset + size,
r ? " (overlapping)" : " (ok)");
return r;
}
......@@ -196,7 +196,7 @@ int LOOPAES_activate(struct crypt_device *cd,
.uuid = crypt_get_uuid(cd),
.size = 0,
.flags = flags,
.data_device = crypt_get_device_name(cd),
.data_device = crypt_data_device(cd),
.u.crypt = {
.cipher = NULL,
.vk = vk,
......@@ -205,9 +205,8 @@ int LOOPAES_activate(struct crypt_device *cd,
}
};
r = device_check_and_adjust(cd, dmd.data_device, DEV_EXCL,
&dmd.size, &dmd.u.crypt.offset, &flags);
r = device_block_adjust(cd, dmd.data_device, DEV_EXCL,
dmd.u.crypt.offset, &dmd.size, &dmd.flags);
if (r)
return r;
......
......@@ -51,17 +51,16 @@ static uint64_t cleaner_size = 0;
static int devfd=-1;
static int setup_mapping(const char *cipher, const char *name,
const char *device,
struct volume_key *vk,
int bsize, struct volume_key *vk,
unsigned int sector, size_t srcLength,
int mode, struct crypt_device *ctx)
{
int device_sector_size = sector_size_for_device(device);
struct device *device = crypt_metadata_device(ctx);
struct crypt_dm_active_device dmd = {
.target = DM_CRYPT,
.uuid = NULL,
.size = 0,
.flags = 0,
.size = round_up_modulo(srcLength, bsize) / SECTOR_SIZE,
.flags = CRYPT_ACTIVATE_PRIVATE,
.data_device = device,
.u.crypt = {
.cipher = cipher,
......@@ -70,22 +69,17 @@ static int setup_mapping(const char *cipher, const char *name,
.iv_offset = 0,
}
};
int r;
dmd.flags = CRYPT_ACTIVATE_PRIVATE;
if (mode == O_RDONLY)
dmd.flags |= CRYPT_ACTIVATE_READONLY;
/*
* we need to round this to nearest multiple of the underlying
* device's sector size, otherwise the mapping will be refused.
*/
if(device_sector_size < 0) {
log_err(ctx, _("Unable to obtain sector size for %s"), device);
return -EINVAL;
}
dmd.size = round_up_modulo(srcLength,device_sector_size)/SECTOR_SIZE;
cleaner_size = dmd.size;
r = device_block_adjust(ctx, dmd.data_device, DEV_OK,
dmd.u.crypt.offset, &dmd.size, &dmd.flags);
if (r < 0)
return r;
cleaner_size = dmd.size;
return dm_create_device(name, "TEMP", &dmd, 0);
}
......@@ -116,9 +110,8 @@ static const char *_error_hint(char *cipherMode, size_t keyLength)
static int LUKS_endec_template(char *src, size_t srcLength,
struct luks_phdr *hdr,
struct volume_key *vk,
const char *device,
unsigned int sector,
ssize_t (*func)(int, void *, size_t),
ssize_t (*func)(int, int, void *, size_t),
int mode,
struct crypt_device *ctx)
{
......@@ -127,6 +120,7 @@ static int LUKS_endec_template(char *src, size_t srcLength,
char *dmCipherSpec = NULL;
const char *dmDir = dm_get_dir();
int r = -1;
int bsize = device_block_size(crypt_metadata_device(ctx));
if(dmDir == NULL) {
log_err(ctx, _("Failed to obtain device mapper directory."));
......@@ -142,12 +136,11 @@ static int LUKS_endec_template(char *src, size_t srcLength,
signal(SIGINT, sigint_handler);
cleaner_name = name;
r = setup_mapping(dmCipherSpec, name, device,
vk, sector, srcLength, mode, ctx);
r = setup_mapping(dmCipherSpec, name, bsize, vk, sector, srcLength, mode, ctx);
if(r < 0) {
log_err(ctx, _("Failed to setup dm-crypt key mapping for device %s.\n"
"Check that kernel supports %s cipher (check syslog for more info).\n%s"),
device, dmCipherSpec,
device_path(crypt_metadata_device(ctx)), dmCipherSpec,
_error_hint(hdr->cipherMode, vk->keylength * 8));
r = -EIO;
goto out1;
......@@ -160,7 +153,7 @@ static int LUKS_endec_template(char *src, size_t srcLength,
goto out2;
}
r = func(devfd,src,srcLength);
r = func(devfd, bsize, src, srcLength);
if(r < 0) {
log_err(ctx, _("Failed to access temporary keystore device.\n"));
r = -EIO;
......@@ -186,21 +179,19 @@ static int LUKS_endec_template(char *src, size_t srcLength,
int LUKS_encrypt_to_storage(char *src, size_t srcLength,
struct luks_phdr *hdr,
struct volume_key *vk,
const char *device,
unsigned int sector,
struct crypt_device *ctx)
{
return LUKS_endec_template(src,srcLength,hdr,vk, device,
sector, write_blockwise, O_RDWR, ctx);
return LUKS_endec_template(src, srcLength, hdr, vk, sector,
write_blockwise, O_RDWR, ctx);
}
int LUKS_decrypt_from_storage(char *dst, size_t dstLength,
struct luks_phdr *hdr,
struct volume_key *vk,
const char *device,
unsigned int sector,
struct crypt_device *ctx)
{
return LUKS_endec_template(dst,dstLength,hdr,vk, device,
sector, read_blockwise, O_RDONLY, ctx);
return LUKS_endec_template(dst, dstLength, hdr, vk, sector,
read_blockwise, O_RDONLY, ctx);
}
This diff is collapsed.
......@@ -63,6 +63,7 @@
converted */
struct volume_key;
struct device_backend;
struct luks_phdr {
char magic[LUKS_MAGIC_L];
......@@ -108,11 +109,10 @@ int LUKS_generate_phdr(
unsigned int alignOffset,
uint32_t iteration_time_ms,
uint64_t *PBKDF2_per_sec,
const char *metadata_device,
int detached_metadata_device,
struct crypt_device *ctx);
int LUKS_read_phdr(
const char *device,
struct luks_phdr *hdr,
int require_luks_device,
int repair,
......@@ -120,36 +120,30 @@ int LUKS_read_phdr(
int LUKS_read_phdr_backup(
const char *backup_file,
const char *device,
struct luks_phdr *hdr,
int require_luks_device,
struct crypt_device *ctx);
int LUKS_hdr_uuid_set(
const char *device,
struct luks_phdr *hdr,
const char *uuid,
struct crypt_device *ctx);
int LUKS_hdr_backup(
const char *backup_file,
const char *device,
struct luks_phdr *hdr,
struct crypt_device *ctx);
int LUKS_hdr_restore(
const char *backup_file,
const char *device,
struct luks_phdr *hdr,
struct crypt_device *ctx);
int LUKS_write_phdr(
const char *device,
struct luks_phdr *hdr,
struct crypt_device *ctx);
int LUKS_set_key(
const char *device,
unsigned int keyIndex,
const char *password,
size_t passwordLen,
......@@ -160,7 +154,6 @@ int LUKS_set_key(
struct crypt_device *ctx);
int LUKS_open_key_with_hdr(
const char *device,
int keyIndex,
const char *password,
size_t passwordLen,
......@@ -169,7 +162,6 @@ int LUKS_open_key_with_hdr(
struct crypt_device *ctx);
int LUKS_del_key(
const char *device,
unsigned int keyIndex,
struct luks_phdr *hdr,
struct crypt_device *ctx);
......@@ -183,7 +175,6 @@ int LUKS_encrypt_to_storage(
char *src, size_t srcLength,
struct luks_phdr *hdr,
struct volume_key *vk,
const char *device,
unsigned int sector,
struct crypt_device *ctx);
......@@ -191,7 +182,6 @@ int LUKS_decrypt_from_storage(
char *dst, size_t dstLength,
struct luks_phdr *hdr,
struct volume_key *vk,
const char *device,
unsigned int sector,
struct crypt_device *ctx);
......
This diff is collapsed.
......@@ -22,20 +22,10 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdarg.h>
#include <errno.h>
#include <linux/fs.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include "libcryptsetup.h"
#include "internal.h"
unsigned crypt_getpagesize(void)
......@@ -74,52 +64,15 @@ static void *aligned_malloc(void **base, int size, int alignment)
#endif
}
int device_read_ahead(const char *dev, uint32_t *read_ahead)
{
int fd, r = 0;
long read_ahead_long;
if ((fd = open(dev, O_RDONLY)) < 0)
return 0;
r = ioctl(fd, BLKRAGET, &read_ahead_long) ? 0 : 1;
close(fd);
if (r)
*read_ahead = (uint32_t) read_ahead_long;
return r;
}
static int sector_size(int fd)
{
int bsize;
if (ioctl(fd,BLKSSZGET, &bsize) < 0)
return -EINVAL;
else
return bsize;
}
int sector_size_for_device(const char *device)
{
int fd = open(device, O_RDONLY);
int r;
if(fd < 0)
return -EINVAL;
r = sector_size(fd);
close(fd);
return r;
}
ssize_t write_blockwise(int fd, void *orig_buf, size_t count)
ssize_t write_blockwise(int fd, int bsize, void *orig_buf, size_t count)
{
void *hangover_buf, *hangover_buf_base = NULL;
void *buf, *buf_base = NULL;
int r, hangover, solid, bsize, alignment;
int r, hangover, solid, alignment;
ssize_t ret = -1;
if ((bsize = sector_size(fd)) < 0)
return bsize;
if (fd == -1 || !orig_buf || bsize <= 0)
return -1;
hangover = count % bsize;
solid = count - hangover;
......@@ -163,14 +116,14 @@ out:
return ret;
}
ssize_t read_blockwise(int fd, void *orig_buf, size_t count) {
ssize_t read_blockwise(int fd, int bsize, void *orig_buf, size_t count) {
void *hangover_buf, *hangover_buf_base = NULL;
void *buf, *buf_base = NULL;
int r, hangover, solid, bsize, alignment;
int r, hangover, solid, alignment;
ssize_t ret = -1;
if ((bsize = sector_size(fd)) < 0)
return bsize;
if (fd == -1 || !orig_buf || bsize <= 0)
return -1;
hangover = count % bsize;
solid = count - hangover;
......@@ -213,15 +166,15 @@ out:
* is implicitly included in the read/write offset, which can not be set to non-aligned
* boundaries. Hence, we combine llseek with write.
*/
ssize_t write_lseek_blockwise(int fd, char *buf, size_t count, off_t offset) {
ssize_t write_lseek_blockwise(int fd, int bsize, char *buf, size_t count, off_t offset) {
char *frontPadBuf;
void *frontPadBuf_base = NULL;
int r, bsize, frontHang;
int r, frontHang;
size_t innerCount = 0;
ssize_t ret = -1;
if ((bsize = sector_size(fd)) < 0)
return bsize;
if (fd == -1 || !buf || bsize <= 0)
return -1;
frontHang = offset % bsize;
......@@ -255,7 +208,7 @@ ssize_t write_lseek_blockwise(int fd, char *buf, size_t count, off_t offset) {
count -= innerCount;
}
ret = count ? write_blockwise(fd, buf, count) : 0;
ret = count ? write_blockwise(fd, bsize, buf, count) : 0;
if (ret >= 0)
ret += innerCount;
out:
......@@ -264,171 +217,6 @@ out:
return ret;
}
int device_ready(struct crypt_device *cd, const char *device, int mode)
{
int devfd, r = 0;
ssize_t s;
struct stat st;
char buf[512];
if(stat(device, &st) < 0) {
log_err(cd, _("Device %s doesn't exist or access denied.\n"), device);
return -EINVAL;
}
if (!S_ISBLK(st.st_mode))
return -ENOTBLK;
log_dbg("Trying to open and read device %s.", device);
devfd = open(device, mode | O_DIRECT | O_SYNC);
if(devfd < 0) {
log_err(cd, _("Cannot open device %s for %s%s access.\n"), device,
(mode & O_EXCL) ? _("exclusive ") : "",
(mode & O_RDWR) ? _("writable") : _("read-only"));
return -EINVAL;
}
/* Try to read first sector */
s = read_blockwise(devfd, buf, sizeof(buf));
if (s < 0 || s != sizeof(buf)) {
log_verbose(cd, _("Cannot read device %s.\n"), device);
r = -EIO;
}
memset(buf, 0, sizeof(buf));
close(devfd);
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)
{
struct stat st;
unsigned long size_small;
int fd, r = -1;
int flags = 0;
*readonly = 0;
*size = 0;
if (stat(device, &st) < 0)
return -EINVAL;
/* never wipe header on mounted device */
if (device_check == DEV_EXCL && S_ISBLK(st.st_mode))
flags |= O_EXCL;
/* Try to open read-write to check whether it is a read-only device */
fd = open(device, O_RDWR | flags);
if (fd == -1 && errno == EROFS) {
*readonly = 1;
fd = open(device, O_RDONLY | flags);
}
if (fd == -1 && device_check == DEV_EXCL && errno == EBUSY)
return -EBUSY;
if (fd == -1)
return -EINVAL;
/* If the device can be opened read-write, i.e. readonly is still 0, then
* check whether BKROGET says that it is read-only. E.g. read-only loop
* devices may be openend read-write but are read-only according to BLKROGET
*/
if (*readonly == 0 && (r = ioctl(fd, BLKROGET, readonly)) < 0)
goto out;
if (ioctl(fd, BLKGETSIZE64, size) >= 0) {
*size >>= SECTOR_SHIFT;
r = 0;
goto out;
}
if (ioctl(fd, BLKGETSIZE, &size_small) >= 0) {
*size = (uint64_t)size_small;
r = 0;
goto out;
}
r = -EINVAL;
out:
close(fd);
return r;
}
int device_check_and_adjust(struct crypt_device *cd,
const char *device,
enum devcheck device_check,
uint64_t *size,
uint64_t *offset,
uint32_t *flags)
{
int r, real_readonly;
uint64_t real_size;
if (!device)
return -ENOTBLK;
r = get_device_infos(device, device_check, &real_readonly, &real_size);
if (r < 0) {
if (r == -EBUSY)
log_err(cd, _("Cannot use device %s which is in use "
"(already mapped or mounted).\n"),
device);
else
log_err(cd, _("Cannot get info about device %s.\n"),
device);
return r;
}
if (*offset >= real_size) {
log_err(cd, _("Requested offset is beyond real size of device %s.\n"),
device);
return -EINVAL;
}
if (!*size) {