Prepare new superblock format.
authorMilan Broz <gmazyland@gmail.com>
Sat, 9 Jun 2012 20:02:06 +0000 (22:02 +0200)
committerMilan Broz <gmazyland@gmail.com>
Sat, 9 Jun 2012 20:02:06 +0000 (22:02 +0200)
lib/bitops.h [new file with mode: 0644]
lib/internal.h
lib/libcryptsetup.h
lib/libdevmapper.c
lib/setup.c
lib/verity/verity.c
lib/verity/verity.h
lib/verity/verity_hash.c
src/veritysetup.c

diff --git a/lib/bitops.h b/lib/bitops.h
new file mode 100644 (file)
index 0000000..d823b65
--- /dev/null
@@ -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 */
index af0c3b2..2f847ae 100644 (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"
index 3c67974..a7dc478 100644 (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 */
 };
 
index 16a863d..46ab807 100644 (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 */
index 9637ace..5d62f60 100644 (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;
 }
index 3991a81..5e0860e 100644 (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);
index aef3887..67a8ad6 100644 (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;
index 08c89f9..e7ef93d 100644 (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,
index 591c181..619fa19 100644 (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") },