• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 19979552133

05 Dec 2025 05:29PM UTC coverage: 72.765% (-0.2%) from 72.917%
19979552133

push

github

yuwata
udev-rules: use the right variable

We carefully prepare a copy of a local buffer to save in device cache
and then save the buffer there instead... This leads to abort in free()
on exit (also, copied is leaked).

Reproducer:
 # udevadm test /sys/block/sr0

Follow-up-for: a9559ebcb

Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=2406118

0 of 1 new or added line in 1 file covered. (0.0%)

1564 existing lines in 65 files now uncovered.

309707 of 425625 relevant lines covered (72.77%)

1149816.14 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/ssh-generator/ssh-generator.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <unistd.h>
4

5
#include "alloc-util.h"
6
#include "creds-util.h"
7
#include "errno-util.h"
8
#include "fd-util.h"
9
#include "fileio.h"
10
#include "generator.h"
11
#include "install.h"
12
#include "log.h"
13
#include "parse-util.h"
14
#include "path-lookup.h"
15
#include "path-util.h"
16
#include "proc-cmdline.h"
17
#include "socket-netlink.h"
18
#include "socket-util.h"
19
#include "special.h"
20
#include "ssh-util.h"
21
#include "string-util.h"
22
#include "strv.h"
23
#include "virt.h"
24

25
/* A small generator binding potentially five or more SSH sockets:
26
 *
27
 *     1. Listen on AF_VSOCK port 22 if we run in a VM with AF_VSOCK enabled
28
 *     2. Listen on AF_UNIX socket /run/host/unix-export/ssh if we run in a container with /run/host/ support
29
 *     3. Listen on AF_UNIX socket /run/ssh-unix-local/socket (always)
30
 *     4. Listen on any socket specified via kernel command line option systemd.ssh_listen=
31
 *     5. Similar, but from system credential ssh.listen
32
 *
33
 * The first two provide a nice way for hosts to connect to containers and VMs they invoke via the usual SSH
34
 * logic, but without waiting for networking or suchlike. The third allows the same for local clients. */
35

36
static const char *arg_dest = NULL;
37
static bool arg_auto = true;
38
static char **arg_listen_extra = NULL;
39

UNCOV
40
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
×
UNCOV
41
        int r;
×
42

UNCOV
43
        assert(key);
×
44

UNCOV
45
        if (proc_cmdline_key_streq(key, "systemd.ssh_auto")) {
×
46
                r = value ? parse_boolean(value) : 1;
×
47
                if (r < 0)
×
UNCOV
48
                        log_warning_errno(r, "Failed to parse systemd.ssh_auto switch \"%s\", ignoring: %m", value);
×
49
                else
50
                        arg_auto = r;
×
51

UNCOV
52
        } else if (proc_cmdline_key_streq(key, "systemd.ssh_listen")) {
×
53

54
                if (proc_cmdline_value_missing(key, value))
×
55
                        return 0;
×
56

57
                SocketAddress sa;
×
58
                r = socket_address_parse(&sa, value);
×
59
                if (r < 0)
×
60
                        log_warning_errno(r, "Failed to parse systemd.ssh_listen= expression, ignoring: %s", value);
×
61
                else {
62
                        _cleanup_free_ char *s = NULL;
×
63
                        r = socket_address_print(&sa, &s);
×
64
                        if (r < 0)
×
65
                                return log_error_errno(r, "Failed to format socket address: %m");
×
66

67
                        if (strv_consume(&arg_listen_extra, TAKE_PTR(s)) < 0)
×
68
                                return log_oom();
×
69
                }
70
        }
71

72
        return 0;
73
}
74

UNCOV
75
static int make_sshd_template_unit(
×
76
                const char *dest,
77
                const char *template,
78
                const char *sshd_binary,
79
                const char *found_sshd_template_service,
80
                char **generated_sshd_template_unit) {
81

UNCOV
82
        int r;
×
83

UNCOV
84
        assert(dest);
×
UNCOV
85
        assert(template);
×
UNCOV
86
        assert(sshd_binary);
×
UNCOV
87
        assert(generated_sshd_template_unit);
×
88

89
        /* If the system has a suitable template already, symlink it under the name we want to use */
UNCOV
90
        if (found_sshd_template_service)
×
UNCOV
91
                return generator_add_symlink(
×
92
                                dest,
93
                                template,
94
                                /* dep_type= */ NULL,
95
                                found_sshd_template_service);
96

97
        if (!*generated_sshd_template_unit) {
×
98
                _cleanup_fclose_ FILE *f = NULL;
×
99

100
                /* We use a generic name for the unit, since we'll use it for both AF_UNIX and AF_VSOCK  */
101
                r = generator_open_unit_file_full(
×
102
                                dest,
103
                                /* source= */ NULL,
104
                                "sshd-generated@.service",
105
                                &f,
106
                                generated_sshd_template_unit,
107
                                /* ret_temp_path= */ NULL);
108
                if (r < 0)
×
109
                        return r;
110

111
                fprintf(f,
×
112
                        "[Unit]\n"
113
                        "Description=OpenSSH Per-Connection Server Daemon\n"
114
                        "Documentation=man:systemd-ssh-generator(8) man:sshd(8)\n"
115
                        "\n"
116
                        "[Service]\n"
117
                        "ExecStart=-%s -i -o \"AuthorizedKeysFile ${CREDENTIALS_DIRECTORY}/ssh.ephemeral-authorized_keys-all .ssh/authorized_keys\"\n"
118
                        "StandardInput=socket\n"
119
                        "ImportCredential=ssh.ephemeral-authorized_keys-all\n",
120
                        sshd_binary);
121

122
                r = fflush_and_check(f);
×
123
                if (r < 0)
×
124
                        return log_error_errno(r, "Failed to write sshd template: %m");
×
125
        }
126

127
        return generator_add_symlink(
×
128
                        dest,
129
                        template,
130
                        /* dep_type= */ NULL,
131
                        *generated_sshd_template_unit);
132
}
133

UNCOV
134
static int write_socket_unit(
×
135
                const char *dest,
136
                const char *unit,
137
                const char *listen_stream,
138
                const char *comment,
139
                const char *extra,
140
                bool with_ssh_access_target_dependency) {
141

UNCOV
142
        int r;
×
143

UNCOV
144
        assert(dest);
×
UNCOV
145
        assert(unit);
×
UNCOV
146
        assert(listen_stream);
×
UNCOV
147
        assert(comment);
×
148

UNCOV
149
        _cleanup_fclose_ FILE *f = NULL;
×
UNCOV
150
        r = generator_open_unit_file(
×
151
                        dest,
152
                        /* source= */ NULL,
153
                        unit,
154
                        &f);
UNCOV
155
        if (r < 0)
×
156
                return r;
157

UNCOV
158
        fprintf(f,
×
159
                "[Unit]\n"
160
                "Description=OpenSSH Server Socket (systemd-ssh-generator, %s)\n"
161
                "Documentation=man:systemd-ssh-generator(8)\n",
162
                comment);
163

164
        /* When this is a remotely accessible socket let's mark this with a milestone: ssh-access.target */
UNCOV
165
        if (with_ssh_access_target_dependency)
×
UNCOV
166
                fputs("Wants=ssh-access.target\n"
×
167
                      "Before=ssh-access.target\n",
168
                      f);
169

UNCOV
170
        fprintf(f,
×
171
                "\n[Socket]\n"
172
                "ListenStream=%s\n"
173
                "Accept=yes\n"
174
                "PollLimitIntervalSec=30s\n"
175
                "PollLimitBurst=50\n",
176
                listen_stream);
177

UNCOV
178
        if (extra)
×
UNCOV
179
                fputs(extra, f);
×
180

UNCOV
181
        r = fflush_and_check(f);
×
UNCOV
182
        if (r < 0)
×
183
                return log_error_errno(r, "Failed to write %s SSH socket unit: %m", comment);
×
184

UNCOV
185
        r = generator_add_symlink(
×
186
                        dest,
187
                        SPECIAL_SOCKETS_TARGET,
188
                        "wants",
189
                        unit);
UNCOV
190
        if (r < 0)
×
191
                return r;
×
192

193
        return 0;
194
}
195

UNCOV
196
static int add_vsock_socket(
×
197
                const char *dest,
198
                const char *sshd_binary,
199
                const char *found_sshd_template_unit,
200
                char **generated_sshd_template_unit) {
201

UNCOV
202
        int r;
×
203

UNCOV
204
        assert(dest);
×
UNCOV
205
        assert(generated_sshd_template_unit);
×
206

UNCOV
207
        Virtualization v = detect_virtualization();
×
UNCOV
208
        if (v < 0)
×
209
                return log_error_errno(v, "Failed to detect if we run in a VM: %m");
×
UNCOV
210
        if (!VIRTUALIZATION_IS_VM(v)) {
×
211
                /* NB: if we are running in a container inside a VM, then we'll *not* do AF_VSOCK stuff */
UNCOV
212
                log_debug("Not running in a VM, not listening on AF_VSOCK.");
×
UNCOV
213
                return 0;
×
214
        }
215

UNCOV
216
        r = vsock_open_or_warn(/* ret= */ NULL);
×
UNCOV
217
        if (r <= 0)
×
218
                return r;
219

220
        /* Determine the local CID so that we can log it to help users to connect to this VM */
UNCOV
221
        unsigned local_cid;
×
UNCOV
222
        r = vsock_get_local_cid_or_warn(&local_cid);
×
UNCOV
223
        if (r <= 0)
×
224
                return r;
225

UNCOV
226
        r = make_sshd_template_unit(
×
227
                        dest,
228
                        "sshd-vsock@.service",
229
                        sshd_binary,
230
                        found_sshd_template_unit,
231
                        generated_sshd_template_unit);
UNCOV
232
        if (r < 0)
×
233
                return r;
234

UNCOV
235
        r = write_socket_unit(
×
236
                        dest,
237
                        "sshd-vsock.socket",
238
                        "vsock::22",
239
                        "AF_VSOCK",
240
                        "ExecStartPost=-/usr/lib/systemd/systemd-ssh-issue --make-vsock\n"
241
                        "ExecStopPre=-/usr/lib/systemd/systemd-ssh-issue --rm-vsock\n",
242
                        /* with_ssh_access_target_dependency= */ true);
UNCOV
243
        if (r < 0)
×
244
                return r;
245

UNCOV
246
        log_debug("Binding SSH to AF_VSOCK vsock::22.\n"
×
247
                  "→ connect via 'ssh vsock/%u' from host", local_cid);
248
        return 0;
249
}
250

UNCOV
251
static int add_local_unix_socket(
×
252
                const char *dest,
253
                const char *sshd_binary,
254
                const char *found_sshd_template_unit,
255
                char **generated_sshd_template_unit) {
256

UNCOV
257
        int r;
×
258

UNCOV
259
        assert(dest);
×
UNCOV
260
        assert(sshd_binary);
×
UNCOV
261
        assert(generated_sshd_template_unit);
×
262

UNCOV
263
        r = make_sshd_template_unit(
×
264
                        dest,
265
                        "sshd-unix-local@.service",
266
                        sshd_binary,
267
                        found_sshd_template_unit,
268
                        generated_sshd_template_unit);
UNCOV
269
        if (r < 0)
×
270
                return r;
271

UNCOV
272
        r = write_socket_unit(
×
273
                        dest,
274
                        "sshd-unix-local.socket",
275
                        "/run/ssh-unix-local/socket",
276
                        "AF_UNIX Local",
277
                        /* extra= */ NULL,
278
                        /* with_ssh_access_target_dependency= */ false);
UNCOV
279
        if (r < 0)
×
280
                return r;
281

UNCOV
282
        log_debug("Binding SSH to AF_UNIX socket /run/ssh-unix-local/socket.\n"
×
283
                  "→ connect via 'ssh .host' locally");
284
        return 0;
285
}
286

UNCOV
287
static int add_export_unix_socket(
×
288
                const char *dest,
289
                const char *sshd_binary,
290
                const char *found_sshd_template_unit,
291
                char **generated_sshd_template_unit) {
292

UNCOV
293
        int r;
×
294

UNCOV
295
        assert(dest);
×
UNCOV
296
        assert(sshd_binary);
×
UNCOV
297
        assert(generated_sshd_template_unit);
×
298

UNCOV
299
        Virtualization v = detect_container();
×
UNCOV
300
        if (v < 0)
×
301
                return log_error_errno(v, "Failed to detect if we run in a container: %m");
×
UNCOV
302
        if (v == VIRTUALIZATION_NONE) {
×
UNCOV
303
                log_debug("Not running in container, not listening on /run/host/unix-export/ssh");
×
UNCOV
304
                return 0;
×
305
        }
306

UNCOV
307
        if (access("/run/host/unix-export/", W_OK) < 0) {
×
308
                if (errno == ENOENT) {
×
309
                        log_debug("Container manager does not provide /run/host/unix-export/ mount, not binding AF_UNIX socket there.");
×
310
                        return 0;
×
311
                }
312
                if (ERRNO_IS_FS_WRITE_REFUSED(errno)) {
×
313
                        log_debug("Container manager does not provide write access to /run/host/unix-export/, not binding AF_UNIX socket there.");
×
314
                        return 0;
×
315
                }
316

317
                return log_error_errno(errno, "Unable to check if /run/host/unix-export exists: %m");
×
318
        }
319

UNCOV
320
        r = make_sshd_template_unit(
×
321
                        dest,
322
                        "sshd-unix-export@.service",
323
                        sshd_binary,
324
                        found_sshd_template_unit,
325
                        generated_sshd_template_unit);
UNCOV
326
        if (r < 0)
×
327
                return r;
328

UNCOV
329
        r = write_socket_unit(
×
330
                        dest,
331
                        "sshd-unix-export.socket",
332
                        "/run/host/unix-export/ssh",
333
                        "AF_UNIX Export",
334
                        /* extra= */ NULL,
335
                        /* with_ssh_access_target_dependency= */ true);
UNCOV
336
        if (r < 0)
×
337
                return r;
338

UNCOV
339
        log_debug("Binding SSH to AF_UNIX socket /run/host/unix-export/ssh\n"
×
340
                  "→ connect via 'ssh unix/run/systemd/nspawn/unix-export/\?\?\?/ssh' from host");
341

342
        return 0;
343
}
344

UNCOV
345
static int add_extra_sockets(
×
346
                const char *dest,
347
                const char *sshd_binary,
348
                const char *found_sshd_template_unit,
349
                char **generated_sshd_template_unit) {
350

UNCOV
351
        unsigned n = 1;
×
UNCOV
352
        int r;
×
353

UNCOV
354
        assert(dest);
×
UNCOV
355
        assert(sshd_binary);
×
UNCOV
356
        assert(generated_sshd_template_unit);
×
357

UNCOV
358
        if (strv_isempty(arg_listen_extra))
×
359
                return 0;
360

361
        STRV_FOREACH(i, arg_listen_extra) {
×
362
                _cleanup_free_ char *service = NULL, *socket = NULL;
×
363

364
                if (n > 1) {
×
365
                        if (asprintf(&service, "sshd-extra-%u@.service", n) < 0)
×
366
                                return log_oom();
×
367

368
                        if (asprintf(&socket, "sshd-extra-%u.socket", n) < 0)
×
369
                                return log_oom();
×
370
                }
371

372
                r = make_sshd_template_unit(
×
373
                                dest,
374
                                service ?: "sshd-extra@.service",
×
375
                                sshd_binary,
376
                                found_sshd_template_unit,
377
                                generated_sshd_template_unit);
378
                if (r < 0)
×
379
                        return r;
380

381
                r = write_socket_unit(
×
382
                                dest,
383
                                socket ?: "sshd-extra.socket",
×
384
                                *i,
385
                                *i,
386
                                /* extra= */ NULL,
387
                                /* with_ssh_access_target_dependency= */ true);
388
                if (r < 0)
×
389
                        return r;
390

391
                log_debug("Binding SSH to socket %s.", *i);
×
392
                n++;
×
393
        }
394

395
        return 0;
396
}
397

UNCOV
398
static int parse_credentials(void) {
×
UNCOV
399
        _cleanup_free_ char *b = NULL;
×
UNCOV
400
        size_t sz = 0;
×
UNCOV
401
        int r;
×
402

UNCOV
403
        r = read_credential_with_decryption("ssh.listen", (void**) &b, &sz);
×
UNCOV
404
        if (r <= 0)
×
405
                return r;
406

UNCOV
407
        _cleanup_fclose_ FILE *f = NULL;
×
408
        f = fmemopen_unlocked(b, sz, "r");
×
409
        if (!f)
×
410
                return log_oom();
×
411

412
        for (;;) {
×
413
                _cleanup_free_ char *item = NULL;
×
414

415
                r = read_stripped_line(f, LINE_MAX, &item);
×
416
                if (r == 0)
×
417
                        break;
418
                if (r < 0) {
×
419
                        log_error_errno(r, "Failed to parse credential 'ssh.listen': %m");
×
420
                        break;
421
                }
422

423
                if (startswith(item, "#"))
×
424
                        continue;
×
425

426
                SocketAddress sa;
×
427
                r = socket_address_parse(&sa, item);
×
428
                if (r < 0) {
×
429
                        log_warning_errno(r, "Failed to parse systemd.ssh_listen= expression, ignoring: %s", item);
×
430
                        continue;
×
431
                }
432

433
                _cleanup_free_ char *s = NULL;
×
434
                r = socket_address_print(&sa, &s);
×
435
                if (r < 0)
×
436
                        return log_error_errno(r, "Failed to format socket address: %m");
×
437

438
                if (strv_consume(&arg_listen_extra, TAKE_PTR(s)) < 0)
×
439
                        return log_oom();
×
440
        }
441

442
        return 0;
×
443
}
444

UNCOV
445
static int run(const char *dest, const char *dest_early, const char *dest_late) {
×
UNCOV
446
        int r;
×
447

UNCOV
448
        assert_se(arg_dest = dest);
×
449

UNCOV
450
        r = proc_cmdline_parse(parse_proc_cmdline_item, /* userdata= */ NULL, /* flags= */ 0);
×
UNCOV
451
        if (r < 0)
×
452
                log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
×
453

UNCOV
454
        (void) parse_credentials();
×
455

UNCOV
456
        strv_sort_uniq(arg_listen_extra);
×
457

UNCOV
458
        if (!arg_auto && strv_isempty(arg_listen_extra)) {
×
459
                log_debug("Disabling SSH generator logic, because it has been turned off explicitly.");
×
UNCOV
460
                return 0;
×
461
        }
462

UNCOV
463
        _cleanup_free_ char *sshd_binary = NULL;
×
UNCOV
464
        r = find_executable("sshd", &sshd_binary);
×
UNCOV
465
        if (r == -ENOENT) {
×
466
                log_debug("Disabling SSH generator logic, since sshd is not installed.");
×
467
                return 0;
×
468
        }
UNCOV
469
        if (r < 0)
×
470
                return log_error_errno(r, "Failed to determine if sshd is installed: %m");
×
471

UNCOV
472
        _cleanup_(lookup_paths_done) LookupPaths lp = {};
×
UNCOV
473
        r = lookup_paths_init_or_warn(&lp, RUNTIME_SCOPE_SYSTEM, LOOKUP_PATHS_EXCLUDE_GENERATED, /* root_dir= */ NULL);
×
UNCOV
474
        if (r < 0)
×
475
                return r;
476

UNCOV
477
        _cleanup_free_ char *found_sshd_template_unit = NULL;
×
UNCOV
478
        r = unit_file_exists_full(RUNTIME_SCOPE_SYSTEM, &lp, "sshd@.service", &found_sshd_template_unit);
×
UNCOV
479
        if (r < 0)
×
480
                return log_error_errno(r, "Unable to detect if sshd@.service exists: %m");
×
481

UNCOV
482
        _cleanup_free_ char *generated_sshd_template_unit = NULL;
×
UNCOV
483
        RET_GATHER(r, add_extra_sockets(dest, sshd_binary, found_sshd_template_unit, &generated_sshd_template_unit));
×
484

UNCOV
485
        if (arg_auto) {
×
UNCOV
486
                RET_GATHER(r, add_vsock_socket(dest, sshd_binary, found_sshd_template_unit, &generated_sshd_template_unit));
×
UNCOV
487
                RET_GATHER(r, add_local_unix_socket(dest, sshd_binary, found_sshd_template_unit, &generated_sshd_template_unit));
×
UNCOV
488
                RET_GATHER(r, add_export_unix_socket(dest, sshd_binary, found_sshd_template_unit, &generated_sshd_template_unit));
×
489
        }
490

UNCOV
491
        return r;
×
492
}
493

UNCOV
494
DEFINE_MAIN_GENERATOR_FUNCTION(run);
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc