2 * veritysetup - setup cryptographic volumes for dm-verity
4 * Copyright (C) 2012, Red Hat, Inc. All rights reserved.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * version 2 as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 * - detect dm-verity (devmapper)
23 * - unify units / uint64 etc
24 * - check translations
25 * - support device without superblock
26 * - audit alloc errors / error path
27 * - change command names (cryptsetup style)
28 * - extend superblock (UUID)
29 * - warn if block_size > PAGE_SIZE
39 #include "cryptsetup.h"
41 #define PACKAGE_VERITY "veritysetup"
45 #define MODE_ACTIVATE 2
49 static int use_superblock = 1; /* FIXME: no superblock not supported */
51 static const char *dm_device = NULL;
52 static const char *data_device = NULL;
53 static const char *hash_device = NULL;
54 static const char *hash_algorithm = NULL;
55 static const char *root_hash = NULL;
57 static int version = 1;
58 static int data_block_size = 4096;
59 static int hash_block_size = 4096;
60 static char *data_blocks_string = NULL;
61 static long long data_blocks = 0;
62 static char *hash_start_string = NULL;
63 static const char *salt_string = NULL;
65 static unsigned salt_size = 32;
67 static off_t superblock_position = 0;
69 static int opt_verbose = 0;
70 static int opt_debug = 0;
71 static int opt_version_mode = 0;
73 static int hex_to_bytes(const char *hex, char *result)
75 char buf[3] = "xx\0", *endp;
78 len = strlen(hex) / 2;
79 for (i = 0; i < len; i++) {
80 memcpy(buf, &hex[i * 2], 2);
81 result[i] = strtoul(buf, &endp, 16);
88 __attribute__((format(printf, 5, 6)))
89 static void clogger(struct crypt_device *cd, int level, const char *file,
90 int line, const char *format, ...)
95 va_start(argp, format);
97 if (vasprintf(&target, format, argp) > 0) {
99 crypt_log(cd, level, target);
101 } else if (opt_debug)
102 printf("# %s:%d %s\n", file ?: "?", line, target);
104 } else if (opt_debug)
105 printf("# %s\n", target);
113 static void _log(int level, const char *msg, void *usrptr __attribute__((unused)))
117 case CRYPT_LOG_NORMAL:
120 case CRYPT_LOG_VERBOSE:
124 case CRYPT_LOG_ERROR:
127 case CRYPT_LOG_DEBUG:
129 printf("# %s\n", msg);
132 fprintf(stderr, "Internal error on logging class for msg: %s", msg);
137 static int action_dump(void)
139 struct crypt_device *cd = NULL;
140 struct crypt_params_verity params = {};
143 if ((r = crypt_init(&cd, hash_device)))
146 params.hash_area_offset = superblock_position;
147 r = crypt_load(cd, CRYPT_VERITY, ¶ms);
154 static int action_activate(int verify)
156 struct crypt_device *cd = NULL;
157 struct crypt_params_verity params = {};
158 uint32_t activate_flags = CRYPT_ACTIVATE_READONLY;
159 char root_hash_bytes[128];
162 if ((r = crypt_init(&cd, hash_device)))
166 params.flags |= CRYPT_VERITY_CHECK_HASH;
168 if (use_superblock) {
169 params.hash_area_offset = superblock_position;
170 r = crypt_load(cd, CRYPT_VERITY, ¶ms);
172 params.hash_name = hash_algorithm;
173 params.salt = salt_bytes;
174 params.salt_size = salt_size;
175 params.data_block_size = data_block_size;
176 params.hash_block_size = hash_block_size;
178 params.data_size = data_blocks * data_block_size / 512;
179 params.version = version;
180 params.flags |= CRYPT_VERITY_NO_HEADER;
181 r = crypt_load(cd, CRYPT_VERITY, ¶ms);
188 r = crypt_set_data_device(cd, data_device);
192 if (hex_to_bytes(root_hash, root_hash_bytes) !=
193 crypt_get_volume_key_size(cd)) {
197 r = crypt_activate_by_volume_key(cd, dm_device, root_hash_bytes,
198 crypt_get_volume_key_size(cd),
207 static int action_create(void)
209 struct crypt_device *cd = NULL;
210 struct crypt_params_verity params = {};
211 char salt_bytes[512];
214 if ((r = crypt_init(&cd, hash_device)))
217 params.hash_name = hash_algorithm;
218 params.data_device = data_device;
221 if (hex_to_bytes(salt_string, salt_bytes) != salt_size) {
225 params.salt = salt_bytes;
228 params.salt_size = salt_size;
229 params.data_block_size = data_block_size;
230 params.hash_block_size = hash_block_size;
231 params.data_size = data_blocks;
232 params.hash_area_offset = superblock_position;
233 params.version = version;
234 params.flags = CRYPT_VERITY_CREATE_HASH;
236 params.flags |= CRYPT_VERITY_NO_HEADER;
238 r = crypt_format(cd, CRYPT_VERITY, NULL, NULL, NULL, NULL, 0, ¶ms);
246 static __attribute__ ((noreturn)) void usage(poptContext popt_context,
247 int exitcode, const char *error,
250 poptPrintUsage(popt_context, stderr, 0);
252 log_err("%s: %s\n", more, error);
253 poptFreeContext(popt_context);
257 static void help(poptContext popt_context,
258 enum poptCallbackReason reason __attribute__((unused)),
259 struct poptOption *key,
260 const char *arg __attribute__((unused)),
261 void *data __attribute__((unused)))
263 if (key->shortName == '?') {
264 log_std("%s %s\n", PACKAGE_VERITY, PACKAGE_VERSION);
265 poptPrintHelp(popt_context, stdout, 0);
268 usage(popt_context, EXIT_SUCCESS, NULL, NULL);
271 static void _dbg_version_and_cmd(int argc, const char **argv)
275 log_std("# %s %s processing \"", PACKAGE_VERITY, PACKAGE_VERSION);
276 for (i = 0; i < argc; i++) {
279 log_std("%s", argv[i]);
284 int main(int argc, const char **argv)
286 static struct poptOption popt_help_options[] = {
287 { NULL, '\0', POPT_ARG_CALLBACK, help, 0, NULL, NULL },
288 { "help", '?', POPT_ARG_NONE, NULL, 0, N_("Show this help message"), NULL },
289 { "usage", '\0', POPT_ARG_NONE, NULL, 0, N_("Display brief usage"), NULL },
292 static struct poptOption popt_options[] = {
293 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, popt_help_options, 0, N_("Help options:"), NULL },
294 { "version", '\0', POPT_ARG_NONE, &opt_version_mode, 0, N_("Print package version"), NULL },
295 { "verbose", 0 /*v*/, POPT_ARG_NONE, &opt_verbose, 0, N_("Shows more detailed error messages"), NULL },
296 { "debug", '\0', POPT_ARG_NONE, &opt_debug, 0, N_("Show debug messages"), NULL },
297 { "create", 'c', POPT_ARG_VAL, &mode, MODE_CREATE, "Create hash", NULL },
298 { "verify", 'v', POPT_ARG_VAL, &mode, MODE_VERIFY, "Verify integrity", NULL },
299 { "activate", 'a', POPT_ARG_VAL, &mode, MODE_ACTIVATE, "Activate the device", NULL },
300 { "dump", 'd', POPT_ARG_VAL, &mode, MODE_DUMP, "Dump the device", NULL },
301 { "no-superblock", 0, POPT_ARG_VAL, &use_superblock, 0, "Do not create/use superblock" },
302 { "format", 0, POPT_ARG_INT, &version, 0, "Format version (1 - normal format, 0 - original Chromium OS format)", "number" },
303 { "data-block-size", 0, POPT_ARG_INT, &data_block_size, 0, "Block size on the data device", "bytes" },
304 { "hash-block-size", 0, POPT_ARG_INT, &hash_block_size, 0, "Block size on the hash device", "bytes" },
305 { "data-blocks", 0, POPT_ARG_STRING, &data_blocks_string, 0, "The number of blocks in the data file", "blocks" },
306 { "hash-start", 0, POPT_ARG_STRING, &hash_start_string, 0, "Starting block on the hash device", "512-byte sectors" },
307 { "algorithm", 0, POPT_ARG_STRING, &hash_algorithm, 0, "Hash algorithm (default sha256)", "string" },
308 { "salt", 0, POPT_ARG_STRING, &salt_string, 0, "Salt", "hex string" },
311 poptContext popt_context;
314 static long long hash_start = 0;
316 crypt_set_log_callback(NULL, _log, NULL);
318 setlocale(LC_ALL, "");
319 bindtextdomain(PACKAGE, LOCALEDIR);
322 popt_context = poptGetContext("verity", argc, argv, popt_options, 0);
324 poptSetOtherOptionHelp(popt_context, "[-c|-v|-a|-d] [<device name> if activating] <data device> <hash device> [<root hash> if activating or verifying] [OPTION...]");
327 poptPrintHelp(popt_context, stdout, 0);
331 r = poptGetNextOpt(popt_context);
333 usage(popt_context, EXIT_FAILURE, poptStrerror(r),
334 poptBadOption(popt_context, POPT_BADOPTION_NOALIAS));
335 if (opt_version_mode) {
336 log_std("%s %s\n", PACKAGE_VERITY, PACKAGE_VERSION);
337 poptFreeContext(popt_context);
342 usage(popt_context, EXIT_FAILURE, _("Unknown action."),
343 poptGetInvocationName(popt_context));
345 if (mode == MODE_ACTIVATE) {
346 dm_device = poptGetArg(popt_context);
347 if (!dm_device || !*dm_device)
348 usage(popt_context, EXIT_FAILURE,
349 _("Missing activation device name."),
350 poptGetInvocationName(popt_context));
353 data_device = poptGetArg(popt_context);
355 usage(popt_context, EXIT_FAILURE, _("Missing data device name."),
356 poptGetInvocationName(popt_context));
358 hash_device = poptGetArg(popt_context);
360 usage(popt_context, EXIT_FAILURE, _("Missing hash device name."),
361 poptGetInvocationName(popt_context));
363 if (mode == MODE_ACTIVATE || mode == MODE_VERIFY) {
364 root_hash = poptGetArg(popt_context);
366 usage(popt_context, EXIT_FAILURE, _("Root hash not specified."),
367 poptGetInvocationName(popt_context));
370 if (data_blocks_string) {
371 data_blocks = strtoll(data_blocks_string, &end, 10);
372 if (!*data_blocks_string || *end)
373 usage(popt_context, EXIT_FAILURE,
374 _("Invalid number of data blocks."),
375 poptGetInvocationName(popt_context));
379 if (hash_start_string) {
380 hash_start = strtoll(hash_start_string, &end, 10);
381 if (!*hash_start_string || *end)
382 usage(popt_context, EXIT_FAILURE,
383 _("Invalid hash device offset."),
384 poptGetInvocationName(popt_context));
387 if (hash_start < 0 ||
388 (unsigned long long)hash_start * 512 / 512 != hash_start ||
389 (off_t)(hash_start * 512) < 0 ||
390 (off_t)(hash_start * 512) != hash_start * 512)
391 usage(popt_context, EXIT_FAILURE,
392 _("Invalid hash device offset."),
393 poptGetInvocationName(popt_context));
396 superblock_position = hash_start * 512;
398 if (salt_string || !use_superblock) {
399 if (!salt_string || !strcmp(salt_string, "-"))
401 salt_size = strlen(salt_string) / 2;
404 if (data_block_size < 512 || (data_block_size & (data_block_size - 1)) || data_block_size >= 1U << 31)
405 usage(popt_context, EXIT_FAILURE, _("Invalid data block size."),
406 poptGetInvocationName(popt_context));
408 if (hash_block_size < 512 || (hash_block_size & (hash_block_size - 1)) || hash_block_size >= 1U << 31)
409 usage(popt_context, EXIT_FAILURE, _("Invalid hash block size."),
410 poptGetInvocationName(popt_context));
412 if (data_blocks < 0 || (off_t)data_blocks < 0 || (off_t)data_blocks != data_blocks)
413 usage(popt_context, EXIT_FAILURE, _("Invalid number of data blocks."),
414 poptGetInvocationName(popt_context));
417 hash_algorithm = "sha256";
421 crypt_set_debug_level(-1);
422 _dbg_version_and_cmd(argc, argv);
427 r = action_activate(0);
430 r = action_activate(1);
440 poptFreeContext(popt_context);