Add verity uuid specification.
authorMilan Broz <gmazyland@gmail.com>
Sat, 9 Jun 2012 21:20:43 +0000 (23:20 +0200)
committerMilan Broz <gmazyland@gmail.com>
Sat, 9 Jun 2012 21:20:43 +0000 (23:20 +0200)
lib/setup.c
lib/verity/verity.c
lib/verity/verity.h
man/veritysetup.8
src/veritysetup.c

index 5d62f60..bcd22df 100644 (file)
@@ -69,6 +69,7 @@ struct crypt_device {
        struct crypt_params_verity verity_hdr;
        char *verity_root_hash;
        uint64_t verity_root_hash_size;
+       char *verity_uuid;
 
        /* callbacks definitions */
        void (*log)(int level, const char *msg, void *usrptr);
@@ -660,7 +661,8 @@ static int _crypt_load_verity(struct crypt_device *cd, struct crypt_params_verit
        if (params)
                sb_offset = params->hash_area_offset;
 
-       r = VERITY_read_sb(cd, mdata_device(cd), sb_offset, &cd->verity_hdr);
+       r = VERITY_read_sb(cd, mdata_device(cd), sb_offset,
+                          &cd->verity_uuid, &cd->verity_hdr);
        if (r < 0)
                return r;
 
@@ -765,8 +767,8 @@ static int _init_by_name_verity(struct crypt_device *cd, const char *name)
                goto out;
 
        if (isVERITY(cd->type)) {
+               cd->verity_uuid = dmd.uuid ? strdup(dmd.uuid) : NULL;
                cd->verity_hdr.flags = CRYPT_VERITY_NO_HEADER; //FIXME
-               //cd->verity_uuid = dmd.uuid ? strdup(dmd.uuid) : NULL;
                cd->verity_hdr.data_size = params.data_size;
                cd->verity_root_hash_size = dmd.u.verity.root_hash_size;
                cd->verity_root_hash = NULL;
@@ -1023,6 +1025,7 @@ static int _crypt_format_loopaes(struct crypt_device *cd,
 }
 
 static int _crypt_format_verity(struct crypt_device *cd,
+                                const char *uuid,
                                 struct crypt_params_verity *params)
 {
        int r = 0;
@@ -1051,7 +1054,6 @@ static int _crypt_format_verity(struct crypt_device *cd,
        } else
                cd->verity_hdr.data_size = params->data_size;
 
-
        cd->verity_root_hash_size = crypt_hash_size(params->hash_name);
        if (!cd->verity_root_hash_size)
                return -EINVAL;
@@ -1077,26 +1079,29 @@ static int _crypt_format_verity(struct crypt_device *cd,
                r = crypt_random_get(cd, CONST_CAST(char*)cd->verity_hdr.salt,
                                     params->salt_size, CRYPT_RND_SALT);
        if (r)
-               goto out;
+               return r;
 
        if (params->flags & CRYPT_VERITY_CREATE_HASH) {
                r = VERITY_create(cd, &cd->verity_hdr, cd->device, mdata_device(cd),
                                  cd->verity_root_hash, cd->verity_root_hash_size);
                if (r)
-                       goto out;
+                       return r;
        }
 
-       if (!(params->flags & CRYPT_VERITY_NO_HEADER))
+       if (!(params->flags & CRYPT_VERITY_NO_HEADER)) {
+               if (uuid)
+                       cd->verity_uuid = strdup(uuid);
+               else {
+                       r = VERITY_UUID_generate(cd, &cd->verity_uuid);
+                       if (r)
+                               return r;
+               }
+
                r = VERITY_write_sb(cd, mdata_device(cd),
                                    cd->verity_hdr.hash_area_offset,
+                                   cd->verity_uuid,
                                    &cd->verity_hdr);
-out:
-       if (r) {
-               free(cd->verity_root_hash);
-               free(CONST_CAST(char*)cd->verity_hdr.hash_name);
-               free(CONST_CAST(char*)cd->verity_hdr.salt);
        }
-
        return r;
 }
 
@@ -1134,7 +1139,7 @@ int crypt_format(struct crypt_device *cd,
        else if (isLOOPAES(type))
                r = _crypt_format_loopaes(cd, cipher, uuid, volume_key_size, params);
        else if (isVERITY(type))
-               r = _crypt_format_verity(cd, params);
+               r = _crypt_format_verity(cd, uuid, params);
        else {
                /* FIXME: allow plugins here? */
                log_err(cd, _("Unknown crypt device type %s requested.\n"), type);
@@ -1365,6 +1370,7 @@ void crypt_free(struct crypt_device *cd)
                free(CONST_CAST(void*)cd->verity_hdr.hash_name);
                free(CONST_CAST(void*)cd->verity_hdr.salt);
                free(cd->verity_root_hash);
+               free(cd->verity_uuid);
 
                free(cd);
        }
@@ -2251,6 +2257,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, "UUID:            \t%s\n", cd->verity_uuid ?: "");
        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);
@@ -2320,6 +2327,9 @@ const char *crypt_get_uuid(struct crypt_device *cd)
        if (isLOOPAES(cd->type))
                return cd->loopaes_uuid;
 
+       if (isVERITY(cd->type))
+               return cd->verity_uuid;
+
        return NULL;
 }
 
index 5e0860e..7cfb811 100644 (file)
@@ -26,6 +26,7 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <netinet/in.h>
+#include <uuid/uuid.h>
 
 #include "libcryptsetup.h"
 #include "verity.h"
@@ -69,6 +70,7 @@ struct verity_sb {
 int VERITY_read_sb(struct crypt_device *cd,
                   const char *device,
                   uint64_t sb_offset,
+                  char **uuid_string,
                   struct crypt_params_verity *params)
 {
        struct verity_sb sb = {};
@@ -167,6 +169,8 @@ int VERITY_read_sb(struct crypt_device *cd,
        }
        memcpy(CONST_CAST(char*)params->salt, sb.salt, params->salt_size);
 
+       if ((*uuid_string = malloc(40)))
+               uuid_unparse(sb.uuid, *uuid_string);
 #endif
        params->hash_area_offset = sb_offset;
        return 0;
@@ -176,15 +180,22 @@ int VERITY_read_sb(struct crypt_device *cd,
 int VERITY_write_sb(struct crypt_device *cd,
                   const char *device,
                   uint64_t sb_offset,
+                  const char *uuid_string,
                   struct crypt_params_verity *params)
 {
        struct verity_sb sb = {};
        ssize_t hdr_size = sizeof(struct verity_sb);
+       uuid_t uuid;
        int r, devfd = 0;
 
        log_dbg("Updating VERITY header of size %u on device %s, offset %" PRIu64 ".",
                sizeof(struct verity_sb), device, sb_offset);
 
+       if (!uuid_string || uuid_parse(uuid_string, uuid) == -1) {
+               log_err(cd, _("Wrong VERITY UUID format provided.\n"), device);
+               return -EINVAL;
+       }
+
        if (params->flags & CRYPT_VERITY_NO_HEADER) {
                log_err(cd, _("Verity device doesn't use on-disk header.\n"), device);
                return -EINVAL;
@@ -215,6 +226,7 @@ int VERITY_write_sb(struct crypt_device *cd,
        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);
+       memcpy(sb.uuid, uuid, sizeof(sb.uuid));
 #endif
        r = write_lseek_blockwise(devfd, (char*)&sb, hdr_size, sb_offset) < hdr_size ? -EIO : 0;
        if (r)
@@ -238,6 +250,17 @@ uint64_t VERITY_hash_offset_block(struct crypt_params_verity *params)
        return hash_offset / params->hash_block_size;
 }
 
+int VERITY_UUID_generate(struct crypt_device *cd, char **uuid_string)
+{
+       uuid_t uuid;
+
+       if (!(*uuid_string = malloc(40)))
+               return -ENOMEM;
+       uuid_generate(uuid);
+       uuid_unparse(uuid, *uuid_string);
+       return 0;
+}
+
 /* Activate verity device in kernel device-mapper */
 int VERITY_activate(struct crypt_device *cd,
                     const char *name,
@@ -273,7 +296,7 @@ int VERITY_activate(struct crypt_device *cd,
        dmd.u.verity.hash_offset = VERITY_hash_offset_block(verity_hdr),
        dmd.flags = activation_flags;
        dmd.size = verity_hdr->data_size * verity_hdr->data_block_size / 512;
-       dmd.uuid = NULL;
+       dmd.uuid = crypt_get_uuid(cd);
        dmd.u.verity.vp = verity_hdr;
 
        r = device_check_and_adjust(cd, dmd.data_device, DEV_EXCL,
index 67a8ad6..273739b 100644 (file)
@@ -32,11 +32,13 @@ struct crypt_params_verity;
 int VERITY_read_sb(struct crypt_device *cd,
                   const char *device,
                   uint64_t sb_offset,
+                  char **uuid,
                   struct crypt_params_verity *params);
 
 int VERITY_write_sb(struct crypt_device *cd,
                   const char *device,
                   uint64_t sb_offset,
+                  const char *uuid_string,
                   struct crypt_params_verity *params);
 
 int VERITY_activate(struct crypt_device *cd,
@@ -63,4 +65,6 @@ int VERITY_create(struct crypt_device *cd,
 
 uint64_t VERITY_hash_offset_block(struct crypt_params_verity *params);
 
+int VERITY_UUID_generate(struct crypt_device *cd, char **uuid_string);
+
 #endif
index 066c486..1aee3cf 100644 (file)
@@ -24,7 +24,7 @@ or activation. This hash must be trusted.
 
 \fB<options>\fR can be [\-\-hash, \-\-no-superblock, \-\-format,
 \-\-data-block-size, \-\-hash-block-size, \-\-data-blocks, \-\-hash-start,
-\-\-salt]
+\-\-salt, \-\-uuid]
 .PP
 \fIcreate\fR <name> <data_device> <hash_device> <root_hash>
 .IP
@@ -59,32 +59,39 @@ Print more information on command execution.
 Run in debug mode with full diagnostic logs. Debug output
 lines are always prefixed by '#'.
 .TP
-.B "\-\-no-superblock
+.B "\-\-no-superblock"
 Create or use dm-verity without permanent on-disk superblock.
 .TP
-.B "\-\-format=number
+.B "\-\-format=number"
 Specifies the hash version type.
 Format type 0 is original Chrome OS verion. Format type 1 si default.
 .TP
-.B "\-\-data-block-size=bytes
+.B "\-\-data-block-size=bytes"
 Used block size for the data device.
 (Note kernel supports only page-size as maximum here.)
 .TP
-.B "\-\-hash-block-size=bytes
+.B "\-\-hash-block-size=bytes"
 Used block size for the hash device.
 (Note kernel supports only page-size as maximum here.)
 .TP
-.B "\-\-data-blocks=blocks
+.B "\-\-data-blocks=blocks"
 Size of data device used in verification.
 If not specified, the whole device is used.
 .TP
-.B "\-\-hash-start=512-bytes sectors
+.B "\-\-hash-start=512-bytes sectors"
 Offset of hash area/superblock on hash_device.
 .TP
-.B "\-\-salt=hex string
+.B "\-\-salt=hex string"
 Salt used for format or verification.
 Format is hexadecimal string.
 .TP
+.B "\-\-uuid=UUID"
+Use the provided UUID for the format command
+instead of generating new one.
+
+The UUID must be provided in the standard UUID format,
+e.g. 12345678-1234-1234-1234-123456789abc.
+.TP
 .B "\-\-version"
 Show the program version.
 .SH RETURN CODES
index 619fa19..eb5ec0d 100644 (file)
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-/* TODO:
- * - extend superblock (UUID)
- * - add api tests
- */
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
@@ -45,6 +40,7 @@ static int hash_block_size = DEFAULT_VERITY_HASH_BLOCK;
 static uint64_t data_blocks = 0;
 static const char *salt_string = NULL;
 static uint64_t hash_start = 0;
+static const char *opt_uuid = NULL;
 
 static int opt_verbose = 0;
 static int opt_debug = 0;
@@ -164,7 +160,7 @@ static int action_format(int arg)
        if (r < 0)
                goto out;
 
-       r = crypt_format(cd, CRYPT_VERITY, NULL, NULL, NULL, NULL, 0, &params);
+       r = crypt_format(cd, CRYPT_VERITY, NULL, NULL, opt_uuid, NULL, 0, &params);
        if (!r)
                crypt_dump(cd);
 out:
@@ -505,6 +501,7 @@ int main(int argc, const char **argv)
                { "hash-start",      0,    POPT_ARG_STRING, &popt_tmp,       2, N_("Starting block on the hash device"), N_("512-byte sectors") },
                { "hash",            'h',  POPT_ARG_STRING, &hash_algorithm, 0, N_("Hash algorithm"), N_("string") },
                { "salt",            's',  POPT_ARG_STRING, &salt_string,    0, N_("Salt"), N_("hex string") },
+               { "uuid",            '\0', POPT_ARG_STRING, &opt_uuid,       0, N_("UUID for device to use."), NULL },
                POPT_TABLEEND
        };