From: Milan Broz Date: Sat, 9 Jun 2012 20:02:06 +0000 (+0200) Subject: Prepare new superblock format. X-Git-Tag: upstream/1.6~271^2~12 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=697c6c9324e8b9230d271ea2a1abe2faead05542;p=platform%2Fupstream%2Fcryptsetup.git Prepare new superblock format. --- diff --git a/lib/bitops.h b/lib/bitops.h new file mode 100644 index 0000000..d823b65 --- /dev/null +++ b/lib/bitops.h @@ -0,0 +1,83 @@ +#ifndef BITOPS_H +#define BITOPS_H + +#include + +/* + * Bit map related macros. Usually provided by libc. + */ +#include + +#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 */ diff --git a/lib/internal.h b/lib/internal.h index af0c3b2..2f847ae 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -32,6 +32,7 @@ #include #include "nls.h" +#include "bitops.h" #include "utils_crypt.h" #include "utils_loop.h" #include "utils_dm.h" diff --git a/lib/libcryptsetup.h b/lib/libcryptsetup.h index 3c67974..a7dc478 100644 --- a/lib/libcryptsetup.h +++ b/lib/libcryptsetup.h @@ -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 */ }; diff --git a/lib/libdevmapper.c b/lib/libdevmapper.c index 16a863d..46ab807 100644 --- a/lib/libdevmapper.c +++ b/lib/libdevmapper.c @@ -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 */ diff --git a/lib/setup.c b/lib/setup.c index 9637ace..5d62f60 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -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; } diff --git a/lib/verity/verity.c b/lib/verity/verity.c index 3991a81..5e0860e 100644 --- a/lib/verity/verity.c +++ b/lib/verity/verity.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -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); diff --git a/lib/verity/verity.h b/lib/verity/verity.h index aef3887..67a8ad6 100644 --- a/lib/verity/verity.h +++ b/lib/verity/verity.h @@ -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; diff --git a/lib/verity/verity_hash.c b/lib/verity/verity_hash.c index 08c89f9..e7ef93d 100644 --- a/lib/verity/verity_hash.c +++ b/lib/verity/verity_hash.c @@ -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, diff --git a/src/veritysetup.c b/src/veritysetup.c index 591c181..619fa19 100644 --- a/src/veritysetup.c +++ b/src/veritysetup.c @@ -20,7 +20,6 @@ /* TODO: * - extend superblock (UUID) * - add api tests - * - report in-kernel status outside libcryptsetup (extend api) */ #include @@ -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") },