Prepare new superblock format.

This commit is contained in:
Milan Broz
2012-06-09 22:02:06 +02:00
parent 6d07be898d
commit 697c6c9324
9 changed files with 174 additions and 31 deletions

83
lib/bitops.h Normal file
View File

@@ -0,0 +1,83 @@
#ifndef BITOPS_H
#define BITOPS_H
#include <stdint.h>
/*
* Bit map related macros. Usually provided by libc.
*/
#include <sys/param.h>
#ifndef NBBY
# define NBBY CHAR_BIT
#endif
#ifndef setbit
# define setbit(a,i) ((a)[(i)/NBBY] |= 1<<((i)%NBBY))
# define clrbit(a,i) ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
# define isset(a,i) ((a)[(i)/NBBY] & (1<<((i)%NBBY)))
# define isclr(a,i) (((a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0)
#endif
/*
* Byte swab macros (based on linux/byteorder/swab.h)
*/
#define swab16(x) \
((uint16_t)( \
(((uint16_t)(x) & (uint16_t)0x00ffU) << 8) | \
(((uint16_t)(x) & (uint16_t)0xff00U) >> 8) ))
#define swab32(x) \
((uint32_t)( \
(((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) | \
(((uint32_t)(x) & (uint32_t)0x0000ff00UL) << 8) | \
(((uint32_t)(x) & (uint32_t)0x00ff0000UL) >> 8) | \
(((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24) ))
#define swab64(x) \
((uint64_t)( \
(uint64_t)(((uint64_t)(x) & (uint64_t)0x00000000000000ffULL) << 56) | \
(uint64_t)(((uint64_t)(x) & (uint64_t)0x000000000000ff00ULL) << 40) | \
(uint64_t)(((uint64_t)(x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \
(uint64_t)(((uint64_t)(x) & (uint64_t)0x00000000ff000000ULL) << 8) | \
(uint64_t)(((uint64_t)(x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \
(uint64_t)(((uint64_t)(x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \
(uint64_t)(((uint64_t)(x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \
(uint64_t)(((uint64_t)(x) & (uint64_t)0xff00000000000000ULL) >> 56) ))
#ifdef WORDS_BIGENDIAN
#define cpu_to_le16(x) swab16(x)
#define cpu_to_le32(x) swab32(x)
#define cpu_to_le64(x) swab64(x)
#define cpu_to_be16(x) ((uint16_t)(x))
#define cpu_to_be32(x) ((uint32_t)(x))
#define cpu_to_be64(x) ((uint64_t)(x))
#define le16_to_cpu(x) swab16(x)
#define le32_to_cpu(x) swab32(x)
#define le64_to_cpu(x) swab64(x)
#define be16_to_cpu(x) ((uint16_t)(x))
#define be32_to_cpu(x) ((uint32_t)(x))
#define be64_to_cpu(x) ((uint64_t)(x))
#else /* !WORDS_BIGENDIAN */
#define cpu_to_le16(x) ((uint16_t)(x))
#define cpu_to_le32(x) ((uint32_t)(x))
#define cpu_to_le64(x) ((uint64_t)(x))
#define cpu_to_be16(x) swab16(x)
#define cpu_to_be32(x) swab32(x)
#define cpu_to_be64(x) swab64(x)
#define le16_to_cpu(x) ((uint16_t)(x))
#define le32_to_cpu(x) ((uint32_t)(x))
#define le64_to_cpu(x) ((uint64_t)(x))
#define be16_to_cpu(x) swab16(x)
#define be32_to_cpu(x) swab32(x)
#define be64_to_cpu(x) swab64(x)
#endif /* WORDS_BIGENDIAN */
#endif /* BITOPS_H */

View File

@@ -32,6 +32,7 @@
#include <inttypes.h>
#include "nls.h"
#include "bitops.h"
#include "utils_crypt.h"
#include "utils_loop.h"
#include "utils_dm.h"

View File

@@ -377,7 +377,7 @@ struct crypt_params_verity {
uint32_t hash_block_size; /**< hash block size (in bytes) */
uint64_t data_size; /**< data area size (in data blocks) */
uint64_t hash_area_offset; /**< hash/header offset (in bytes) */
uint32_t version; /**< in-kernel hash version */
uint32_t hash_type; /**< in-kernel hashing type */
uint32_t flags; /**< CRYPT_VERITY* flags */
};

View File

@@ -353,7 +353,7 @@ 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->version, dmd->data_device,
vp->hash_type, dmd->data_device,
dmd->u.verity.hash_device,
vp->data_block_size, vp->hash_block_size,
vp->data_size, dmd->u.verity.hash_offset,
@@ -362,7 +362,6 @@ static char *get_dm_verity_params(struct crypt_params_verity *vp,
crypt_safe_free(params);
params = NULL;
}
log_dbg("TABLE: %s", params);
out:
crypt_safe_free(hexroot);
crypt_safe_free(hexsalt);
@@ -837,7 +836,7 @@ static int _dm_query_verity(uint32_t get_flags,
if (*params != ' ')
return -EINVAL;
if (vp)
vp->version = val32;
vp->hash_type = val32;
params++;
/* data device */

View File

@@ -776,7 +776,7 @@ static int _init_by_name_verity(struct crypt_device *cd, const char *name)
cd->verity_hdr.data_block_size = params.data_block_size;
cd->verity_hdr.hash_block_size = params.hash_block_size;
cd->verity_hdr.hash_area_offset = dmd.u.verity.hash_offset;
cd->verity_hdr.version = params.version;
cd->verity_hdr.hash_type = params.hash_type;
cd->verity_hdr.flags = params.flags;
cd->verity_hdr.salt_size = params.salt_size;
cd->verity_hdr.salt = params.salt;
@@ -1036,9 +1036,6 @@ static int _crypt_format_verity(struct crypt_device *cd,
if (!params || !params->data_device)
return -EINVAL;
if (params->version > 1)
return -EINVAL;
/* set data device */
cd->type = CRYPT_VERITY;
r = crypt_set_data_device(cd, params->data_device);
@@ -1069,7 +1066,7 @@ static int _crypt_format_verity(struct crypt_device *cd,
cd->verity_hdr.data_block_size = params->data_block_size;
cd->verity_hdr.hash_block_size = params->hash_block_size;
cd->verity_hdr.hash_area_offset = params->hash_area_offset;
cd->verity_hdr.version = params->version;
cd->verity_hdr.hash_type = params->hash_type;
cd->verity_hdr.flags = params->flags;
cd->verity_hdr.salt_size = params->salt_size;
cd->verity_hdr.salt = malloc(params->salt_size);
@@ -1327,7 +1324,6 @@ int crypt_header_restore(struct crypt_device *cd,
if (requested_type && !isLUKS(requested_type))
return -EINVAL;
/* Some hash functions need initialized gcrypt library */
r = init_crypto(cd);
if (r < 0)
return r;
@@ -1946,7 +1942,7 @@ int crypt_activate_by_volume_key(struct crypt_device *cd,
struct volume_key *vk = NULL;
int r = -EINVAL;
log_dbg("Activating volume %s by volume key.", name);
log_dbg("Activating volume %s by volume key.", name ?: "[none]");
if (name) {
ci = crypt_status(NULL, name);
@@ -2255,7 +2251,7 @@ static int _luks_dump(struct crypt_device *cd)
static int _verity_dump(struct crypt_device *cd)
{
log_std(cd, "VERITY header information for %s\n", mdata_device(cd));
log_std(cd, "Version: \t%u\n", cd->verity_hdr.version);
log_std(cd, "Hash type: \t%u\n", cd->verity_hdr.hash_type);
log_std(cd, "Data blocks: \t%" PRIu64 "\n", cd->verity_hdr.data_size);
log_std(cd, "Data block size: \t%u\n", cd->verity_hdr.data_block_size);
log_std(cd, "Hash block size: \t%u\n", cd->verity_hdr.hash_block_size);
@@ -2415,7 +2411,7 @@ int crypt_get_verity_info(struct crypt_device *cd,
vp->hash_block_size = cd->verity_hdr.hash_block_size;
vp->data_size = cd->verity_hdr.data_size;
vp->hash_area_offset = cd->verity_hdr.hash_area_offset;
vp->version = cd->verity_hdr.version;
vp->hash_type = cd->verity_hdr.hash_type;
vp->flags = cd->verity_hdr.flags & CRYPT_VERITY_NO_HEADER;
return 0;
}

View File

@@ -21,6 +21,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
@@ -30,7 +31,9 @@
#include "verity.h"
#include "internal.h"
/* FIXME: not yet final on-disk format! Add UUID etc */
#define NEW_SB 1
#ifndef NEW_SB
struct verity_sb {
uint8_t signature[8];
uint8_t version;
@@ -42,10 +45,26 @@ struct verity_sb {
uint32_t data_blocks_hi;
uint32_t data_blocks_lo;
uint8_t algorithm[16];
uint8_t salt[VERITY_MAX_SALT_SIZE];
uint8_t salt[384];
uint8_t pad3[88];
};
#else
struct verity_sb {
uint8_t signature[8]; /* "verity\0\0" */
uint32_t version; /* superblock version */
uint32_t hash_type; /* 0 - Chrome OS, 1 - normal */
uint8_t uuid[16]; /* UUID of hash device */
uint8_t algorithm[32];/* hash algorithm name */
uint64_t data_block_size; /* data block in bytes */
uint64_t hash_block_size; /* hash block in bytes */
uint64_t data_blocks; /* number of data blocks */
uint64_t salt_size; /* salt size */
uint8_t salt[256]; /* salt */
uint8_t _pad[160];
} __attribute__((packed));
#endif
/* Read verity superblock from disk */
int VERITY_read_sb(struct crypt_device *cd,
const char *device,
@@ -54,7 +73,7 @@ int VERITY_read_sb(struct crypt_device *cd,
{
struct verity_sb sb = {};
ssize_t hdr_size = sizeof(struct verity_sb);
int devfd = 0;
int devfd = 0, sb_version;
uint64_t sb_data_blocks;
log_dbg("Reading VERITY header of size %u on device %s, offset %" PRIu64 ".",
@@ -82,7 +101,7 @@ int VERITY_read_sb(struct crypt_device *cd,
log_err(cd, _("Device %s is not a valid VERITY device.\n"), device);
return -EINVAL;
}
#ifndef NEW_SB
if (sb.version > 1) {
log_err(cd, _("Unsupported VERITY version %d.\n"), sb.version);
return -EINVAL;
@@ -91,7 +110,7 @@ int VERITY_read_sb(struct crypt_device *cd,
if (sb.data_block_bits < 9 || sb.data_block_bits >= 31 ||
sb.hash_block_bits < 9 || sb.hash_block_bits >= 31 ||
!memchr(sb.algorithm, 0, sizeof(sb.algorithm)) ||
ntohs(sb.salt_size) > VERITY_MAX_SALT_SIZE) {
ntohs(sb.salt_size) > 256) {
log_err(cd, _("VERITY header corrupted.\n"));
return -EINVAL;
}
@@ -110,9 +129,46 @@ int VERITY_read_sb(struct crypt_device *cd,
if (!params->salt)
return -ENOMEM;
memcpy(CONST_CAST(char*)params->salt, sb.salt, params->salt_size);
params->hash_area_offset = sb_offset;
params->version = sb.version;
params->hash_type = sb.version;
#else
sb_version = le32_to_cpu(sb.version);
if (sb_version != 1) {
log_err(cd, _("Unsupported VERITY version %d.\n"), sb_version);
return -EINVAL;
}
params->hash_type = le32_to_cpu(sb.hash_type);
if (params->hash_type > 1) {
log_err(cd, _("Unsupported VERITY hash type %d.\n"), params->hash_type);
return -EINVAL;
}
params->data_block_size = le64_to_cpu(sb.data_block_size);
params->hash_block_size = le64_to_cpu(sb.hash_block_size);
if (params->data_block_size % 512 || params->hash_block_size % 512) {
log_err(cd, _("Unsupported VERITY block size.\n"));
return -EINVAL;
}
params->data_size = le64_to_cpu(sb.data_blocks);
params->hash_name = strndup((const char*)sb.algorithm, sizeof(sb.algorithm));
if (!params->hash_name)
return -ENOMEM;
params->salt_size = le64_to_cpu(sb.salt_size);
if (params->salt_size > sizeof(sb.salt)) {
log_err(cd, _("VERITY header corrupted.\n"));
free(CONST_CAST(char*)params->hash_name);
return -EINVAL;
}
params->salt = malloc(params->salt_size);
if (!params->salt) {
free(CONST_CAST(char*)params->hash_name);
return -ENOMEM;
}
memcpy(CONST_CAST(char*)params->salt, sb.salt, params->salt_size);
#endif
params->hash_area_offset = sb_offset;
return 0;
}
@@ -141,7 +197,8 @@ int VERITY_write_sb(struct crypt_device *cd,
}
memcpy(&sb.signature, VERITY_SIGNATURE, sizeof(sb.signature));
sb.version = params->version;
#ifndef NEW_SB
sb.version = params->hash_type;
sb.data_block_bits = ffs(params->data_block_size) - 1;
sb.hash_block_bits = ffs(params->hash_block_size) - 1;
sb.salt_size = htons(params->salt_size);
@@ -149,7 +206,16 @@ int VERITY_write_sb(struct crypt_device *cd,
sb.data_blocks_lo = htonl(params->data_size & 0xFFFFFFFF);
strncpy((char *)sb.algorithm, params->hash_name, sizeof(sb.algorithm));
memcpy(sb.salt, params->salt, params->salt_size);
#else
sb.version = cpu_to_le32(1);
sb.hash_type = cpu_to_le32(params->hash_type);
sb.data_block_size = cpu_to_le64(params->data_block_size);
sb.hash_block_size = cpu_to_le64(params->hash_block_size);
sb.salt_size = cpu_to_le64(params->salt_size);
sb.data_blocks = cpu_to_le64(params->data_size);
strncpy((char *)sb.algorithm, params->hash_name, sizeof(sb.algorithm));
memcpy(sb.salt, params->salt, params->salt_size);
#endif
r = write_lseek_blockwise(devfd, (char*)&sb, hdr_size, sb_offset) < hdr_size ? -EIO : 0;
if (r)
log_err(cd, _("Error during update of verity header on device %s.\n"), device);

View File

@@ -25,7 +25,6 @@
#define VERITY_SIGNATURE "verity\0\0"
#define VERITY_MAX_LEVELS 63
#define VERITY_MAX_SALT_SIZE 384
struct crypt_device;
struct crypt_params_verity;

View File

@@ -324,7 +324,7 @@ int VERITY_verify(struct crypt_device *cd,
size_t root_hash_size)
{
return VERITY_create_or_verify_hash(cd, 1,
verity_hdr->version,
verity_hdr->hash_type,
verity_hdr->hash_name,
hash_device,
data_device,
@@ -348,7 +348,7 @@ int VERITY_create(struct crypt_device *cd,
{
int pgsize = crypt_getpagesize();
if (verity_hdr->salt_size > VERITY_MAX_SALT_SIZE)
if (verity_hdr->salt_size > 256)
return -EINVAL;
if (verity_hdr->hash_block_size > pgsize ||
@@ -357,7 +357,7 @@ int VERITY_create(struct crypt_device *cd,
"size exceeds page size (%u).\n"), pgsize);
return VERITY_create_or_verify_hash(cd, 0,
verity_hdr->version,
verity_hdr->hash_type,
verity_hdr->hash_name,
hash_device,
data_device,

View File

@@ -20,7 +20,6 @@
/* TODO:
* - extend superblock (UUID)
* - add api tests
* - report in-kernel status outside libcryptsetup (extend api)
*/
#include <stdio.h>
@@ -40,7 +39,7 @@
static int use_superblock = 1; /* FIXME: no superblock not supported */
static const char *hash_algorithm = NULL;
static int version = 1;
static int hash_type = 1;
static int data_block_size = DEFAULT_VERITY_DATA_BLOCK;
static int hash_block_size = DEFAULT_VERITY_HASH_BLOCK;
static uint64_t data_blocks = 0;
@@ -142,7 +141,7 @@ static int _prepare_format(struct crypt_params_verity *params,
params->hash_block_size = hash_block_size;
params->data_size = data_blocks;
params->hash_area_offset = hash_start;
params->version = version;
params->hash_type = hash_type;
params->flags = flags;
return 0;
@@ -300,7 +299,7 @@ static int action_status(int arg)
if (r < 0)
goto out;
log_std(" version: %u\n", vp.version);
log_std(" hash type: %u\n", vp.hash_type);
log_std(" data block: %u\n", vp.data_block_size);
log_std(" hash block: %u\n", vp.hash_block_size);
log_std(" hash name: %s\n", vp.hash_name);
@@ -499,7 +498,7 @@ int main(int argc, const char **argv)
{ "verbose", 'v', POPT_ARG_NONE, &opt_verbose, 0, N_("Shows more detailed error messages"), NULL },
{ "debug", '\0', POPT_ARG_NONE, &opt_debug, 0, N_("Show debug messages"), NULL },
{ "no-superblock", 0, POPT_ARG_VAL, &use_superblock, 0, N_("Do not use verity superblock"), NULL },
{ "format", 0, POPT_ARG_INT, &version, 0, N_("Format type (1 - normal, 0 - original Chromium OS)"), N_("number") },
{ "format", 0, POPT_ARG_INT, &hash_type, 0, N_("Format type (1 - normal, 0 - original Chrome OS)"), N_("number") },
{ "data-block-size", 0, POPT_ARG_INT, &data_block_size, 0, N_("Block size on the data device"), N_("bytes") },
{ "hash-block-size", 0, POPT_ARG_INT, &hash_block_size, 0, N_("Block size on the hash device"), N_("bytes") },
{ "data-blocks", 0, POPT_ARG_STRING, &popt_tmp, 1, N_("The number of blocks in the data file"), N_("blocks") },