Bug Summary

File:build-scan/../src/cryptsetup/cryptsetup-generator.c
Warning:line 491, column 25
Potential leak of memory pointed to by 'uuid'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name cryptsetup-generator.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -menable-no-infs -menable-no-nans -menable-unsafe-fp-math -fno-signed-zeros -mreassociate -freciprocal-math -fdenormal-fp-math=preserve-sign,preserve-sign -ffp-contract=fast -fno-rounding-math -ffast-math -ffinite-math-only -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.0.0 -include config.h -I systemd-cryptsetup-generator.p -I . -I .. -I src/basic -I ../src/basic -I src/shared -I ../src/shared -I src/systemd -I ../src/systemd -I src/journal -I ../src/journal -I src/journal-remote -I ../src/journal-remote -I src/nspawn -I ../src/nspawn -I src/resolve -I ../src/resolve -I src/timesync -I ../src/timesync -I ../src/time-wait-sync -I src/login -I ../src/login -I src/udev -I ../src/udev -I src/libudev -I ../src/libudev -I src/core -I ../src/core -I ../src/libsystemd/sd-bus -I ../src/libsystemd/sd-device -I ../src/libsystemd/sd-hwdb -I ../src/libsystemd/sd-id128 -I ../src/libsystemd/sd-netlink -I ../src/libsystemd/sd-network -I src/libsystemd-network -I ../src/libsystemd-network -D _FILE_OFFSET_BITS=64 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wwrite-strings -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unused-result -Wno-format-signedness -Wno-error=nonnull -std=gnu99 -fconst-strings -fdebug-compilation-dir /home/mrc0mmand/repos/@redhat-plumbers/systemd-rhel8/build-scan -ferror-limit 19 -fvisibility hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -analyzer-output=html -faddrsig -o /tmp/scan-build-2021-07-16-221226-1465241-1 -x c ../src/cryptsetup/cryptsetup-generator.c
1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include <errno(*__errno_location ()).h>
4#include <stdio_ext.h>
5
6#include "alloc-util.h"
7#include "dropin.h"
8#include "escape.h"
9#include "fd-util.h"
10#include "fileio.h"
11#include "fstab-util.h"
12#include "generator.h"
13#include "hashmap.h"
14#include "id128-util.h"
15#include "log.h"
16#include "mkdir.h"
17#include "parse-util.h"
18#include "path-util.h"
19#include "proc-cmdline.h"
20#include "specifier.h"
21#include "string-util.h"
22#include "strv.h"
23#include "unit-name.h"
24#include "util.h"
25
26typedef struct crypto_device {
27 char *uuid;
28 char *keyfile;
29 char *keydev;
30 char *name;
31 char *options;
32 bool_Bool create;
33} crypto_device;
34
35static const char *arg_dest = "/tmp";
36static bool_Bool arg_enabled = true1;
37static bool_Bool arg_read_crypttab = true1;
38static bool_Bool arg_whitelist = false0;
39static Hashmap *arg_disks = NULL((void*)0);
40static char *arg_default_options = NULL((void*)0);
41static char *arg_default_keyfile = NULL((void*)0);
42
43static int split_keyspec(const char *keyspec, char **ret_keyfile, char **ret_keydev) {
44 _cleanup_free___attribute__((cleanup(freep))) char *keyfile = NULL((void*)0), *keydev = NULL((void*)0);
45 const char *c;
46
47 assert(ret_keyfile)do { if ((__builtin_expect(!!(!(ret_keyfile)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret_keyfile"), "../src/cryptsetup/cryptsetup-generator.c"
, 47, __PRETTY_FUNCTION__); } while (0)
;
48 assert(ret_keydev)do { if ((__builtin_expect(!!(!(ret_keydev)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret_keydev"), "../src/cryptsetup/cryptsetup-generator.c"
, 48, __PRETTY_FUNCTION__); } while (0)
;
49
50 if (!keyspec) {
51 *ret_keyfile = *ret_keydev = NULL((void*)0);
52 return 0;
53 }
54
55 c = strrchr(keyspec, ':');
56 if (c) {
57 /* The keydev part has to be either an absolute path to device node (/dev/something,
58 * /dev/foo/something, or even possibly /dev/foo/something:part), or a fstab device
59 * specification starting with LABEL= or similar. The keyfile part has the same syntax.
60 *
61 * Let's try to guess if the second part looks like a keydev specification, or just part of a
62 * filename with a colon. fstab_node_to_udev_node() will convert the fstab device syntax to
63 * an absolute path. If we didn't get an absolute path, assume that it is just part of the
64 * first keyfile argument. */
65
66 keydev = fstab_node_to_udev_node(c + 1);
67 if (!keydev)
68 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/cryptsetup/cryptsetup-generator.c"
, 68, __func__)
;
69
70 if (path_is_absolute(keydev))
71 keyfile = strndup(keyspec, c-keyspec);
72 else {
73 log_debug("Keyspec argument contains a colon, but \"%s\" doesn't look like a device specification.\n"({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup-generator.c", 75, __func__, "Keyspec argument contains a colon, but \"%s\" doesn't look like a device specification.\n"
"Assuming that \"%s\" is a single device specification.", c +
1, keyspec) : -abs(_e); })
74 "Assuming that \"%s\" is a single device specification.",({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup-generator.c", 75, __func__, "Keyspec argument contains a colon, but \"%s\" doesn't look like a device specification.\n"
"Assuming that \"%s\" is a single device specification.", c +
1, keyspec) : -abs(_e); })
75 c + 1, keyspec)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup-generator.c", 75, __func__, "Keyspec argument contains a colon, but \"%s\" doesn't look like a device specification.\n"
"Assuming that \"%s\" is a single device specification.", c +
1, keyspec) : -abs(_e); })
;
76 keydev = mfree(keydev);
77 c = NULL((void*)0);
78 }
79 }
80
81 if (!c)
82 /* No keydev specified */
83 keyfile = strdup(keyspec);
84
85 if (!keyfile)
86 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/cryptsetup/cryptsetup-generator.c"
, 86, __func__)
;
87
88 *ret_keyfile = TAKE_PTR(keyfile)({ typeof(keyfile) _ptr_ = (keyfile); (keyfile) = ((void*)0);
_ptr_; })
;
89 *ret_keydev = TAKE_PTR(keydev)({ typeof(keydev) _ptr_ = (keydev); (keydev) = ((void*)0); _ptr_
; })
;
90
91 return 0;
92}
93
94static int generate_keydev_mount(const char *name, const char *keydev, const char *keydev_timeout, bool_Bool canfail, char **unit, char **mount) {
95 _cleanup_free___attribute__((cleanup(freep))) char *u = NULL((void*)0), *where = NULL((void*)0), *name_escaped = NULL((void*)0), *device_unit = NULL((void*)0);
96 _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f = NULL((void*)0);
97 int r;
98 usec_t timeout_us;
99
100 assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("name"), "../src/cryptsetup/cryptsetup-generator.c"
, 100, __PRETTY_FUNCTION__); } while (0)
;
101 assert(keydev)do { if ((__builtin_expect(!!(!(keydev)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("keydev"), "../src/cryptsetup/cryptsetup-generator.c"
, 101, __PRETTY_FUNCTION__); } while (0)
;
102 assert(unit)do { if ((__builtin_expect(!!(!(unit)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("unit"), "../src/cryptsetup/cryptsetup-generator.c"
, 102, __PRETTY_FUNCTION__); } while (0)
;
103 assert(mount)do { if ((__builtin_expect(!!(!(mount)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("mount"), "../src/cryptsetup/cryptsetup-generator.c"
, 103, __PRETTY_FUNCTION__); } while (0)
;
104
105 r = mkdir_parents("/run/systemd/cryptsetup", 0755);
106 if (r < 0)
107 return r;
108
109 r = mkdir("/run/systemd/cryptsetup", 0700);
110 if (r < 0 && errno(*__errno_location ()) != EEXIST17)
111 return -errno(*__errno_location ());
112
113 name_escaped = cescape(name);
114 if (!name_escaped)
115 return -ENOMEM12;
116
117 where = strjoin("/run/systemd/cryptsetup/keydev-", name_escaped)strjoin_real(("/run/systemd/cryptsetup/keydev-"), name_escaped
, ((void*)0))
;
118 if (!where)
119 return -ENOMEM12;
120
121 r = mkdir(where, 0700);
122 if (r < 0 && errno(*__errno_location ()) != EEXIST17)
123 return -errno(*__errno_location ());
124
125 r = unit_name_from_path(where, ".mount", &u);
126 if (r < 0)
127 return r;
128
129 r = generator_open_unit_file(arg_dest, NULL((void*)0), u, &f);
130 if (r < 0)
131 return r;
132
133 fprintf(f,
134 "[Unit]\n"
135 "DefaultDependencies=no\n\n"
136 "[Mount]\n"
137 "What=%s\n"
138 "Where=%s\n"
139 "Options=ro%s\n", keydev, where, canfail ? ",nofail" : "");
140
141 if (keydev_timeout) {
142 r = parse_sec_fix_0(keydev_timeout, &timeout_us);
143 if (r >= 0) {
144 r = unit_name_from_path(keydev, ".device", &device_unit);
145 if (r < 0)
146 return log_error_errno(r, "Failed to generate unit name: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup-generator.c", 146, __func__, "Failed to generate unit name: %m"
) : -abs(_e); })
;
147
148 r = write_drop_in_format(arg_dest, device_unit, 90, "device-timeout",
149 "# Automatically generated by systemd-cryptsetup-generator \n\n"
150 "[Unit]\nJobRunningTimeoutSec=%s", keydev_timeout);
151 if (r < 0)
152 return log_error_errno(r, "Failed to write device drop-in: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup-generator.c", 152, __func__, "Failed to write device drop-in: %m"
) : -abs(_e); })
;
153
154 } else
155 log_warning_errno(r, "Failed to parse %s, ignoring: %m", keydev_timeout)({ int _level = ((4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup-generator.c", 155, __func__, "Failed to parse %s, ignoring: %m"
, keydev_timeout) : -abs(_e); })
;
156
157 }
158
159 r = fflush_and_check(f);
160 if (r < 0)
161 return r;
162
163 *unit = TAKE_PTR(u)({ typeof(u) _ptr_ = (u); (u) = ((void*)0); _ptr_; });
164 *mount = TAKE_PTR(where)({ typeof(where) _ptr_ = (where); (where) = ((void*)0); _ptr_
; })
;
165
166 return 0;
167}
168
169static int create_disk(
170 const char *name,
171 const char *device,
172 const char *password,
173 const char *keydev,
174 const char *options) {
175
176 _cleanup_free___attribute__((cleanup(freep))) char *n = NULL((void*)0), *d = NULL((void*)0), *u = NULL((void*)0), *e = NULL((void*)0),
177 *keydev_mount = NULL((void*)0), *keyfile_timeout_value = NULL((void*)0), *password_escaped = NULL((void*)0),
178 *filtered = NULL((void*)0), *u_escaped = NULL((void*)0), *filtered_escaped = NULL((void*)0), *name_escaped = NULL((void*)0);
179 _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f = NULL((void*)0);
180 const char *dmname;
181 bool_Bool noauto, nofail, tmp, swap, netdev;
182 int r, keyfile_can_timeout;
183
184 assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("name"), "../src/cryptsetup/cryptsetup-generator.c"
, 184, __PRETTY_FUNCTION__); } while (0)
;
185 assert(device)do { if ((__builtin_expect(!!(!(device)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("device"), "../src/cryptsetup/cryptsetup-generator.c"
, 185, __PRETTY_FUNCTION__); } while (0)
;
186
187 noauto = fstab_test_yes_no_option(options, "noauto\0" "auto\0");
188 nofail = fstab_test_yes_no_option(options, "nofail\0" "fail\0");
189 tmp = fstab_test_option(options, "tmp\0");
190 swap = fstab_test_option(options, "swap\0");
191 netdev = fstab_test_option(options, "_netdev\0");
192
193 keyfile_can_timeout = fstab_filter_options(options, "keyfile-timeout\0", NULL((void*)0), &keyfile_timeout_value, NULL((void*)0));
194 if (keyfile_can_timeout < 0)
195 return log_error_errno(keyfile_can_timeout, "Failed to parse keyfile-timeout= option value: %m")({ int _level = ((3)), _e = ((keyfile_can_timeout)), _realm =
(LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= (
(_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/cryptsetup/cryptsetup-generator.c"
, 195, __func__, "Failed to parse keyfile-timeout= option value: %m"
) : -abs(_e); })
;
196
197 if (tmp && swap) {
198 log_error("Device '%s' cannot be both 'tmp' and 'swap'. Ignoring.", name)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup-generator.c", 198, __func__, "Device '%s' cannot be both 'tmp' and 'swap'. Ignoring."
, name) : -abs(_e); })
;
199 return -EINVAL22;
200 }
201
202 name_escaped = specifier_escape(name);
203 if (!name_escaped)
204 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/cryptsetup/cryptsetup-generator.c"
, 204, __func__)
;
205
206 e = unit_name_escape(name);
207 if (!e)
208 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/cryptsetup/cryptsetup-generator.c"
, 208, __func__)
;
209
210 u = fstab_node_to_udev_node(device);
211 if (!u)
212 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/cryptsetup/cryptsetup-generator.c"
, 212, __func__)
;
213
214 r = unit_name_build("systemd-cryptsetup", e, ".service", &n);
215 if (r < 0)
216 return log_error_errno(r, "Failed to generate unit name: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup-generator.c", 216, __func__, "Failed to generate unit name: %m"
) : -abs(_e); })
;
217
218 u_escaped = specifier_escape(u);
219 if (!u_escaped)
220 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/cryptsetup/cryptsetup-generator.c"
, 220, __func__)
;
221
222 r = unit_name_from_path(u, ".device", &d);
223 if (r < 0)
224 return log_error_errno(r, "Failed to generate unit name: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup-generator.c", 224, __func__, "Failed to generate unit name: %m"
) : -abs(_e); })
;
225
226 if (keydev && !password) {
227 log_error("Key device is specified, but path to the password file is missing.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup-generator.c", 227, __func__, "Key device is specified, but path to the password file is missing."
) : -abs(_e); })
;
228 return -EINVAL22;
229 }
230
231 r = generator_open_unit_file(arg_dest, NULL((void*)0), n, &f);
232 if (r < 0)
233 return r;
234
235 fprintf(f,
236 "[Unit]\n"
237 "Description=Cryptography Setup for %%I\n"
238 "Documentation=man:crypttab(5) man:systemd-cryptsetup-generator(8) man:systemd-cryptsetup@.service(8)\n"
239 "SourcePath=/etc/crypttab\n"
240 "DefaultDependencies=no\n"
241 "Conflicts=umount.target\n"
242 "IgnoreOnIsolate=true\n"
243 "After=%s\n",
244 netdev ? "remote-fs-pre.target" : "cryptsetup-pre.target");
245
246 if (password) {
247 password_escaped = specifier_escape(password);
248 if (!password_escaped)
249 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/cryptsetup/cryptsetup-generator.c"
, 249, __func__)
;
250 }
251
252 if (keydev) {
253 _cleanup_free___attribute__((cleanup(freep))) char *unit = NULL((void*)0), *p = NULL((void*)0);
254
255 r = generate_keydev_mount(name, keydev, keyfile_timeout_value, keyfile_can_timeout > 0, &unit, &keydev_mount);
256 if (r < 0)
257 return log_error_errno(r, "Failed to generate keydev mount unit: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup-generator.c", 257, __func__, "Failed to generate keydev mount unit: %m"
) : -abs(_e); })
;
258
259 p = prefix_root(keydev_mount, password_escaped);
260 if (!p)
261 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/cryptsetup/cryptsetup-generator.c"
, 261, __func__)
;
262
263 free_and_replace(password_escaped, p)({ free(password_escaped); (password_escaped) = (p); (p) = ((
void*)0); 0; })
;
264
265 fprintf(f, "After=%s\n", unit);
266 if (keyfile_can_timeout > 0)
267 fprintf(f, "Wants=%s\n", unit);
268 else
269 fprintf(f, "Requires=%s\n", unit);
270 }
271
272 if (!nofail)
273 fprintf(f,
274 "Before=%s\n",
275 netdev ? "remote-cryptsetup.target" : "cryptsetup.target");
276
277 if (password && !keydev) {
278 if (STR_IN_SET(password, "/dev/urandom", "/dev/random", "/dev/hw_random")(!!strv_find((((char**) ((const char*[]) { "/dev/urandom", "/dev/random"
, "/dev/hw_random", ((void*)0) }))), (password)))
)
279 fputs("After=systemd-random-seed.service\n", f);
280 else if (!STR_IN_SET(password, "-", "none")(!!strv_find((((char**) ((const char*[]) { "-", "none", ((void
*)0) }))), (password)))
) {
281 _cleanup_free___attribute__((cleanup(freep))) char *uu;
282
283 uu = fstab_node_to_udev_node(password);
284 if (!uu)
285 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/cryptsetup/cryptsetup-generator.c"
, 285, __func__)
;
286
287 if (!path_equal(uu, "/dev/null")) {
288
289 if (path_startswith(uu, "/dev/")) {
290 _cleanup_free___attribute__((cleanup(freep))) char *dd = NULL((void*)0);
291
292 r = unit_name_from_path(uu, ".device", &dd);
293 if (r < 0)
294 return log_error_errno(r, "Failed to generate unit name: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup-generator.c", 294, __func__, "Failed to generate unit name: %m"
) : -abs(_e); })
;
295
296 fprintf(f, "After=%1$s\nRequires=%1$s\n", dd);
297 } else
298 fprintf(f, "RequiresMountsFor=%s\n", password_escaped);
299 }
300 }
301 }
302
303 if (path_startswith(u, "/dev/")) {
304 fprintf(f,
305 "BindsTo=%s\n"
306 "After=%s\n"
307 "Before=umount.target\n",
308 d, d);
309
310 if (swap)
311 fputs("Before=dev-mapper-%i.swap\n",
312 f);
313 } else
314 fprintf(f,
315 "RequiresMountsFor=%s\n",
316 u_escaped);
317
318 r = generator_write_timeouts(arg_dest, device, name, options, &filtered);
319 if (r < 0)
320 return r;
321
322 if (filtered) {
323 filtered_escaped = specifier_escape(filtered);
324 if (!filtered_escaped)
325 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/cryptsetup/cryptsetup-generator.c"
, 325, __func__)
;
326 }
327
328 fprintf(f,
329 "\n[Service]\n"
330 "Type=oneshot\n"
331 "RemainAfterExit=yes\n"
332 "TimeoutSec=0\n" /* the binary handles timeouts anyway */
333 "KeyringMode=shared\n" /* make sure we can share cached keys among instances */
334 "ExecStart=" SYSTEMD_CRYPTSETUP_PATH"/usr/lib/systemd/systemd-cryptsetup" " attach '%s' '%s' '%s' '%s'\n"
335 "ExecStop=" SYSTEMD_CRYPTSETUP_PATH"/usr/lib/systemd/systemd-cryptsetup" " detach '%s'\n",
336 name_escaped, u_escaped, strempty(password_escaped), strempty(filtered_escaped),
337 name_escaped);
338
339 if (tmp)
340 fprintf(f,
341 "ExecStartPost=/sbin/mke2fs '/dev/mapper/%s'\n",
342 name_escaped);
343
344 if (swap)
345 fprintf(f,
346 "ExecStartPost=/sbin/mkswap '/dev/mapper/%s'\n",
347 name_escaped);
348
349 if (keydev)
350 fprintf(f,
351 "ExecStartPost=-" UMOUNT_PATH"/bin/umount" " %s\n\n",
352 keydev_mount);
353
354 r = fflush_and_check(f);
355 if (r < 0)
356 return log_error_errno(r, "Failed to write unit file %s: %m", n)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup-generator.c", 356, __func__, "Failed to write unit file %s: %m"
, n) : -abs(_e); })
;
357
358 if (!noauto) {
359 r = generator_add_symlink(arg_dest, d, "wants", n);
360 if (r < 0)
361 return r;
362
363 r = generator_add_symlink(arg_dest,
364 netdev ? "remote-cryptsetup.target" : "cryptsetup.target",
365 nofail ? "wants" : "requires", n);
366 if (r < 0)
367 return r;
368 }
369
370 dmname = strjoina("dev-mapper-", e, ".device")({ const char *_appendees_[] = { "dev-mapper-", e, ".device" }
; char *_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0
; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_
)/sizeof((_appendees_)[0]), ((void)0))) && _appendees_
[_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
;
371 r = generator_add_symlink(arg_dest, dmname, "requires", n);
372 if (r < 0)
373 return r;
374
375 if (!noauto && !nofail) {
376 r = write_drop_in(arg_dest, dmname, 90, "device-timeout",
377 "# Automatically generated by systemd-cryptsetup-generator \n\n"
378 "[Unit]\nJobTimeoutSec=0");
379 if (r < 0)
380 return log_error_errno(r, "Failed to write device drop-in: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup-generator.c", 380, __func__, "Failed to write device drop-in: %m"
) : -abs(_e); })
;
381 }
382
383 return 0;
384}
385
386static void crypt_device_free(crypto_device *d) {
387 free(d->uuid);
388 free(d->keyfile);
389 free(d->keydev);
390 free(d->name);
391 free(d->options);
392 free(d);
393}
394
395static crypto_device *get_crypto_device(const char *uuid) {
396 int r;
397 crypto_device *d;
398
399 assert(uuid)do { if ((__builtin_expect(!!(!(uuid)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("uuid"), "../src/cryptsetup/cryptsetup-generator.c"
, 399, __PRETTY_FUNCTION__); } while (0)
;
400
401 d = hashmap_get(arg_disks, uuid);
402 if (!d) {
403 d = new0(struct crypto_device, 1)((struct crypto_device*) calloc((1), sizeof(struct crypto_device
)))
;
404 if (!d)
405 return NULL((void*)0);
406
407 d->create = false0;
408 d->keyfile = d->options = d->name = NULL((void*)0);
409
410 d->uuid = strdup(uuid);
411 if (!d->uuid)
412 return mfree(d);
413
414 r = hashmap_put(arg_disks, d->uuid, d);
415 if (r < 0) {
416 free(d->uuid);
417 return mfree(d);
418 }
419 }
420
421 return d;
422}
423
424static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
425 _cleanup_free___attribute__((cleanup(freep))) char *uuid = NULL((void*)0), *uuid_value = NULL((void*)0);
426 crypto_device *d;
427 int r;
428
429 if (streq(key, "luks")(strcmp((key),("luks")) == 0)) {
1
Assuming the condition is false
2
Taking false branch
430
431 r = value ? parse_boolean(value) : 1;
432 if (r < 0)
433 log_warning("Failed to parse luks= kernel command line switch %s. Ignoring.", value)({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup-generator.c", 433, __func__, "Failed to parse luks= kernel command line switch %s. Ignoring."
, value) : -abs(_e); })
;
434 else
435 arg_enabled = r;
436
437 } else if (streq(key, "luks.crypttab")(strcmp((key),("luks.crypttab")) == 0)) {
3
Assuming the condition is false
4
Taking false branch
438
439 r = value ? parse_boolean(value) : 1;
440 if (r < 0)
441 log_warning("Failed to parse luks.crypttab= kernel command line switch %s. Ignoring.", value)({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup-generator.c", 441, __func__, "Failed to parse luks.crypttab= kernel command line switch %s. Ignoring."
, value) : -abs(_e); })
;
442 else
443 arg_read_crypttab = r;
444
445 } else if (streq(key, "luks.uuid")(strcmp((key),("luks.uuid")) == 0)) {
5
Assuming the condition is false
6
Taking false branch
446
447 if (proc_cmdline_value_missing(key, value))
448 return 0;
449
450 d = get_crypto_device(startswith(value, "luks-") ? value+5 : value);
451 if (!d)
452 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/cryptsetup/cryptsetup-generator.c"
, 452, __func__)
;
453
454 d->create = arg_whitelist = true1;
455
456 } else if (streq(key, "luks.options")(strcmp((key),("luks.options")) == 0)) {
7
Assuming the condition is false
8
Taking false branch
457
458 if (proc_cmdline_value_missing(key, value))
459 return 0;
460
461 r = sscanf(value, "%m[0-9a-fA-F-]=%ms", &uuid, &uuid_value);
462 if (r == 2) {
463 d = get_crypto_device(uuid);
464 if (!d)
465 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/cryptsetup/cryptsetup-generator.c"
, 465, __func__)
;
466
467 free_and_replace(d->options, uuid_value)({ free(d->options); (d->options) = (uuid_value); (uuid_value
) = ((void*)0); 0; })
;
468 } else if (free_and_strdup(&arg_default_options, value) < 0)
469 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/cryptsetup/cryptsetup-generator.c"
, 469, __func__)
;
470
471 } else if (streq(key, "luks.key")(strcmp((key),("luks.key")) == 0)) {
9
Taking true branch
472 size_t n;
473 _cleanup_free___attribute__((cleanup(freep))) char *keyfile = NULL((void*)0), *keydev = NULL((void*)0);
474 const char *keyspec;
475
476 if (proc_cmdline_value_missing(key, value))
10
Taking false branch
477 return 0;
478
479 n = strspn(value, LETTERS"abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" DIGITS"0123456789" "-");
480 if (value[n] != '=') {
11
Assuming the condition is false
12
Taking false branch
481 if (free_and_strdup(&arg_default_keyfile, value) < 0)
482 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/cryptsetup/cryptsetup-generator.c"
, 482, __func__)
;
483 return 0;
484 }
485
486 uuid = strndup(value, n);
13
Memory is allocated
487 if (!uuid)
14
Assuming 'uuid' is non-null
15
Taking false branch
488 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/cryptsetup/cryptsetup-generator.c"
, 488, __func__)
;
489
490 if (!id128_is_valid(uuid)) {
16
Assuming the condition is true
17
Taking true branch
491 log_warning("Failed to parse luks.key= kernel command line switch. UUID is invalid, ignoring.")({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup-generator.c", 491, __func__, "Failed to parse luks.key= kernel command line switch. UUID is invalid, ignoring."
) : -abs(_e); })
;
18
Potential leak of memory pointed to by 'uuid'
492 return 0;
493 }
494
495 d = get_crypto_device(uuid);
496 if (!d)
497 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/cryptsetup/cryptsetup-generator.c"
, 497, __func__)
;
498
499 keyspec = value + n + 1;
500 r = split_keyspec(keyspec, &keyfile, &keydev);
501 if (r < 0)
502 return r;
503
504 free_and_replace(d->keyfile, keyfile)({ free(d->keyfile); (d->keyfile) = (keyfile); (keyfile
) = ((void*)0); 0; })
;
505 free_and_replace(d->keydev, keydev)({ free(d->keydev); (d->keydev) = (keydev); (keydev) = (
(void*)0); 0; })
;
506
507 } else if (streq(key, "luks.name")(strcmp((key),("luks.name")) == 0)) {
508
509 if (proc_cmdline_value_missing(key, value))
510 return 0;
511
512 r = sscanf(value, "%m[0-9a-fA-F-]=%ms", &uuid, &uuid_value);
513 if (r == 2) {
514 d = get_crypto_device(uuid);
515 if (!d)
516 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/cryptsetup/cryptsetup-generator.c"
, 516, __func__)
;
517
518 d->create = arg_whitelist = true1;
519
520 free_and_replace(d->name, uuid_value)({ free(d->name); (d->name) = (uuid_value); (uuid_value
) = ((void*)0); 0; })
;
521 } else
522 log_warning("Failed to parse luks name switch %s. Ignoring.", value)({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup-generator.c", 522, __func__, "Failed to parse luks name switch %s. Ignoring."
, value) : -abs(_e); })
;
523 }
524
525 return 0;
526}
527
528static int add_crypttab_devices(void) {
529 struct stat st;
530 unsigned crypttab_line = 0;
531 _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f = NULL((void*)0);
532
533 if (!arg_read_crypttab)
534 return 0;
535
536 f = fopen("/etc/crypttab", "re");
537 if (!f) {
538 if (errno(*__errno_location ()) != ENOENT2)
539 log_error_errno(errno, "Failed to open /etc/crypttab: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/cryptsetup/cryptsetup-generator.c"
, 539, __func__, "Failed to open /etc/crypttab: %m") : -abs(_e
); })
;
540 return 0;
541 }
542
543 (void) __fsetlocking(f, FSETLOCKING_BYCALLERFSETLOCKING_BYCALLER);
544
545 if (fstat(fileno(f), &st) < 0) {
546 log_error_errno(errno, "Failed to stat /etc/crypttab: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/cryptsetup/cryptsetup-generator.c"
, 546, __func__, "Failed to stat /etc/crypttab: %m") : -abs(_e
); })
;
547 return 0;
548 }
549
550 for (;;) {
551 int r, k;
552 char line[LINE_MAX2048], *l, *uuid;
553 crypto_device *d = NULL((void*)0);
554 _cleanup_free___attribute__((cleanup(freep))) char *name = NULL((void*)0), *device = NULL((void*)0), *keydev = NULL((void*)0), *keyfile = NULL((void*)0), *keyspec = NULL((void*)0), *options = NULL((void*)0);
555
556 if (!fgets(line, sizeof(line), f))
557 break;
558
559 crypttab_line++;
560
561 l = strstrip(line);
562 if (IN_SET(*l, 0, '#')({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){0, '#'})/sizeof(int)]; switch(*l) { case
0: case '#': _found = 1; break; default: break; } _found; })
)
563 continue;
564
565 k = sscanf(l, "%ms %ms %ms %ms", &name, &device, &keyspec, &options);
566 if (k < 2 || k > 4) {
567 log_error("Failed to parse /etc/crypttab:%u, ignoring.", crypttab_line)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup-generator.c", 567, __func__, "Failed to parse /etc/crypttab:%u, ignoring."
, crypttab_line) : -abs(_e); })
;
568 continue;
569 }
570
571 uuid = startswith(device, "UUID=");
572 if (!uuid)
573 uuid = path_startswith(device, "/dev/disk/by-uuid/");
574 if (!uuid)
575 uuid = startswith(name, "luks-");
576 if (uuid)
577 d = hashmap_get(arg_disks, uuid);
578
579 if (arg_whitelist && !d) {
580 log_info("Not creating device '%s' because it was not specified on the kernel command line.", name)({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup-generator.c", 580, __func__, "Not creating device '%s' because it was not specified on the kernel command line."
, name) : -abs(_e); })
;
581 continue;
582 }
583
584 r = split_keyspec(keyspec, &keyfile, &keydev);
585 if (r < 0)
586 return r;
587
588 r = create_disk(name, device, keyfile, keydev, (d && d->options) ? d->options : options);
589 if (r < 0)
590 return r;
591
592 if (d)
593 d->create = false0;
594 }
595
596 return 0;
597}
598
599static int add_proc_cmdline_devices(void) {
600 int r;
601 Iterator i;
602 crypto_device *d;
603
604 HASHMAP_FOREACH(d, arg_disks, i)for ((i) = ((Iterator) { .idx = ((2147483647 *2U +1U) - 1), .
next_key = ((void*)0) }); hashmap_iterate((arg_disks), &(
i), (void**)&(d), ((void*)0)); )
{
605 const char *options;
606 _cleanup_free___attribute__((cleanup(freep))) char *device = NULL((void*)0);
607
608 if (!d->create)
609 continue;
610
611 if (!d->name) {
612 d->name = strappend("luks-", d->uuid);
613 if (!d->name)
614 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/cryptsetup/cryptsetup-generator.c"
, 614, __func__)
;
615 }
616
617 device = strappend("UUID=", d->uuid);
618 if (!device)
619 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/cryptsetup/cryptsetup-generator.c"
, 619, __func__)
;
620
621 if (d->options)
622 options = d->options;
623 else if (arg_default_options)
624 options = arg_default_options;
625 else
626 options = "timeout=0";
627
628 r = create_disk(d->name, device, d->keyfile ?: arg_default_keyfile, d->keydev, options);
629 if (r < 0)
630 return r;
631 }
632
633 return 0;
634}
635
636int main(int argc, char *argv[]) {
637 int r;
638
639 if (argc > 1 && argc != 4) {
640 log_error("This program takes three or no arguments.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup-generator.c", 640, __func__, "This program takes three or no arguments."
) : -abs(_e); })
;
641 return EXIT_FAILURE1;
642 }
643
644 if (argc > 1)
645 arg_dest = argv[1];
646
647 log_set_prohibit_ipc(true1);
648 log_set_target(LOG_TARGET_AUTO);
649 log_parse_environment()log_parse_environment_realm(LOG_REALM_SYSTEMD);
650 log_open();
651
652 umask(0022);
653
654 arg_disks = hashmap_new(&string_hash_ops)internal_hashmap_new(&string_hash_ops );
655 if (!arg_disks) {
656 r = log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/cryptsetup/cryptsetup-generator.c"
, 656, __func__)
;
657 goto finish;
658 }
659
660 r = proc_cmdline_parse(parse_proc_cmdline_item, NULL((void*)0), PROC_CMDLINE_STRIP_RD_PREFIX);
661 if (r < 0) {
662 log_warning_errno(r, "Failed to parse kernel command line: %m")({ int _level = ((4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup-generator.c", 662, __func__, "Failed to parse kernel command line: %m"
) : -abs(_e); })
;
663 goto finish;
664 }
665
666 if (!arg_enabled) {
667 r = 0;
668 goto finish;
669 }
670
671 r = add_crypttab_devices();
672 if (r < 0)
673 goto finish;
674
675 r = add_proc_cmdline_devices();
676 if (r < 0)
677 goto finish;
678
679 r = 0;
680
681finish:
682 hashmap_free_with_destructor(arg_disks, crypt_device_free)({ ({ void *_item; while ((_item = hashmap_steal_first(arg_disks
))) crypt_device_free(_item); }); hashmap_free(arg_disks); })
;
683 free(arg_default_options);
684 free(arg_default_keyfile);
685
686 return r < 0 ? EXIT_FAILURE1 : EXIT_SUCCESS0;
687}