]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/veritysetup/veritysetup.c
veritysetup-generator: add support for veritytab
[thirdparty/systemd.git] / src / veritysetup / veritysetup.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2f3dfc6f 2
dccca82b 3#include <errno.h>
2f3dfc6f
LP
4#include <stdio.h>
5#include <sys/stat.h>
6
dccca82b 7#include "alloc-util.h"
1e2f3230 8#include "cryptsetup-util.h"
035e8e50 9#include "fileio.h"
2f3dfc6f 10#include "hexdecoct.h"
dccca82b 11#include "log.h"
6b9306b2 12#include "main-func.h"
035e8e50 13#include "path-util.h"
294bf0c3 14#include "pretty-print.h"
2f3dfc6f 15#include "string-util.h"
37ec0fdd 16#include "terminal-util.h"
2f3dfc6f
LP
17
18static char *arg_root_hash = NULL;
19static char *arg_data_what = NULL;
20static char *arg_hash_what = NULL;
cb0198a1
GP
21static uint32_t arg_activate_flags = CRYPT_ACTIVATE_READONLY;
22static char *arg_root_hash_signature = NULL;
2f3dfc6f 23
6b9306b2
YW
24STATIC_DESTRUCTOR_REGISTER(arg_root_hash, freep);
25STATIC_DESTRUCTOR_REGISTER(arg_data_what, freep);
26STATIC_DESTRUCTOR_REGISTER(arg_hash_what, freep);
cb0198a1 27STATIC_DESTRUCTOR_REGISTER(arg_root_hash_signature, freep);
6b9306b2 28
2f3dfc6f 29static int help(void) {
37ec0fdd
LP
30 _cleanup_free_ char *link = NULL;
31 int r;
32
33 r = terminal_urlify_man("systemd-veritysetup@.service", "8", &link);
34 if (r < 0)
35 return log_oom();
36
cb0198a1 37 printf("%s attach VOLUME DATADEVICE HASHDEVICE ROOTHASH [OPTIONS]\n"
2f3dfc6f 38 "%s detach VOLUME\n\n"
37ec0fdd
LP
39 "Attaches or detaches an integrity protected block device.\n"
40 "\nSee the %s for details.\n"
41 , program_invocation_short_name
42 , program_invocation_short_name
43 , link
44 );
2f3dfc6f
LP
45
46 return 0;
47}
48
cb0198a1
GP
49static int looks_like_roothashsig(const char *option) {
50 const char *val;
51 int r;
52
53 if (path_is_absolute(option)) {
54
55 r = free_and_strdup(&arg_root_hash_signature, option);
56 if (r < 0)
57 return log_oom();
58
59 return 1;
60 }
61
62 val = startswith(option, "base64:");
63 if (val) {
64
65 r = free_and_strdup(&arg_root_hash_signature, val);
66 if (r < 0)
67 return log_oom();
68
69 return 1;
70 }
71
72 return 0;
73}
74
75static int parse_options(const char *options) {
76 int r;
77
78 /* backward compatibility with the obsolete ROOTHASHSIG positional argument */
79 r = looks_like_roothashsig(options);
80 if (r < 0)
81 return r;
82 if (r == 1) {
83 log_warning("Usage of ROOTHASHSIG positional argument is deprecated. "
84 "Please use the option root-hash-signature=%s instead.", options);
85 return 0;
86 }
87
88 for (;;) {
89 _cleanup_free_ char *word = NULL;
90 char *val;
91
92 r = extract_first_word(&options, &word, ",", EXTRACT_DONT_COALESCE_SEPARATORS | EXTRACT_UNESCAPE_SEPARATORS);
93 if (r < 0)
94 return log_error_errno(r, "Failed to parse options: %m");
95 if (r == 0)
96 break;
97
08b04ec7
GP
98 if (STR_IN_SET(word, "noauto", "auto", "nofail", "fail", "_netdev"))
99 continue;
100
cb0198a1
GP
101 if (isempty(word))
102 continue;
103 else if (streq(word, "ignore-corruption"))
104 arg_activate_flags |= CRYPT_ACTIVATE_IGNORE_CORRUPTION;
105 else if (streq(word, "restart-on-corruption"))
106 arg_activate_flags |= CRYPT_ACTIVATE_RESTART_ON_CORRUPTION;
107 else if (streq(word, "ignore-zero-blocks"))
108 arg_activate_flags |= CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS;
109#ifdef CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE
110 else if (streq(word, "check-at-most-once"))
111 arg_activate_flags |= CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE;
112#endif
113#ifdef CRYPT_ACTIVATE_PANIC_ON_CORRUPTION
114 else if (streq(word, "panic-on-corruption"))
115 arg_activate_flags |= CRYPT_ACTIVATE_PANIC_ON_CORRUPTION;
116#endif
117 else if ((val = startswith(word, "root-hash-signature="))) {
118
119 r = looks_like_roothashsig(val);
120 if (r < 0)
121 return r;
122 if (r == 0)
123 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "root-hash-signature expects either full path to signature file or "
124 "base64 string encoding signature prefixed by base64:.");
125
126 r = free_and_strdup(&arg_root_hash_signature, val);
127 if (r < 0)
128 return log_oom();
129 } else
130 log_warning("Encountered unknown option '%s', ignoring.", word);
131 }
132
133 return r;
134}
135
6b9306b2 136static int run(int argc, char *argv[]) {
294bd454 137 _cleanup_(crypt_freep) struct crypt_device *cd = NULL;
2f3dfc6f
LP
138 int r;
139
6b9306b2
YW
140 if (argc <= 1)
141 return help();
2f3dfc6f 142
6b9306b2
YW
143 if (argc < 3)
144 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program requires at least two arguments.");
2f3dfc6f 145
6bf3c61c 146 log_setup_service();
2f3dfc6f
LP
147
148 umask(0022);
149
150 if (streq(argv[1], "attach")) {
151 _cleanup_free_ void *m = NULL;
152 crypt_status_info status;
153 size_t l;
154
6b9306b2
YW
155 if (argc < 6)
156 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "attach requires at least two arguments.");
2f3dfc6f
LP
157
158 r = unhexmem(argv[5], strlen(argv[5]), &m, &l);
6b9306b2
YW
159 if (r < 0)
160 return log_error_errno(r, "Failed to parse root hash: %m");
2f3dfc6f
LP
161
162 r = crypt_init(&cd, argv[4]);
6b9306b2
YW
163 if (r < 0)
164 return log_error_errno(r, "Failed to open verity device %s: %m", argv[4]);
2f3dfc6f 165
efc3b12f 166 cryptsetup_enable_logging(cd);
2f3dfc6f
LP
167
168 status = crypt_status(cd, argv[2]);
3742095b 169 if (IN_SET(status, CRYPT_ACTIVE, CRYPT_BUSY)) {
2f3dfc6f 170 log_info("Volume %s already active.", argv[2]);
6b9306b2 171 return 0;
2f3dfc6f
LP
172 }
173
cb0198a1
GP
174 if (argc > 6) {
175 r = parse_options(argv[6]);
176 if (r < 0)
177 return log_error_errno(r, "Failed to parse options: %m");
178 }
179
2f3dfc6f 180 r = crypt_load(cd, CRYPT_VERITY, NULL);
6b9306b2
YW
181 if (r < 0)
182 return log_error_errno(r, "Failed to load verity superblock: %m");
2f3dfc6f
LP
183
184 r = crypt_set_data_device(cd, argv[3]);
6b9306b2
YW
185 if (r < 0)
186 return log_error_errno(r, "Failed to configure data device: %m");
2f3dfc6f 187
cb0198a1 188 if (arg_root_hash_signature && *arg_root_hash_signature) {
035e8e50
LB
189#if HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
190 _cleanup_free_ char *hash_sig = NULL;
191 size_t hash_sig_size;
192 char *value;
193
cb0198a1 194 if ((value = startswith(arg_root_hash_signature, "base64:"))) {
035e8e50
LB
195 r = unbase64mem(value, strlen(value), (void *)&hash_sig, &hash_sig_size);
196 if (r < 0)
cb0198a1 197 return log_error_errno(r, "Failed to parse root hash signature '%s': %m", arg_root_hash_signature);
035e8e50 198 } else {
986311c2 199 r = read_full_file_full(
cb0198a1 200 AT_FDCWD, arg_root_hash_signature, UINT64_MAX, SIZE_MAX,
986311c2
LP
201 READ_FULL_FILE_CONNECT_SOCKET,
202 NULL,
203 &hash_sig, &hash_sig_size);
035e8e50
LB
204 if (r < 0)
205 return log_error_errno(r, "Failed to read root hash signature: %m");
206 }
207
cb0198a1 208 r = crypt_activate_by_signed_key(cd, argv[2], m, l, hash_sig, hash_sig_size, arg_activate_flags);
035e8e50
LB
209#else
210 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "activation of verity device with signature %s requested, but not supported by cryptsetup due to missing crypt_activate_by_signed_key()", argv[6]);
211#endif
212 } else
cb0198a1 213 r = crypt_activate_by_volume_key(cd, argv[2], m, l, arg_activate_flags);
6b9306b2
YW
214 if (r < 0)
215 return log_error_errno(r, "Failed to set up verity device: %m");
2f3dfc6f
LP
216
217 } else if (streq(argv[1], "detach")) {
218
219 r = crypt_init_by_name(&cd, argv[2]);
220 if (r == -ENODEV) {
221 log_info("Volume %s already inactive.", argv[2]);
6b9306b2 222 return 0;
2f3dfc6f 223 }
6b9306b2
YW
224 if (r < 0)
225 return log_error_errno(r, "crypt_init_by_name() failed: %m");
2f3dfc6f 226
efc3b12f 227 cryptsetup_enable_logging(cd);
2f3dfc6f
LP
228
229 r = crypt_deactivate(cd, argv[2]);
6b9306b2
YW
230 if (r < 0)
231 return log_error_errno(r, "Failed to deactivate: %m");
2f3dfc6f 232
6b9306b2
YW
233 } else
234 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown verb %s.", argv[1]);
2f3dfc6f 235
6b9306b2 236 return 0;
2f3dfc6f 237}
6b9306b2
YW
238
239DEFINE_MAIN_FUNCTION(run);