mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-13 20:00:08 +01:00
Check various number limits.
This commit is contained in:
33
lib/setup.c
33
lib/setup.c
@@ -70,7 +70,7 @@ struct crypt_device {
|
|||||||
/* used in CRYPT_VERITY */
|
/* used in CRYPT_VERITY */
|
||||||
struct crypt_params_verity verity_hdr;
|
struct crypt_params_verity verity_hdr;
|
||||||
char *verity_root_hash;
|
char *verity_root_hash;
|
||||||
uint64_t verity_root_hash_size;
|
unsigned int verity_root_hash_size;
|
||||||
char *verity_uuid;
|
char *verity_uuid;
|
||||||
|
|
||||||
/* callbacks definitions */
|
/* callbacks definitions */
|
||||||
@@ -689,7 +689,10 @@ static int _crypt_load_verity(struct crypt_device *cd, struct crypt_params_verit
|
|||||||
(r = crypt_set_data_device(cd, params->data_device)) < 0)
|
(r = crypt_set_data_device(cd, params->data_device)) < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
/* Hash availability checked in sb load */
|
||||||
cd->verity_root_hash_size = crypt_hash_size(cd->verity_hdr.hash_name);
|
cd->verity_root_hash_size = crypt_hash_size(cd->verity_hdr.hash_name);
|
||||||
|
if (cd->verity_root_hash_size > 4096)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
if (!cd->type && !(cd->type = strdup(CRYPT_VERITY)))
|
if (!cd->type && !(cd->type = strdup(CRYPT_VERITY)))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@@ -1046,7 +1049,7 @@ static int _crypt_format_verity(struct crypt_device *cd,
|
|||||||
const char *uuid,
|
const char *uuid,
|
||||||
struct crypt_params_verity *params)
|
struct crypt_params_verity *params)
|
||||||
{
|
{
|
||||||
int r = 0;
|
int r = 0, hash_size;
|
||||||
uint64_t data_device_size;
|
uint64_t data_device_size;
|
||||||
|
|
||||||
if (!mdata_device(cd)) {
|
if (!mdata_device(cd)) {
|
||||||
@@ -1057,6 +1060,22 @@ static int _crypt_format_verity(struct crypt_device *cd,
|
|||||||
if (!params || !params->data_device)
|
if (!params || !params->data_device)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (params->hash_type > VERITY_MAX_HASH_TYPE) {
|
||||||
|
log_err(cd, _("Unsupported VERITY hash type %d.\n"), params->hash_type);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VERITY_BLOCK_SIZE_OK(params->data_block_size) ||
|
||||||
|
VERITY_BLOCK_SIZE_OK(params->hash_block_size)) {
|
||||||
|
log_err(cd, _("Unsupported VERITY block size.\n"));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params->hash_area_offset % 512) {
|
||||||
|
log_err(cd, _("Unsupported VERITY hash offset.\n"));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(cd->type = strdup(CRYPT_VERITY)))
|
if (!(cd->type = strdup(CRYPT_VERITY)))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
@@ -1064,7 +1083,7 @@ static int _crypt_format_verity(struct crypt_device *cd,
|
|||||||
if (r)
|
if (r)
|
||||||
return r;
|
return r;
|
||||||
if (!params->data_size) {
|
if (!params->data_size) {
|
||||||
r = device_size(params->data_device, &data_device_size);
|
r = device_size(cd->device, &data_device_size);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@@ -1072,9 +1091,13 @@ static int _crypt_format_verity(struct crypt_device *cd,
|
|||||||
} else
|
} else
|
||||||
cd->verity_hdr.data_size = params->data_size;
|
cd->verity_hdr.data_size = params->data_size;
|
||||||
|
|
||||||
cd->verity_root_hash_size = crypt_hash_size(params->hash_name);
|
hash_size = crypt_hash_size(params->hash_name);
|
||||||
if (!cd->verity_root_hash_size)
|
if (hash_size <= 0) {
|
||||||
|
log_err(cd, _("Hash algorithm %s not supported.\n"),
|
||||||
|
params->hash_name);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
cd->verity_root_hash_size = hash_size;
|
||||||
|
|
||||||
cd->verity_root_hash = malloc(cd->verity_root_hash_size);
|
cd->verity_root_hash = malloc(cd->verity_root_hash_size);
|
||||||
if (!cd->verity_root_hash)
|
if (!cd->verity_root_hash)
|
||||||
|
|||||||
@@ -88,6 +88,11 @@ int VERITY_read_sb(struct crypt_device *cd,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sb_offset % 512) {
|
||||||
|
log_err(cd, _("Unsupported VERITY hash offset.\n"));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
devfd = open(device ,O_RDONLY | O_DIRECT);
|
devfd = open(device ,O_RDONLY | O_DIRECT);
|
||||||
if(devfd == -1) {
|
if(devfd == -1) {
|
||||||
log_err(cd, _("Cannot open device %s.\n"), device);
|
log_err(cd, _("Cannot open device %s.\n"), device);
|
||||||
@@ -141,14 +146,15 @@ int VERITY_read_sb(struct crypt_device *cd,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
params->hash_type = le32_to_cpu(sb.hash_type);
|
params->hash_type = le32_to_cpu(sb.hash_type);
|
||||||
if (params->hash_type > 1) {
|
if (params->hash_type > VERITY_MAX_HASH_TYPE) {
|
||||||
log_err(cd, _("Unsupported VERITY hash type %d.\n"), params->hash_type);
|
log_err(cd, _("Unsupported VERITY hash type %d.\n"), params->hash_type);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
params->data_block_size = le64_to_cpu(sb.data_block_size);
|
params->data_block_size = le64_to_cpu(sb.data_block_size);
|
||||||
params->hash_block_size = le64_to_cpu(sb.hash_block_size);
|
params->hash_block_size = le64_to_cpu(sb.hash_block_size);
|
||||||
if (params->data_block_size % 512 || params->hash_block_size % 512) {
|
if (VERITY_BLOCK_SIZE_OK(params->data_block_size) ||
|
||||||
|
VERITY_BLOCK_SIZE_OK(params->hash_block_size)) {
|
||||||
log_err(cd, _("Unsupported VERITY block size.\n"));
|
log_err(cd, _("Unsupported VERITY block size.\n"));
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@@ -157,6 +163,12 @@ int VERITY_read_sb(struct crypt_device *cd,
|
|||||||
params->hash_name = strndup((const char*)sb.algorithm, sizeof(sb.algorithm));
|
params->hash_name = strndup((const char*)sb.algorithm, sizeof(sb.algorithm));
|
||||||
if (!params->hash_name)
|
if (!params->hash_name)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
if (crypt_hash_size(params->hash_name) <= 0) {
|
||||||
|
log_err(cd, _("Hash algorithm %s not supported.\n"),
|
||||||
|
params->hash_name);
|
||||||
|
free(CONST_CAST(char*)params->hash_name);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
params->salt_size = le64_to_cpu(sb.salt_size);
|
params->salt_size = le64_to_cpu(sb.salt_size);
|
||||||
if (params->salt_size > sizeof(sb.salt)) {
|
if (params->salt_size > sizeof(sb.salt)) {
|
||||||
|
|||||||
@@ -23,6 +23,10 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#define VERITY_MAX_HASH_TYPE 1
|
||||||
|
#define VERITY_BLOCK_SIZE_OK(x) ((x) % 512 || (x) < 512 || \
|
||||||
|
(x) > (512 * 1024) || (x) & ((x)-1))
|
||||||
|
|
||||||
struct crypt_device;
|
struct crypt_device;
|
||||||
struct crypt_params_verity;
|
struct crypt_params_verity;
|
||||||
|
|
||||||
|
|||||||
@@ -88,6 +88,14 @@ out:
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int mult_overflow(off_t *u, off_t b, size_t size)
|
||||||
|
{
|
||||||
|
*u = (uint64_t)b * size;
|
||||||
|
if ((off_t)(*u / size) != b || (off_t)*u < 0 || (off_t)*u != *u)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int create_or_verify(struct crypt_device *cd, FILE *rd, FILE *wr,
|
static int create_or_verify(struct crypt_device *cd, FILE *rd, FILE *wr,
|
||||||
off_t data_block, size_t data_block_size,
|
off_t data_block, size_t data_block_size,
|
||||||
off_t hash_block, size_t hash_block_size,
|
off_t hash_block, size_t hash_block_size,
|
||||||
@@ -102,16 +110,23 @@ static int create_or_verify(struct crypt_device *cd, FILE *rd, FILE *wr,
|
|||||||
size_t hash_per_block = 1 << get_bits_down(hash_block_size / digest_size);
|
size_t hash_per_block = 1 << get_bits_down(hash_block_size / digest_size);
|
||||||
size_t digest_size_full = 1 << get_bits_up(digest_size);
|
size_t digest_size_full = 1 << get_bits_up(digest_size);
|
||||||
off_t blocks_to_write = (blocks + hash_per_block - 1) / hash_per_block;
|
off_t blocks_to_write = (blocks + hash_per_block - 1) / hash_per_block;
|
||||||
|
off_t seek_rd, seek_wr;
|
||||||
size_t left_bytes;
|
size_t left_bytes;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (fseeko(rd, data_block * data_block_size, SEEK_SET)) {
|
if (mult_overflow(&seek_rd, data_block, data_block_size) ||
|
||||||
|
mult_overflow(&seek_wr, hash_block, hash_block_size)) {
|
||||||
|
log_err(cd, _("Device offset overflow.\n"));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fseeko(rd, seek_rd, SEEK_SET)) {
|
||||||
log_dbg("Cannot seek to requested position in data device.");
|
log_dbg("Cannot seek to requested position in data device.");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wr && fseeko(wr, hash_block * hash_block_size, SEEK_SET)) {
|
if (wr && fseeko(wr, seek_wr, SEEK_SET)) {
|
||||||
log_dbg("Cannot seek to requested position in hash device.");
|
log_dbg("Cannot seek to requested position in hash device.");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
@@ -205,7 +220,8 @@ static int VERITY_create_or_verify_hash(struct crypt_device *cd,
|
|||||||
off_t hash_level_size[VERITY_MAX_LEVELS];
|
off_t hash_level_size[VERITY_MAX_LEVELS];
|
||||||
off_t data_file_blocks, s;
|
off_t data_file_blocks, s;
|
||||||
size_t hash_per_block, hash_per_block_bits;
|
size_t hash_per_block, hash_per_block_bits;
|
||||||
uint64_t data_device_size = 0, hash_device_size = 0;
|
off_t data_device_size = 0, hash_device_size = 0;
|
||||||
|
uint64_t dev_size;
|
||||||
int levels, i, r;
|
int levels, i, r;
|
||||||
|
|
||||||
log_dbg("Hash %s %s, data device %s, data blocks %" PRIu64
|
log_dbg("Hash %s %s, data device %s, data blocks %" PRIu64
|
||||||
@@ -213,15 +229,23 @@ static int VERITY_create_or_verify_hash(struct crypt_device *cd,
|
|||||||
verify ? "verification" : "creation", hash_name,
|
verify ? "verification" : "creation", hash_name,
|
||||||
data_device, data_blocks, hash_device, hash_position);
|
data_device, data_blocks, hash_device, hash_position);
|
||||||
|
|
||||||
|
if (data_blocks < 0 || hash_position < 0) {
|
||||||
|
log_err(cd, _("Invalid size parameters for verity device.\n"));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
if (!data_blocks) {
|
if (!data_blocks) {
|
||||||
r = device_size(data_device, &data_device_size);
|
r = device_size(data_device, &dev_size);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
data_file_blocks = data_device_size / data_block_size;
|
data_file_blocks = dev_size / data_block_size;
|
||||||
} else {
|
} else
|
||||||
data_device_size = data_blocks * data_block_size;
|
|
||||||
data_file_blocks = data_blocks;
|
data_file_blocks = data_blocks;
|
||||||
|
|
||||||
|
if (mult_overflow(&data_device_size, data_blocks, data_block_size)) {
|
||||||
|
log_err(cd, _("Device offset overflow.\n"));
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
hash_per_block_bits = get_bits_down(hash_block_size / digest_size);
|
hash_per_block_bits = get_bits_down(hash_block_size / digest_size);
|
||||||
@@ -251,12 +275,16 @@ static int VERITY_create_or_verify_hash(struct crypt_device *cd,
|
|||||||
if (hash_position + s < hash_position ||
|
if (hash_position + s < hash_position ||
|
||||||
(hash_position + s) < 0 ||
|
(hash_position + s) < 0 ||
|
||||||
(hash_position + s) != hash_position + s) {
|
(hash_position + s) != hash_position + s) {
|
||||||
log_dbg("Hash device offset overflow.");
|
log_err(cd, _("Device offset overflow.\n"));
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
hash_position += s;
|
hash_position += s;
|
||||||
}
|
}
|
||||||
hash_device_size = hash_position * hash_block_size;
|
|
||||||
|
if (mult_overflow(&hash_device_size, hash_position, hash_block_size)) {
|
||||||
|
log_err(cd, _("Device offset overflow.\n"));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
log_dbg("Data device size required: %" PRIu64 " bytes.",
|
log_dbg("Data device size required: %" PRIu64 " bytes.",
|
||||||
data_device_size);
|
data_device_size);
|
||||||
@@ -383,10 +411,9 @@ int VERITY_create(struct crypt_device *cd,
|
|||||||
if (verity_hdr->salt_size > 256)
|
if (verity_hdr->salt_size > 256)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (verity_hdr->hash_block_size > pgsize ||
|
if (verity_hdr->data_block_size > pgsize)
|
||||||
verity_hdr->data_block_size > pgsize)
|
log_err(cd, _("WARNING: Kernel cannot activate device if data "
|
||||||
log_err(cd, _("WARNING: Kernel cannot activate device if block "
|
"block size exceeds page size (%u).\n"), pgsize);
|
||||||
"size exceeds page size (%u).\n"), pgsize);
|
|
||||||
|
|
||||||
return VERITY_create_or_verify_hash(cd, 0,
|
return VERITY_create_or_verify_hash(cd, 0,
|
||||||
verity_hdr->hash_type,
|
verity_hdr->hash_type,
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <popt.h>
|
#include <popt.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
@@ -126,9 +127,11 @@ static int _prepare_format(struct crypt_params_verity *params,
|
|||||||
params->salt_size = 0;
|
params->salt_size = 0;
|
||||||
params->salt = NULL;
|
params->salt = NULL;
|
||||||
} else if (salt_string) {
|
} else if (salt_string) {
|
||||||
params->salt_size = strlen(salt_string) / 2;
|
if (hex_to_bytes(salt_string, salt_bytes) * 2 != strlen(salt_string)) {
|
||||||
if (hex_to_bytes(salt_string, salt_bytes) != params->salt_size)
|
log_err(_("Invalid salt string specified.\n"));
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
params->salt_size = strlen(salt_string) / 2;
|
||||||
params->salt = salt_bytes;
|
params->salt = salt_bytes;
|
||||||
} else
|
} else
|
||||||
params->salt_size = DEFAULT_VERITY_SALT_SIZE;
|
params->salt_size = DEFAULT_VERITY_SALT_SIZE;
|
||||||
@@ -201,7 +204,9 @@ static int _activate(const char *dm_device,
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
hash_size = crypt_get_volume_key_size(cd);
|
hash_size = crypt_get_volume_key_size(cd);
|
||||||
if (hex_to_bytes(root_hash, root_hash_bytes) != hash_size) {
|
if (hash_size * 2 != strlen(root_hash) ||
|
||||||
|
hex_to_bytes(root_hash, root_hash_bytes) != hash_size) {
|
||||||
|
log_err(_("Invalid root hash string specified.\n"));
|
||||||
r = -EINVAL;
|
r = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -528,8 +533,8 @@ int main(int argc, const char **argv)
|
|||||||
char *endp;
|
char *endp;
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
ull_value = strtoull(popt_tmp, &endp, 0);
|
ull_value = strtoull(popt_tmp, &endp, 10);
|
||||||
if (*endp || !*popt_tmp ||
|
if (*endp || !*popt_tmp || !isdigit(*popt_tmp) ||
|
||||||
(errno == ERANGE && ull_value == ULLONG_MAX) ||
|
(errno == ERANGE && ull_value == ULLONG_MAX) ||
|
||||||
(errno != 0 && ull_value == 0))
|
(errno != 0 && ull_value == 0))
|
||||||
r = POPT_ERROR_BADNUMBER;
|
r = POPT_ERROR_BADNUMBER;
|
||||||
@@ -540,6 +545,8 @@ int main(int argc, const char **argv)
|
|||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
hash_start = ull_value * 512;
|
hash_start = ull_value * 512;
|
||||||
|
if (hash_start / 512 != ull_value)
|
||||||
|
r = POPT_ERROR_BADNUMBER;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -584,6 +591,12 @@ int main(int argc, const char **argv)
|
|||||||
poptGetInvocationName(popt_context));
|
poptGetInvocationName(popt_context));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data_block_size < 0 || hash_block_size < 0 || hash_type < 0) {
|
||||||
|
usage(popt_context, EXIT_FAILURE,
|
||||||
|
_("Negative number for option not permitted."),
|
||||||
|
poptGetInvocationName(popt_context));
|
||||||
|
}
|
||||||
|
|
||||||
if (opt_debug) {
|
if (opt_debug) {
|
||||||
opt_verbose = 1;
|
opt_verbose = 1;
|
||||||
crypt_set_debug_level(-1);
|
crypt_set_debug_level(-1);
|
||||||
|
|||||||
Reference in New Issue
Block a user