ac43e3339acd0f29f34f25e9a73b017f5be3cdaf
[platform/upstream/cryptsetup.git] / src / veritysetup.c
1 /*
2  * veritysetup - setup cryptographic volumes for dm-verity
3  *
4  * Copyright (C) 2012, Red Hat, Inc. All rights reserved.
5  *
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.
9  *
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.
14  *
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.
18  */
19
20 #include "cryptsetup.h"
21
22 #define PACKAGE_VERITY "veritysetup"
23
24 static int use_superblock = 1;
25
26 static const char *hash_algorithm = NULL;
27 static int hash_type = 1;
28 static int data_block_size = DEFAULT_VERITY_DATA_BLOCK;
29 static int hash_block_size = DEFAULT_VERITY_HASH_BLOCK;
30 static uint64_t data_blocks = 0;
31 static const char *salt_string = NULL;
32 static uint64_t hash_offset = 0;
33 static const char *opt_uuid = NULL;
34
35 static int opt_version_mode = 0;
36
37 static const char **action_argv;
38 static int action_argc;
39
40 static int _prepare_format(struct crypt_params_verity *params,
41                            const char *data_device,
42                            uint32_t flags)
43 {
44         char *salt = NULL;
45         int len;
46
47         params->hash_name = hash_algorithm ?: DEFAULT_VERITY_HASH;
48         params->data_device = data_device;
49
50         if (salt_string && !strcmp(salt_string, "-")) {
51                 params->salt_size = 0;
52                 params->salt = NULL;
53         } else if (salt_string) {
54                 len = crypt_hex_to_bytes(salt_string, &salt, 0);
55                 if (len < 0) {
56                         log_err(_("Invalid salt string specified.\n"));
57                         return -EINVAL;
58                 }
59                 params->salt_size = len;
60                 params->salt = salt;
61         } else {
62                 params->salt_size = DEFAULT_VERITY_SALT_SIZE;
63                 params->salt = NULL;
64         }
65
66         params->data_block_size = data_block_size;
67         params->hash_block_size = hash_block_size;
68         params->data_size = data_blocks;
69         params->hash_area_offset = hash_offset;
70         params->hash_type = hash_type;
71         params->flags = flags;
72
73         return 0;
74 }
75
76 static int action_format(int arg)
77 {
78         struct crypt_device *cd = NULL;
79         struct crypt_params_verity params = {};
80         uint32_t flags = CRYPT_VERITY_CREATE_HASH;
81         int r;
82
83         /* Try to create hash image if doesn't exist */
84         r = open(action_argv[1], O_WRONLY | O_EXCL | O_CREAT, S_IRUSR | S_IWUSR);
85         if (r < 0 && errno != EEXIST) {
86                 log_err(_("Cannot create hash image %s for writing.\n"), action_argv[1]);
87                 return -EINVAL;
88         } else if (r >= 0) {
89                 log_dbg("Created hash image %s.", action_argv[1]);
90                 close(r);
91         }
92
93         if ((r = crypt_init(&cd, action_argv[1])))
94                 goto out;
95
96         if (!use_superblock)
97                 flags |= CRYPT_VERITY_NO_HEADER;
98
99         r = _prepare_format(&params, action_argv[0], flags);
100         if (r < 0)
101                 goto out;
102
103         r = crypt_format(cd, CRYPT_VERITY, NULL, NULL, opt_uuid, NULL, 0, &params);
104         if (!r)
105                 crypt_dump(cd);
106 out:
107         crypt_free(cd);
108         free(CONST_CAST(char*)params.salt);
109         return r;
110 }
111
112 static int _activate(const char *dm_device,
113                       const char *data_device,
114                       const char *hash_device,
115                       const char *root_hash,
116                       uint32_t flags)
117 {
118         struct crypt_device *cd = NULL;
119         struct crypt_params_verity params = {};
120         uint32_t activate_flags = CRYPT_ACTIVATE_READONLY;
121         char *root_hash_bytes = NULL;
122         ssize_t hash_size;
123         int r;
124
125         if ((r = crypt_init(&cd, hash_device)))
126                 goto out;
127
128         if (use_superblock) {
129                 params.flags = flags;
130                 params.hash_area_offset = hash_offset;
131                 r = crypt_load(cd, CRYPT_VERITY, &params);
132         } else {
133                 r = _prepare_format(&params, data_device, flags | CRYPT_VERITY_NO_HEADER);
134                 if (r < 0)
135                         goto out;
136                 r = crypt_format(cd, CRYPT_VERITY, NULL, NULL, NULL, NULL, 0, &params);
137         }
138         if (r < 0)
139                 goto out;
140         r = crypt_set_data_device(cd, data_device);
141         if (r < 0)
142                 goto out;
143
144         hash_size = crypt_get_volume_key_size(cd);
145         if (crypt_hex_to_bytes(root_hash, &root_hash_bytes, 0) != hash_size) {
146                 log_err(_("Invalid root hash string specified.\n"));
147                 r = -EINVAL;
148                 goto out;
149         }
150         r = crypt_activate_by_volume_key(cd, dm_device,
151                                          root_hash_bytes,
152                                          hash_size,
153                                          activate_flags);
154 out:
155         crypt_free(cd);
156         free(root_hash_bytes);
157         free(CONST_CAST(char*)params.salt);
158         return r;
159 }
160
161 static int action_create(int arg)
162 {
163         return _activate(action_argv[0],
164                          action_argv[1],
165                          action_argv[2],
166                          action_argv[3], 0);
167 }
168
169 static int action_verify(int arg)
170 {
171         return _activate(NULL,
172                          action_argv[0],
173                          action_argv[1],
174                          action_argv[2],
175                          CRYPT_VERITY_CHECK_HASH);
176 }
177
178 static int action_remove(int arg)
179 {
180         struct crypt_device *cd = NULL;
181         int r;
182
183         r = crypt_init_by_name(&cd, action_argv[0]);
184         if (r == 0)
185                 r = crypt_deactivate(cd, action_argv[0]);
186
187         crypt_free(cd);
188         return r;
189 }
190
191 static int action_status(int arg)
192 {
193         crypt_status_info ci;
194         struct crypt_active_device cad;
195         struct crypt_params_verity vp = {};
196         struct crypt_device *cd = NULL;
197         struct stat st;
198         char *backing_file;
199         unsigned i, path = 0;
200         int r = 0;
201
202         /* perhaps a path, not a dm device name */
203         if (strchr(action_argv[0], '/') && !stat(action_argv[0], &st))
204                 path = 1;
205
206         ci = crypt_status(NULL, action_argv[0]);
207         switch (ci) {
208         case CRYPT_INVALID:
209                 r = -EINVAL;
210                 break;
211         case CRYPT_INACTIVE:
212                 if (path)
213                         log_std("%s is inactive.\n", action_argv[0]);
214                 else
215                         log_std("%s/%s is inactive.\n", crypt_get_dir(), action_argv[0]);
216                 r = -ENODEV;
217                 break;
218         case CRYPT_ACTIVE:
219         case CRYPT_BUSY:
220                 if (path)
221                         log_std("%s is active%s.\n", action_argv[0],
222                                 ci == CRYPT_BUSY ? " and is in use" : "");
223                 else
224                         log_std("%s/%s is active%s.\n", crypt_get_dir(), action_argv[0],
225                                 ci == CRYPT_BUSY ? " and is in use" : "");
226
227                 r = crypt_init_by_name_and_header(&cd, action_argv[0], NULL);
228                 if (r < 0 || !crypt_get_type(cd))
229                         goto out;
230
231                 log_std("  type:        %s\n", crypt_get_type(cd));
232
233                 r = crypt_get_active_device(cd, action_argv[0], &cad);
234                 if (r < 0)
235                         goto out;
236
237                 log_std("  status:      %s\n",
238                         cad.flags & CRYPT_ACTIVATE_CORRUPTED ? "corrupted" : "verified");
239
240                 r = crypt_get_verity_info(cd, &vp);
241                 if (r < 0)
242                         goto out;
243
244                 log_std("  hash type:   %u\n", vp.hash_type);
245                 log_std("  data block:  %u\n", vp.data_block_size);
246                 log_std("  hash block:  %u\n", vp.hash_block_size);
247                 log_std("  hash name:   %s\n", vp.hash_name);
248                 log_std("  salt:        ");
249                 if (vp.salt_size)
250                         for(i = 0; i < vp.salt_size; i++)
251                                 log_std("%02hhx", (const char)vp.salt[i]);
252                 else
253                         log_std("-");
254                 log_std("\n");
255
256                 log_std("  data device: %s\n", vp.data_device);
257                 if (crypt_loop_device(vp.data_device)) {
258                         backing_file = crypt_loop_backing_file(vp.data_device);
259                         log_std("  data loop:   %s\n", backing_file);
260                         free(backing_file);
261                 }
262                 log_std("  size:        %" PRIu64 " sectors\n", cad.size);
263                 log_std("  mode:        %s\n", cad.flags & CRYPT_ACTIVATE_READONLY ?
264                                            "readonly" : "read/write");
265
266                 log_std("  hash device: %s\n", vp.hash_device);
267                 if (crypt_loop_device(vp.hash_device)) {
268                         backing_file = crypt_loop_backing_file(vp.hash_device);
269                         log_std("  hash loop:   %s\n", backing_file);
270                         free(backing_file);
271                 }
272                 log_std("  hash offset: %" PRIu64 " sectors\n",
273                         vp.hash_area_offset * vp.hash_block_size / 512);
274         }
275 out:
276         crypt_free(cd);
277         if (r == -ENOTSUP)
278                 r = 0;
279         return r;
280 }
281
282 static int action_dump(int arg)
283 {
284         struct crypt_device *cd = NULL;
285         struct crypt_params_verity params = {};
286         int r;
287
288         if ((r = crypt_init(&cd, action_argv[0])))
289                 return r;
290
291         params.hash_area_offset = hash_offset;
292         r = crypt_load(cd, CRYPT_VERITY, &params);
293         if (!r)
294                 crypt_dump(cd);
295         crypt_free(cd);
296         return r;
297 }
298
299 static struct action_type {
300         const char *type;
301         int (*handler)(int);
302         int required_action_argc;
303         const char *arg_desc;
304         const char *desc;
305 } action_types[] = {
306         { "format",     action_format, 2, N_("<data_device> <hash_device>"),N_("format device") },
307         { "verify",     action_verify, 3, N_("<data_device> <hash_device> <root_hash>"),N_("verify device") },
308         { "create",     action_create, 4, N_("<name> <data_device> <hash_device> <root_hash>"),N_("create active device") },
309         { "remove",     action_remove, 1, N_("<name>"),N_("remove (deactivate) device") },
310         { "status",     action_status, 1, N_("<name>"),N_("show active device status") },
311         { "dump",       action_dump,   1, N_("<hash_device>"),N_("show on-disk information") },
312         { NULL, NULL, 0, NULL, NULL }
313 };
314
315 static void help(poptContext popt_context,
316                  enum poptCallbackReason reason __attribute__((unused)),
317                  struct poptOption *key,
318                  const char *arg __attribute__((unused)),
319                  void *data __attribute__((unused)))
320 {
321         struct action_type *action;
322
323         if (key->shortName == '?') {
324                 log_std("%s %s\n", PACKAGE_VERITY, PACKAGE_VERSION);
325                 poptPrintHelp(popt_context, stdout, 0);
326                 log_std(_("\n"
327                          "<action> is one of:\n"));
328                 for(action = action_types; action->type; action++)
329                         log_std("\t%s %s - %s\n", action->type, _(action->arg_desc), _(action->desc));
330                 log_std(_("\n"
331                          "<name> is the device to create under %s\n"
332                          "<data_device> is the data device\n"
333                          "<hash_device> is the device containing verification data\n"
334                          "<root_hash> hash of the root node on <hash_device>\n"),
335                         crypt_get_dir());
336
337                 log_std(_("\nDefault compiled-in dm-verity parameters:\n"
338                          "\tHash: %s, Data block (bytes): %u, "
339                          "Hash block (bytes): %u, Salt size: %u, Hash format: %u\n"),
340                         DEFAULT_VERITY_HASH, DEFAULT_VERITY_DATA_BLOCK,
341                         DEFAULT_VERITY_HASH_BLOCK, DEFAULT_VERITY_SALT_SIZE,
342                         1);
343                 exit(EXIT_SUCCESS);
344         } else
345                 usage(popt_context, EXIT_SUCCESS, NULL, NULL);
346 }
347
348 static int run_action(struct action_type *action)
349 {
350         int r;
351
352         log_dbg("Running command %s.", action->type);
353
354         r = action->handler(0);
355
356         show_status(r);
357         return translate_errno(r);
358 }
359
360 int main(int argc, const char **argv)
361 {
362         static char *popt_tmp;
363         static const char *null_action_argv[] = {NULL};
364         static struct poptOption popt_help_options[] = {
365                 { NULL,    '\0', POPT_ARG_CALLBACK, help, 0, NULL,                         NULL },
366                 { "help",  '?',  POPT_ARG_NONE,     NULL, 0, N_("Show this help message"), NULL },
367                 { "usage", '\0', POPT_ARG_NONE,     NULL, 0, N_("Display brief usage"),    NULL },
368                 POPT_TABLEEND
369         };
370         static struct poptOption popt_options[] = {
371                 { NULL,              '\0', POPT_ARG_INCLUDE_TABLE, popt_help_options, 0, N_("Help options:"), NULL },
372                 { "version",         '\0', POPT_ARG_NONE, &opt_version_mode, 0, N_("Print package version"), NULL },
373                 { "verbose",         'v',  POPT_ARG_NONE, &opt_verbose,      0, N_("Shows more detailed error messages"), NULL },
374                 { "debug",           '\0', POPT_ARG_NONE, &opt_debug,        0, N_("Show debug messages"), NULL },
375                 { "no-superblock",   0,    POPT_ARG_VAL,  &use_superblock,   0, N_("Do not use verity superblock"), NULL },
376                 { "format",          0,    POPT_ARG_INT,  &hash_type,        0, N_("Format type (1 - normal, 0 - original Chrome OS)"), N_("number") },
377                 { "data-block-size", 0,    POPT_ARG_INT,  &data_block_size,  0, N_("Block size on the data device"), N_("bytes") },
378                 { "hash-block-size", 0,    POPT_ARG_INT,  &hash_block_size,  0, N_("Block size on the hash device"), N_("bytes") },
379                 { "data-blocks",     0,    POPT_ARG_STRING, &popt_tmp,       1, N_("The number of blocks in the data file"), N_("blocks") },
380                 { "hash-offset",     0,    POPT_ARG_STRING, &popt_tmp,       2, N_("Starting offset on the hash device"), N_("bytes") },
381                 { "hash",            'h',  POPT_ARG_STRING, &hash_algorithm, 0, N_("Hash algorithm"), N_("string") },
382                 { "salt",            's',  POPT_ARG_STRING, &salt_string,    0, N_("Salt"), N_("hex string") },
383                 { "uuid",            '\0', POPT_ARG_STRING, &opt_uuid,       0, N_("UUID for device to use."), NULL },
384                 POPT_TABLEEND
385         };
386
387         poptContext popt_context;
388         struct action_type *action;
389         const char *aname;
390         int r;
391
392         crypt_set_log_callback(NULL, tool_log, NULL);
393
394         setlocale(LC_ALL, "");
395         bindtextdomain(PACKAGE, LOCALEDIR);
396         textdomain(PACKAGE);
397
398         popt_context = poptGetContext("verity", argc, argv, popt_options, 0);
399         poptSetOtherOptionHelp(popt_context,
400                                _("[OPTION...] <action> <action-specific>"));
401
402         while((r = poptGetNextOpt(popt_context)) > 0) {
403                 unsigned long long ull_value;
404                 char *endp;
405
406                 errno = 0;
407                 ull_value = strtoull(popt_tmp, &endp, 10);
408                 if (*endp || !*popt_tmp || !isdigit(*popt_tmp) ||
409                     (errno == ERANGE && ull_value == ULLONG_MAX) ||
410                     (errno != 0 && ull_value == 0))
411                         r = POPT_ERROR_BADNUMBER;
412
413                 switch(r) {
414                         case 1:
415                                 data_blocks = ull_value;
416                                 break;
417                         case 2:
418                                 hash_offset = ull_value;
419                                 break;
420                 }
421
422                 if (r < 0)
423                         break;
424         }
425
426         if (r < -1)
427                 usage(popt_context, EXIT_FAILURE, poptStrerror(r),
428                       poptBadOption(popt_context, POPT_BADOPTION_NOALIAS));
429
430         if (opt_version_mode) {
431                 log_std("%s %s\n", PACKAGE_VERITY, PACKAGE_VERSION);
432                 poptFreeContext(popt_context);
433                 exit(EXIT_SUCCESS);
434         }
435
436         if (!(aname = poptGetArg(popt_context)))
437                 usage(popt_context, EXIT_FAILURE, _("Argument <action> missing."),
438                       poptGetInvocationName(popt_context));
439         for(action = action_types; action->type; action++)
440                 if (strcmp(action->type, aname) == 0)
441                         break;
442         if (!action->type)
443                 usage(popt_context, EXIT_FAILURE, _("Unknown action."),
444                       poptGetInvocationName(popt_context));
445
446         action_argc = 0;
447         action_argv = poptGetArgs(popt_context);
448         /* Make return values of poptGetArgs more consistent in case of remaining argc = 0 */
449         if(!action_argv)
450                 action_argv = null_action_argv;
451
452         /* Count args, somewhat unnice, change? */
453         while(action_argv[action_argc] != NULL)
454                 action_argc++;
455
456         if(action_argc < action->required_action_argc) {
457                 char buf[128];
458                 snprintf(buf, 128,_("%s: requires %s as arguments"), action->type, action->arg_desc);
459                 usage(popt_context, EXIT_FAILURE, buf,
460                       poptGetInvocationName(popt_context));
461         }
462
463         if (data_block_size < 0 || hash_block_size < 0 || hash_type < 0) {
464                 usage(popt_context, EXIT_FAILURE,
465                       _("Negative number for option not permitted."),
466                       poptGetInvocationName(popt_context));
467         }
468
469         if (opt_debug) {
470                 opt_verbose = 1;
471                 crypt_set_debug_level(-1);
472                 dbg_version_and_cmd(argc, argv);
473         }
474
475         r = run_action(action);
476         poptFreeContext(popt_context);
477         return r;
478 }