Unrated severityNVD Advisory· Published Oct 26, 2018· Updated Jun 9, 2025
systemd: reexec state injection: fgets() on overlong lines leads to line splitting
CVE-2018-15686
Description
A vulnerability in unit_deserialize of systemd allows an attacker to supply arbitrary state across systemd re-execution via NotifyAccess. This can be used to improperly influence systemd execution and possibly lead to root privilege escalation. Affected releases are systemd versions up to and including 239.
Affected products
1Patches
19f1c81d80a43Merge pull request #10519 from poettering/serialize-fixes
34 files changed · +603 −528
docs/CODING_STYLE+4 −0 modified@@ -458,3 +458,7 @@ - When referring to a file system path that is a directory, please always suffix it with "/", to indicate that it is a directory, not a regular file (or other file system object). + +- Don't use fgets(), it's too hard to properly handle errors such as overly + long lines. Use read_line() instead, which is our own function that handles + this much nicer.
src/basic/env-util.c+0 −33 modified@@ -752,36 +752,3 @@ int getenv_bool_secure(const char *p) { return parse_boolean(e); } - -int serialize_environment(FILE *f, char **environment) { - char **e; - - STRV_FOREACH(e, environment) { - _cleanup_free_ char *ce; - - ce = cescape(*e); - if (!ce) - return -ENOMEM; - - fprintf(f, "env=%s\n", ce); - } - - /* caller should call ferror() */ - - return 0; -} - -int deserialize_environment(char ***environment, const char *line) { - char *uce; - int r; - - assert(line); - assert(environment); - - assert(startswith(line, "env=")); - r = cunescape(line + 4, 0, &uce); - if (r < 0) - return r; - - return strv_env_replace(environment, uce); -}
src/basic/env-util.h+0 −3 modified@@ -45,6 +45,3 @@ char *strv_env_get(char **x, const char *n) _pure_; int getenv_bool(const char *p); int getenv_bool_secure(const char *p); - -int serialize_environment(FILE *f, char **environment); -int deserialize_environment(char ***environment, const char *line);
src/basic/exec-util.c+31 −11 modified@@ -9,13 +9,15 @@ #include "alloc-util.h" #include "conf-files.h" +#include "def.h" #include "env-util.h" #include "exec-util.h" #include "fd-util.h" #include "fileio.h" #include "hashmap.h" #include "macro.h" #include "process-util.h" +#include "serialize.h" #include "set.h" #include "signal-util.h" #include "stat-util.h" @@ -282,7 +284,7 @@ static int gather_environment_collect(int fd, void *arg) { return -errno; } - r = serialize_environment(f, *env); + r = serialize_strv(f, "env", *env); if (r < 0) return r; @@ -294,29 +296,47 @@ static int gather_environment_collect(int fd, void *arg) { } static int gather_environment_consume(int fd, void *arg) { - char ***env = arg; _cleanup_fclose_ FILE *f = NULL; - char line[LINE_MAX]; - int r = 0, k; + char ***env = arg; + int r = 0; /* Read a series of env=cescape(VAR=value) assignments from fd into env. */ assert(env); - f = fdopen(fd, "r"); + f = fdopen(fd, "re"); if (!f) { safe_close(fd); return -errno; } - FOREACH_LINE(line, f, return -EIO) { - truncate_nl(line); + for (;;) { + _cleanup_free_ char *line = NULL; + const char *v; + int k; - k = deserialize_environment(env, line); + k = read_line(f, LONG_LINE_MAX, &line); if (k < 0) - log_error_errno(k, "Invalid line \"%s\": %m", line); - if (k < 0 && r == 0) - r = k; + return k; + if (k == 0) + break; + + v = startswith(line, "env="); + if (!v) { + log_debug("Serialization line \"%s\" unexpectedly didn't start with \"env=\".", line); + if (r == 0) + r = -EINVAL; + + continue; + } + + k = deserialize_environment(v, env); + if (k < 0) { + log_debug_errno(k, "Invalid serialization line \"%s\": %m", line); + + if (r == 0) + r = k; + } } return r;
src/basic/fileio.h+0 −9 modified@@ -59,15 +59,6 @@ DIR *xopendirat(int dirfd, const char *name, int flags); int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f); int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f); -#define FOREACH_LINE(line, f, on_error) \ - for (;;) \ - if (!fgets(line, sizeof(line), f)) { \ - if (ferror(f)) { \ - on_error; \ - } \ - break; \ - } else - int fflush_and_check(FILE *f); int fflush_sync_and_check(FILE *f);
src/basic/time-util.c+1 −58 modified@@ -24,6 +24,7 @@ #include "parse-util.h" #include "path-util.h" #include "process-util.h" +#include "serialize.h" #include "stat-util.h" #include "string-util.h" #include "strv.h" @@ -530,64 +531,6 @@ char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) { return buf; } -void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) { - - assert(f); - assert(name); - assert(t); - - if (!dual_timestamp_is_set(t)) - return; - - fprintf(f, "%s="USEC_FMT" "USEC_FMT"\n", - name, - t->realtime, - t->monotonic); -} - -int dual_timestamp_deserialize(const char *value, dual_timestamp *t) { - uint64_t a, b; - int r, pos; - - assert(value); - assert(t); - - pos = strspn(value, WHITESPACE); - if (value[pos] == '-') - return -EINVAL; - pos += strspn(value + pos, DIGITS); - pos += strspn(value + pos, WHITESPACE); - if (value[pos] == '-') - return -EINVAL; - - r = sscanf(value, "%" PRIu64 "%" PRIu64 "%n", &a, &b, &pos); - if (r != 2) { - log_debug("Failed to parse dual timestamp value \"%s\".", value); - return -EINVAL; - } - - if (value[pos] != '\0') - /* trailing garbage */ - return -EINVAL; - - t->realtime = a; - t->monotonic = b; - - return 0; -} - -int timestamp_deserialize(const char *value, usec_t *timestamp) { - int r; - - assert(value); - - r = safe_atou64(value, timestamp); - if (r < 0) - return log_debug_errno(r, "Failed to parse timestamp value \"%s\": %m", value); - - return r; -} - static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) { static const struct { const char *name;
src/basic/time-util.h+0 −4 modified@@ -108,10 +108,6 @@ char *format_timestamp_us_utc(char *buf, size_t l, usec_t t); char *format_timestamp_relative(char *buf, size_t l, usec_t t); char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy); -void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t); -int dual_timestamp_deserialize(const char *value, dual_timestamp *t); -int timestamp_deserialize(const char *value, usec_t *timestamp); - int parse_timestamp(const char *t, usec_t *usec); int parse_sec(const char *t, usec_t *usec);
src/core/automount.c+11 −9 modified@@ -26,6 +26,7 @@ #include "parse-util.h" #include "path-util.h" #include "process-util.h" +#include "serialize.h" #include "special.h" #include "stdio-util.h" #include "string-table.h" @@ -841,16 +842,16 @@ static int automount_serialize(Unit *u, FILE *f, FDSet *fds) { assert(f); assert(fds); - unit_serialize_item(u, f, "state", automount_state_to_string(a->state)); - unit_serialize_item(u, f, "result", automount_result_to_string(a->result)); - unit_serialize_item_format(u, f, "dev-id", "%u", (unsigned) a->dev_id); + (void) serialize_item(f, "state", automount_state_to_string(a->state)); + (void) serialize_item(f, "result", automount_result_to_string(a->result)); + (void) serialize_item_format(f, "dev-id", "%lu", (unsigned long) a->dev_id); SET_FOREACH(p, a->tokens, i) - unit_serialize_item_format(u, f, "token", "%u", PTR_TO_UINT(p)); + (void) serialize_item_format(f, "token", "%u", PTR_TO_UINT(p)); SET_FOREACH(p, a->expire_tokens, i) - unit_serialize_item_format(u, f, "expire-token", "%u", PTR_TO_UINT(p)); + (void) serialize_item_format(f, "expire-token", "%u", PTR_TO_UINT(p)); - r = unit_serialize_item_fd(u, f, fds, "pipe-fd", a->pipe_fd); + r = serialize_fd(f, fds, "pipe-fd", a->pipe_fd); if (r < 0) return r; @@ -882,12 +883,13 @@ static int automount_deserialize_item(Unit *u, const char *key, const char *valu a->result = f; } else if (streq(key, "dev-id")) { - unsigned d; + unsigned long d; - if (safe_atou(value, &d) < 0) + if (safe_atolu(value, &d) < 0) log_unit_debug(u, "Failed to parse dev-id value: %s", value); else - a->dev_id = (unsigned) d; + a->dev_id = (dev_t) d; + } else if (streq(key, "token")) { unsigned token;
src/core/dbus.c+3 −7 modified@@ -36,6 +36,7 @@ #include "mkdir.h" #include "process-util.h" #include "selinux-access.h" +#include "serialize.h" #include "service.h" #include "special.h" #include "string-util.h" @@ -1204,13 +1205,8 @@ void bus_track_serialize(sd_bus_track *t, FILE *f, const char *prefix) { int c, j; c = sd_bus_track_count_name(t, n); - - for (j = 0; j < c; j++) { - fputs(prefix, f); - fputc('=', f); - fputs(n, f); - fputc('\n', f); - } + for (j = 0; j < c; j++) + (void) serialize_item(f, prefix, n); } }
src/core/device.c+3 −2 modified@@ -12,6 +12,7 @@ #include "log.h" #include "parse-util.h" #include "path-util.h" +#include "serialize.h" #include "stat-util.h" #include "string-util.h" #include "swap.h" @@ -225,10 +226,10 @@ static int device_serialize(Unit *u, FILE *f, FDSet *fds) { assert(f); assert(fds); - unit_serialize_item(u, f, "state", device_state_to_string(d->state)); + (void) serialize_item(f, "state", device_state_to_string(d->state)); if (device_found_to_string_many(d->found, &s) >= 0) - unit_serialize_item(u, f, "found", s); + (void) serialize_item(f, "found", s); return 0; }
src/core/dynamic-user.c+4 −3 modified@@ -12,6 +12,7 @@ #include "io-util.h" #include "parse-util.h" #include "random-util.h" +#include "serialize.h" #include "socket-util.h" #include "stdio-util.h" #include "string-util.h" @@ -607,13 +608,13 @@ int dynamic_user_serialize(Manager *m, FILE *f, FDSet *fds) { copy0 = fdset_put_dup(fds, d->storage_socket[0]); if (copy0 < 0) - return copy0; + return log_error_errno(copy0, "Failed to add dynamic user storage fd to serialization: %m"); copy1 = fdset_put_dup(fds, d->storage_socket[1]); if (copy1 < 0) - return copy1; + return log_error_errno(copy1, "Failed to add dynamic user storage fd to serialization: %m"); - fprintf(f, "dynamic-user=%s %i %i\n", d->name, copy0, copy1); + (void) serialize_item_format(f, "dynamic-user", "%s %i %i", d->name, copy0, copy1); } return 0;
src/core/job.c+28 −34 modified@@ -10,10 +10,12 @@ #include "dbus-job.h" #include "dbus.h" #include "escape.h" +#include "fileio.h" #include "job.h" #include "log.h" #include "macro.h" #include "parse-util.h" +#include "serialize.h" #include "set.h" #include "special.h" #include "stdio-util.h" @@ -1074,17 +1076,17 @@ int job_serialize(Job *j, FILE *f) { assert(j); assert(f); - fprintf(f, "job-id=%u\n", j->id); - fprintf(f, "job-type=%s\n", job_type_to_string(j->type)); - fprintf(f, "job-state=%s\n", job_state_to_string(j->state)); - fprintf(f, "job-irreversible=%s\n", yes_no(j->irreversible)); - fprintf(f, "job-sent-dbus-new-signal=%s\n", yes_no(j->sent_dbus_new_signal)); - fprintf(f, "job-ignore-order=%s\n", yes_no(j->ignore_order)); + (void) serialize_item_format(f, "job-id", "%u", j->id); + (void) serialize_item(f, "job-type", job_type_to_string(j->type)); + (void) serialize_item(f, "job-state", job_state_to_string(j->state)); + (void) serialize_bool(f, "job-irreversible", j->irreversible); + (void) serialize_bool(f, "job-sent-dbus-new-signal", j->sent_dbus_new_signal); + (void) serialize_bool(f, "job-ignore-order", j->ignore_order); if (j->begin_usec > 0) - fprintf(f, "job-begin="USEC_FMT"\n", j->begin_usec); + (void) serialize_usec(f, "job-begin", j->begin_usec); if (j->begin_running_usec > 0) - fprintf(f, "job-begin-running="USEC_FMT"\n", j->begin_running_usec); + (void) serialize_usec(f, "job-begin-running", j->begin_running_usec); bus_track_serialize(j->bus_track, f, "subscribed"); @@ -1094,24 +1096,26 @@ int job_serialize(Job *j, FILE *f) { } int job_deserialize(Job *j, FILE *f) { + int r; + assert(j); assert(f); for (;;) { - char line[LINE_MAX], *l, *v; + _cleanup_free_ char *line = NULL; + char *l, *v; size_t k; - if (!fgets(line, sizeof(line), f)) { - if (feof(f)) - return 0; - return -errno; - } + r = read_line(f, LONG_LINE_MAX, &line); + if (r < 0) + return log_error_errno(r, "Failed to read serialization line: %m"); + if (r == 0) + return 0; - char_array_0(line); l = strstrip(line); /* End marker */ - if (l[0] == 0) + if (isempty(l)) return 0; k = strcspn(l, "="); @@ -1174,27 +1178,17 @@ int job_deserialize(Job *j, FILE *f) { else j->ignore_order = j->ignore_order || b; - } else if (streq(l, "job-begin")) { - unsigned long long ull; + } else if (streq(l, "job-begin")) + (void) deserialize_usec(v, &j->begin_usec); - if (sscanf(v, "%llu", &ull) != 1) - log_debug("Failed to parse job-begin value %s", v); - else - j->begin_usec = ull; - - } else if (streq(l, "job-begin-running")) { - unsigned long long ull; - - if (sscanf(v, "%llu", &ull) != 1) - log_debug("Failed to parse job-begin-running value %s", v); - else - j->begin_running_usec = ull; - - } else if (streq(l, "subscribed")) { + else if (streq(l, "job-begin-running")) + (void) deserialize_usec(v, &j->begin_running_usec); + else if (streq(l, "subscribed")) { if (strv_extend(&j->deserialized_clients, v) < 0) - log_oom(); - } + return log_oom(); + } else + log_debug("Unknown job serialization key: %s", l); } }
src/core/main.c+1 −1 modified@@ -1145,7 +1145,7 @@ static int prepare_reexecute( r = manager_serialize(m, f, fds, switching_root); if (r < 0) - return log_error_errno(r, "Failed to serialize state: %m"); + return r; if (fseeko(f, 0, SEEK_SET) == (off_t) -1) return log_error_errno(errno, "Failed to rewind serialization fd: %m");
src/core/manager.c+70 −67 modified@@ -22,8 +22,8 @@ #include "sd-messages.h" #include "sd-path.h" -#include "alloc-util.h" #include "all-units.h" +#include "alloc-util.h" #include "audit-fd.h" #include "boot-timestamps.h" #include "bus-common-errors.h" @@ -61,6 +61,7 @@ #include "ratelimit.h" #include "rlimit-util.h" #include "rm-rf.h" +#include "serialize.h" #include "signal-util.h" #include "socket-util.h" #include "special.h" @@ -3082,6 +3083,19 @@ int manager_open_serialization(Manager *m, FILE **_f) { return 0; } +static bool manager_timestamp_shall_serialize(ManagerTimestamp t) { + + if (!in_initrd()) + return true; + + /* The following timestamps only apply to the host system, hence only serialize them there */ + return !IN_SET(t, + MANAGER_TIMESTAMP_USERSPACE, MANAGER_TIMESTAMP_FINISH, + MANAGER_TIMESTAMP_SECURITY_START, MANAGER_TIMESTAMP_SECURITY_FINISH, + MANAGER_TIMESTAMP_GENERATORS_START, MANAGER_TIMESTAMP_GENERATORS_FINISH, + MANAGER_TIMESTAMP_UNITS_LOAD_START, MANAGER_TIMESTAMP_UNITS_LOAD_FINISH); +} + int manager_serialize( Manager *m, FILE *f, @@ -3100,73 +3114,65 @@ int manager_serialize( _cleanup_(manager_reloading_stopp) _unused_ Manager *reloading = manager_reloading_start(m); - fprintf(f, "current-job-id=%"PRIu32"\n", m->current_job_id); - fprintf(f, "n-installed-jobs=%u\n", m->n_installed_jobs); - fprintf(f, "n-failed-jobs=%u\n", m->n_failed_jobs); - fprintf(f, "taint-usr=%s\n", yes_no(m->taint_usr)); - fprintf(f, "ready-sent=%s\n", yes_no(m->ready_sent)); - fprintf(f, "taint-logged=%s\n", yes_no(m->taint_logged)); - fprintf(f, "service-watchdogs=%s\n", yes_no(m->service_watchdogs)); + (void) serialize_item_format(f, "current-job-id", "%" PRIu32, m->current_job_id); + (void) serialize_item_format(f, "n-installed-jobs", "%u", m->n_installed_jobs); + (void) serialize_item_format(f, "n-failed-jobs", "%u", m->n_failed_jobs); + (void) serialize_bool(f, "taint-usr", m->taint_usr); + (void) serialize_bool(f, "ready-sent", m->ready_sent); + (void) serialize_bool(f, "taint-logged", m->taint_logged); + (void) serialize_bool(f, "service-watchdogs", m->service_watchdogs); t = show_status_to_string(m->show_status); if (t) - fprintf(f, "show-status=%s\n", t); + (void) serialize_item(f, "show-status", t); if (m->log_level_overridden) - fprintf(f, "log-level-override=%i\n", log_get_max_level()); + (void) serialize_item_format(f, "log-level-override", "%i", log_get_max_level()); if (m->log_target_overridden) - fprintf(f, "log-target-override=%s\n", log_target_to_string(log_get_target())); + (void) serialize_item(f, "log-target-override", log_target_to_string(log_get_target())); for (q = 0; q < _MANAGER_TIMESTAMP_MAX; q++) { - /* The following timestamps only apply to the host system, hence only serialize them there */ - if (in_initrd() && - IN_SET(q, MANAGER_TIMESTAMP_USERSPACE, MANAGER_TIMESTAMP_FINISH, - MANAGER_TIMESTAMP_SECURITY_START, MANAGER_TIMESTAMP_SECURITY_FINISH, - MANAGER_TIMESTAMP_GENERATORS_START, MANAGER_TIMESTAMP_GENERATORS_FINISH, - MANAGER_TIMESTAMP_UNITS_LOAD_START, MANAGER_TIMESTAMP_UNITS_LOAD_FINISH)) + _cleanup_free_ char *joined = NULL; + + if (!manager_timestamp_shall_serialize(q)) continue; - t = manager_timestamp_to_string(q); - const char *field = strjoina(t, "-timestamp"); - dual_timestamp_serialize(f, field, m->timestamps + q); + joined = strjoin(manager_timestamp_to_string(q), "-timestamp"); + if (!joined) + return log_oom(); + + (void) serialize_dual_timestamp(f, joined, m->timestamps + q); } if (!switching_root) - (void) serialize_environment(f, m->environment); + (void) serialize_strv(f, "env", m->environment); if (m->notify_fd >= 0) { - int copy; - - copy = fdset_put_dup(fds, m->notify_fd); - if (copy < 0) - return copy; + r = serialize_fd(f, fds, "notify-fd", m->notify_fd); + if (r < 0) + return r; - fprintf(f, "notify-fd=%i\n", copy); - fprintf(f, "notify-socket=%s\n", m->notify_socket); + (void) serialize_item(f, "notify-socket", m->notify_socket); } if (m->cgroups_agent_fd >= 0) { - int copy; - - copy = fdset_put_dup(fds, m->cgroups_agent_fd); - if (copy < 0) - return copy; - - fprintf(f, "cgroups-agent-fd=%i\n", copy); + r = serialize_fd(f, fds, "cgroups-agent-fd", m->cgroups_agent_fd); + if (r < 0) + return r; } if (m->user_lookup_fds[0] >= 0) { int copy0, copy1; copy0 = fdset_put_dup(fds, m->user_lookup_fds[0]); if (copy0 < 0) - return copy0; + return log_error_errno(copy0, "Failed to add user lookup fd to serialization: %m"); copy1 = fdset_put_dup(fds, m->user_lookup_fds[1]); if (copy1 < 0) - return copy1; + return log_error_errno(copy1, "Failed to add user lookup fd to serialization: %m"); - fprintf(f, "user-lookup=%i %i\n", copy0, copy1); + (void) serialize_item_format(f, "user-lookup", "%i %i", copy0, copy1); } bus_track_serialize(m->subscribed, f, "subscribed"); @@ -3199,11 +3205,11 @@ int manager_serialize( r = fflush_and_check(f); if (r < 0) - return r; + return log_error_errno(r, "Failed to flush serialization: %m"); r = bus_fdset_add_all(m, fds); if (r < 0) - return r; + return log_error_errno(r, "Failed to add bus sockets to serialization: %m"); return 0; } @@ -3222,20 +3228,17 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { _cleanup_(manager_reloading_stopp) _unused_ Manager *reloading = manager_reloading_start(m); for (;;) { - char line[LINE_MAX]; + _cleanup_free_ char *line = NULL; const char *val, *l; - errno = 0; - if (!fgets(line, sizeof(line), f)) { - if (!feof(f)) - return -errno ?: -EIO; - return 0; - } + r = read_line(f, LONG_LINE_MAX, &line); + if (r < 0) + return log_error_errno(r, "Failed to read serialization line: %m"); + if (r == 0) + break; - char_array_0(line); l = strstrip(line); - - if (l[0] == 0) + if (isempty(l)) /* end marker */ break; if ((val = startswith(l, "current-job-id="))) { @@ -3326,9 +3329,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { manager_override_log_target(m, target); } else if (startswith(l, "env=")) { - r = deserialize_environment(&m->environment, l); - if (r == -ENOMEM) - return r; + r = deserialize_environment(l + 4, &m->environment); if (r < 0) log_notice_errno(r, "Failed to parse environment entry: \"%s\", ignoring: %m", l); @@ -3398,35 +3399,37 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { } if (q < _MANAGER_TIMESTAMP_MAX) /* found it */ - dual_timestamp_deserialize(val, m->timestamps + q); + (void) deserialize_dual_timestamp(val, m->timestamps + q); else if (!startswith(l, "kdbus-fd=")) /* ignore kdbus */ log_notice("Unknown serialization item '%s', ignoring.", l); } } for (;;) { - Unit *u; - char name[UNIT_NAME_MAX+2]; + _cleanup_free_ char *line = NULL; const char* unit_name; + Unit *u; /* Start marker */ - errno = 0; - if (!fgets(name, sizeof(name), f)) { - if (!feof(f)) - return -errno ?: -EIO; - return 0; - } + r = read_line(f, LONG_LINE_MAX, &line); + if (r < 0) + return log_error_errno(r, "Failed to read serialization line: %m"); + if (r == 0) + break; - char_array_0(name); - unit_name = strstrip(name); + unit_name = strstrip(line); r = manager_load_unit(m, unit_name, NULL, NULL, &u); if (r < 0) { if (r == -ENOMEM) return r; log_notice_errno(r, "Failed to load unit \"%s\", skipping deserialization: %m", unit_name); - unit_deserialize_skip(f); + + r = unit_deserialize_skip(f); + if (r < 0) + return r; + continue; } @@ -3474,7 +3477,7 @@ int manager_reload(Manager *m) { r = manager_serialize(m, f, fds, false); if (r < 0) - return log_error_errno(r, "Failed to serialize manager: %m"); + return r; if (fseeko(f, 0, SEEK_SET) < 0) return log_error_errno(errno, "Failed to seek to beginning of serialization: %m"); @@ -4342,7 +4345,7 @@ static void manager_serialize_uid_refs_internal( if (!(c & DESTROY_IPC_FLAG)) continue; - fprintf(f, "%s=" UID_FMT "\n", field_name, uid); + (void) serialize_item_format(f, field_name, UID_FMT, uid); } }
src/core/mount.c+6 −5 modified@@ -25,6 +25,7 @@ #include "parse-util.h" #include "path-util.h" #include "process-util.h" +#include "serialize.h" #include "special.h" #include "string-table.h" #include "string-util.h" @@ -1140,15 +1141,15 @@ static int mount_serialize(Unit *u, FILE *f, FDSet *fds) { assert(f); assert(fds); - unit_serialize_item(u, f, "state", mount_state_to_string(m->state)); - unit_serialize_item(u, f, "result", mount_result_to_string(m->result)); - unit_serialize_item(u, f, "reload-result", mount_result_to_string(m->reload_result)); + (void) serialize_item(f, "state", mount_state_to_string(m->state)); + (void) serialize_item(f, "result", mount_result_to_string(m->result)); + (void) serialize_item(f, "reload-result", mount_result_to_string(m->reload_result)); if (m->control_pid > 0) - unit_serialize_item_format(u, f, "control-pid", PID_FMT, m->control_pid); + (void) serialize_item_format(f, "control-pid", PID_FMT, m->control_pid); if (m->control_command_id >= 0) - unit_serialize_item(u, f, "control-command", mount_exec_command_to_string(m->control_command_id)); + (void) serialize_item(f, "control-command", mount_exec_command_to_string(m->control_command_id)); return 0; }
src/core/path.c+3 −2 modified@@ -14,6 +14,7 @@ #include "macro.h" #include "mkdir.h" #include "path.h" +#include "serialize.h" #include "special.h" #include "stat-util.h" #include "string-table.h" @@ -600,8 +601,8 @@ static int path_serialize(Unit *u, FILE *f, FDSet *fds) { assert(f); assert(fds); - unit_serialize_item(u, f, "state", path_state_to_string(p->state)); - unit_serialize_item(u, f, "result", path_result_to_string(p->result)); + (void) serialize_item(f, "state", path_state_to_string(p->state)); + (void) serialize_item(f, "result", path_result_to_string(p->result)); return 0; }
src/core/scope.c+5 −4 modified@@ -8,6 +8,7 @@ #include "load-dropin.h" #include "log.h" #include "scope.h" +#include "serialize.h" #include "special.h" #include "string-table.h" #include "string-util.h" @@ -402,11 +403,11 @@ static int scope_serialize(Unit *u, FILE *f, FDSet *fds) { assert(f); assert(fds); - unit_serialize_item(u, f, "state", scope_state_to_string(s->state)); - unit_serialize_item(u, f, "was-abandoned", yes_no(s->was_abandoned)); + (void) serialize_item(f, "state", scope_state_to_string(s->state)); + (void) serialize_bool(f, "was-abandoned", s->was_abandoned); if (s->controller) - unit_serialize_item(u, f, "controller", s->controller); + (void) serialize_item(f, "controller", s->controller); return 0; } @@ -441,7 +442,7 @@ static int scope_deserialize_item(Unit *u, const char *key, const char *value, F r = free_and_strdup(&s->controller, value); if (r < 0) - log_oom(); + return log_oom(); } else log_unit_debug(u, "Unknown serialization key: %s", key);
src/core/service.c+56 −51 modified@@ -27,6 +27,7 @@ #include "parse-util.h" #include "path-util.h" #include "process-util.h" +#include "serialize.h" #include "service.h" #include "signal-util.h" #include "special.h" @@ -2431,13 +2432,13 @@ static unsigned service_exec_command_index(Unit *u, ServiceExecCommand id, ExecC } static int service_serialize_exec_command(Unit *u, FILE *f, ExecCommand *command) { + _cleanup_free_ char *args = NULL, *p = NULL; + size_t allocated = 0, length = 0; Service *s = SERVICE(u); + const char *type, *key; ServiceExecCommand id; unsigned idx; - const char *type; char **arg; - _cleanup_free_ char *args = NULL, *p = NULL; - size_t allocated = 0, length = 0; assert(s); assert(f); @@ -2456,16 +2457,16 @@ static int service_serialize_exec_command(Unit *u, FILE *f, ExecCommand *command idx = service_exec_command_index(u, id, command); STRV_FOREACH(arg, command->argv) { - size_t n; _cleanup_free_ char *e = NULL; + size_t n; - e = xescape(*arg, WHITESPACE); + e = cescape(*arg); if (!e) - return -ENOMEM; + return log_oom(); n = strlen(e); if (!GREEDY_REALLOC(args, allocated, length + 1 + n + 1)) - return -ENOMEM; + return log_oom(); if (length > 0) args[length++] = ' '; @@ -2475,16 +2476,16 @@ static int service_serialize_exec_command(Unit *u, FILE *f, ExecCommand *command } if (!GREEDY_REALLOC(args, allocated, length + 1)) - return -ENOMEM; + return log_oom(); + args[length++] = 0; - p = xescape(command->path, WHITESPACE); + p = cescape(command->path); if (!p) return -ENOMEM; - fprintf(f, "%s-command=%s %u %s %s\n", type, service_exec_command_to_string(id), idx, p, args); - - return 0; + key = strjoina(type, "-command"); + return serialize_item_format(f, key, "%s %u %s %s", service_exec_command_to_string(id), idx, p, args); } static int service_serialize(Unit *u, FILE *f, FDSet *fds) { @@ -2496,54 +2497,55 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) { assert(f); assert(fds); - unit_serialize_item(u, f, "state", service_state_to_string(s->state)); - unit_serialize_item(u, f, "result", service_result_to_string(s->result)); - unit_serialize_item(u, f, "reload-result", service_result_to_string(s->reload_result)); + (void) serialize_item(f, "state", service_state_to_string(s->state)); + (void) serialize_item(f, "result", service_result_to_string(s->result)); + (void) serialize_item(f, "reload-result", service_result_to_string(s->reload_result)); if (s->control_pid > 0) - unit_serialize_item_format(u, f, "control-pid", PID_FMT, s->control_pid); + (void) serialize_item_format(f, "control-pid", PID_FMT, s->control_pid); if (s->main_pid_known && s->main_pid > 0) - unit_serialize_item_format(u, f, "main-pid", PID_FMT, s->main_pid); + (void) serialize_item_format(f, "main-pid", PID_FMT, s->main_pid); - unit_serialize_item(u, f, "main-pid-known", yes_no(s->main_pid_known)); - unit_serialize_item(u, f, "bus-name-good", yes_no(s->bus_name_good)); - unit_serialize_item(u, f, "bus-name-owner", s->bus_name_owner); + (void) serialize_bool(f, "main-pid-known", s->main_pid_known); + (void) serialize_bool(f, "bus-name-good", s->bus_name_good); + (void) serialize_bool(f, "bus-name-owner", s->bus_name_owner); - unit_serialize_item_format(u, f, "n-restarts", "%u", s->n_restarts); - unit_serialize_item(u, f, "flush-n-restarts", yes_no(s->flush_n_restarts)); + (void) serialize_item_format(f, "n-restarts", "%u", s->n_restarts); + (void) serialize_bool(f, "flush-n-restarts", s->flush_n_restarts); - r = unit_serialize_item_escaped(u, f, "status-text", s->status_text); + r = serialize_item_escaped(f, "status-text", s->status_text); if (r < 0) return r; service_serialize_exec_command(u, f, s->control_command); service_serialize_exec_command(u, f, s->main_command); - r = unit_serialize_item_fd(u, f, fds, "stdin-fd", s->stdin_fd); + r = serialize_fd(f, fds, "stdin-fd", s->stdin_fd); if (r < 0) return r; - r = unit_serialize_item_fd(u, f, fds, "stdout-fd", s->stdout_fd); + r = serialize_fd(f, fds, "stdout-fd", s->stdout_fd); if (r < 0) return r; - r = unit_serialize_item_fd(u, f, fds, "stderr-fd", s->stderr_fd); + r = serialize_fd(f, fds, "stderr-fd", s->stderr_fd); if (r < 0) return r; if (s->exec_fd_event_source) { - r = unit_serialize_item_fd(u, f, fds, "exec-fd", sd_event_source_get_io_fd(s->exec_fd_event_source)); + r = serialize_fd(f, fds, "exec-fd", sd_event_source_get_io_fd(s->exec_fd_event_source)); if (r < 0) return r; - unit_serialize_item(u, f, "exec-fd-hot", yes_no(s->exec_fd_hot)); + + (void) serialize_bool(f, "exec-fd-hot", s->exec_fd_hot); } if (UNIT_ISSET(s->accept_socket)) { - r = unit_serialize_item(u, f, "accept-socket", UNIT_DEREF(s->accept_socket)->id); + r = serialize_item(f, "accept-socket", UNIT_DEREF(s->accept_socket)->id); if (r < 0) return r; } - r = unit_serialize_item_fd(u, f, fds, "socket-fd", s->socket_fd); + r = serialize_fd(f, fds, "socket-fd", s->socket_fd); if (r < 0) return r; @@ -2553,30 +2555,31 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) { copy = fdset_put_dup(fds, fs->fd); if (copy < 0) - return copy; + return log_error_errno(copy, "Failed to copy file descriptor for serialization: %m"); c = cescape(fs->fdname); + if (!c) + return log_oom(); - unit_serialize_item_format(u, f, "fd-store-fd", "%i %s", copy, strempty(c)); + (void) serialize_item_format(f, "fd-store-fd", "%i %s", copy, c); } if (s->main_exec_status.pid > 0) { - unit_serialize_item_format(u, f, "main-exec-status-pid", PID_FMT, s->main_exec_status.pid); - dual_timestamp_serialize(f, "main-exec-status-start", &s->main_exec_status.start_timestamp); - dual_timestamp_serialize(f, "main-exec-status-exit", &s->main_exec_status.exit_timestamp); + (void) serialize_item_format(f, "main-exec-status-pid", PID_FMT, s->main_exec_status.pid); + (void) serialize_dual_timestamp(f, "main-exec-status-start", &s->main_exec_status.start_timestamp); + (void) serialize_dual_timestamp(f, "main-exec-status-exit", &s->main_exec_status.exit_timestamp); if (dual_timestamp_is_set(&s->main_exec_status.exit_timestamp)) { - unit_serialize_item_format(u, f, "main-exec-status-code", "%i", s->main_exec_status.code); - unit_serialize_item_format(u, f, "main-exec-status-status", "%i", s->main_exec_status.status); + (void) serialize_item_format(f, "main-exec-status-code", "%i", s->main_exec_status.code); + (void) serialize_item_format(f, "main-exec-status-status", "%i", s->main_exec_status.status); } } - dual_timestamp_serialize(f, "watchdog-timestamp", &s->watchdog_timestamp); - - unit_serialize_item(u, f, "forbid-restart", yes_no(s->forbid_restart)); + (void) serialize_dual_timestamp(f, "watchdog-timestamp", &s->watchdog_timestamp); + (void) serialize_bool(f, "forbid-restart", s->forbid_restart); if (s->watchdog_override_enable) - unit_serialize_item_format(u, f, "watchdog-override-usec", USEC_FMT, s->watchdog_override_usec); + (void) serialize_item_format(f, "watchdog-override-usec", USEC_FMT, s->watchdog_override_usec); return 0; } @@ -2825,11 +2828,11 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value, else s->main_exec_status.status = i; } else if (streq(key, "main-exec-status-start")) - dual_timestamp_deserialize(value, &s->main_exec_status.start_timestamp); + deserialize_dual_timestamp(value, &s->main_exec_status.start_timestamp); else if (streq(key, "main-exec-status-exit")) - dual_timestamp_deserialize(value, &s->main_exec_status.exit_timestamp); + deserialize_dual_timestamp(value, &s->main_exec_status.exit_timestamp); else if (streq(key, "watchdog-timestamp")) - dual_timestamp_deserialize(value, &s->watchdog_timestamp); + deserialize_dual_timestamp(value, &s->watchdog_timestamp); else if (streq(key, "forbid-restart")) { int b; @@ -2881,13 +2884,11 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value, safe_close(fd); } } else if (streq(key, "watchdog-override-usec")) { - usec_t watchdog_override_usec; - if (timestamp_deserialize(value, &watchdog_override_usec) < 0) + if (deserialize_usec(value, &s->watchdog_override_usec) < 0) log_unit_debug(u, "Failed to parse watchdog_override_usec value: %s", value); - else { + else s->watchdog_override_enable = true; - s->watchdog_override_usec = watchdog_override_usec; - } + } else if (STR_IN_SET(key, "main-command", "control-command")) { r = service_deserialize_exec_command(u, key, value); if (r < 0) @@ -3712,8 +3713,12 @@ static void service_notify_message( _cleanup_free_ char *t = NULL; if (!isempty(e)) { - if (!utf8_is_valid(e)) - log_unit_warning(u, "Status message in notification message is not UTF-8 clean."); + /* Note that this size limit check is mostly paranoia: since the datagram size we are willing + * to process is already limited to NOTIFY_BUFFER_MAX, this limit here should never be hit. */ + if (strlen(e) > STATUS_TEXT_MAX) + log_unit_warning(u, "Status message overly long (%zu > %u), ignoring.", strlen(e), STATUS_TEXT_MAX); + else if (!utf8_is_valid(e)) + log_unit_warning(u, "Status message in notification message is not UTF-8 clean, ignoring."); else { t = strdup(e); if (!t)
src/core/service.h+2 −0 modified@@ -206,3 +206,5 @@ const char* service_result_to_string(ServiceResult i) _const_; ServiceResult service_result_from_string(const char *s) _pure_; DEFINE_CAST(SERVICE, Service); + +#define STATUS_TEXT_MAX (16U*1024U)
src/core/slice.c+3 −1 modified@@ -5,6 +5,7 @@ #include "alloc-util.h" #include "dbus-slice.h" #include "log.h" +#include "serialize.h" #include "slice.h" #include "special.h" #include "string-util.h" @@ -256,7 +257,8 @@ static int slice_serialize(Unit *u, FILE *f, FDSet *fds) { assert(f); assert(fds); - unit_serialize_item(u, f, "state", slice_state_to_string(s->state)); + (void) serialize_item(f, "state", slice_state_to_string(s->state)); + return 0; }
src/core/socket.c+18 −16 modified@@ -32,10 +32,11 @@ #include "path-util.h" #include "process-util.h" #include "selinux-util.h" +#include "serialize.h" #include "signal-util.h" #include "smack-util.h" -#include "socket.h" #include "socket-protocol-list.h" +#include "socket.h" #include "special.h" #include "string-table.h" #include "string-util.h" @@ -2499,16 +2500,16 @@ static int socket_serialize(Unit *u, FILE *f, FDSet *fds) { assert(f); assert(fds); - unit_serialize_item(u, f, "state", socket_state_to_string(s->state)); - unit_serialize_item(u, f, "result", socket_result_to_string(s->result)); - unit_serialize_item_format(u, f, "n-accepted", "%u", s->n_accepted); - unit_serialize_item_format(u, f, "n-refused", "%u", s->n_refused); + (void) serialize_item(f, "state", socket_state_to_string(s->state)); + (void) serialize_item(f, "result", socket_result_to_string(s->result)); + (void) serialize_item_format(f, "n-accepted", "%u", s->n_accepted); + (void) serialize_item_format(f, "n-refused", "%u", s->n_refused); if (s->control_pid > 0) - unit_serialize_item_format(u, f, "control-pid", PID_FMT, s->control_pid); + (void) serialize_item_format(f, "control-pid", PID_FMT, s->control_pid); if (s->control_command_id >= 0) - unit_serialize_item(u, f, "control-command", socket_exec_command_to_string(s->control_command_id)); + (void) serialize_item(f, "control-command", socket_exec_command_to_string(s->control_command_id)); LIST_FOREACH(port, p, s->ports) { int copy; @@ -2518,36 +2519,37 @@ static int socket_serialize(Unit *u, FILE *f, FDSet *fds) { copy = fdset_put_dup(fds, p->fd); if (copy < 0) - return copy; + return log_warning_errno(copy, "Failed to serialize socket fd: %m"); if (p->type == SOCKET_SOCKET) { _cleanup_free_ char *t = NULL; r = socket_address_print(&p->address, &t); if (r < 0) - return r; + return log_error_errno(r, "Failed to format socket address: %m"); if (socket_address_family(&p->address) == AF_NETLINK) - unit_serialize_item_format(u, f, "netlink", "%i %s", copy, t); + (void) serialize_item_format(f, "netlink", "%i %s", copy, t); else - unit_serialize_item_format(u, f, "socket", "%i %i %s", copy, p->address.type, t); - + (void) serialize_item_format(f, "socket", "%i %i %s", copy, p->address.type, t); } else if (p->type == SOCKET_SPECIAL) - unit_serialize_item_format(u, f, "special", "%i %s", copy, p->path); + (void) serialize_item_format(f, "special", "%i %s", copy, p->path); else if (p->type == SOCKET_MQUEUE) - unit_serialize_item_format(u, f, "mqueue", "%i %s", copy, p->path); + (void) serialize_item_format(f, "mqueue", "%i %s", copy, p->path); else if (p->type == SOCKET_USB_FUNCTION) - unit_serialize_item_format(u, f, "ffs", "%i %s", copy, p->path); + (void) serialize_item_format(f, "ffs", "%i %s", copy, p->path); else { assert(p->type == SOCKET_FIFO); - unit_serialize_item_format(u, f, "fifo", "%i %s", copy, p->path); + (void) serialize_item_format(f, "fifo", "%i %s", copy, p->path); } } return 0; } static void socket_port_take_fd(SocketPort *p, FDSet *fds, int fd) { + assert(p); + safe_close(p->fd); p->fd = fdset_remove(fds, fd); }
src/core/swap.c+5 −4 modified@@ -20,6 +20,7 @@ #include "parse-util.h" #include "path-util.h" #include "process-util.h" +#include "serialize.h" #include "special.h" #include "string-table.h" #include "string-util.h" @@ -894,14 +895,14 @@ static int swap_serialize(Unit *u, FILE *f, FDSet *fds) { assert(f); assert(fds); - unit_serialize_item(u, f, "state", swap_state_to_string(s->state)); - unit_serialize_item(u, f, "result", swap_result_to_string(s->result)); + (void) serialize_item(f, "state", swap_state_to_string(s->state)); + (void) serialize_item(f, "result", swap_result_to_string(s->result)); if (s->control_pid > 0) - unit_serialize_item_format(u, f, "control-pid", PID_FMT, s->control_pid); + (void) serialize_item_format(f, "control-pid", PID_FMT, s->control_pid); if (s->control_command_id >= 0) - unit_serialize_item(u, f, "control-command", swap_exec_command_to_string(s->control_command_id)); + (void) serialize_item(f, "control-command", swap_exec_command_to_string(s->control_command_id)); return 0; }
src/core/target.c+3 −2 modified@@ -2,11 +2,12 @@ #include "dbus-target.h" #include "log.h" +#include "serialize.h" #include "special.h" #include "string-util.h" +#include "target.h" #include "unit-name.h" #include "unit.h" -#include "target.h" static const UnitActiveState state_translation_table[_TARGET_STATE_MAX] = { [TARGET_DEAD] = UNIT_INACTIVE, @@ -144,7 +145,7 @@ static int target_serialize(Unit *u, FILE *f, FDSet *fds) { assert(f); assert(fds); - unit_serialize_item(u, f, "state", target_state_to_string(s->state)); + (void) serialize_item(f, "state", target_state_to_string(s->state)); return 0; }
src/core/timer.c+11 −17 modified@@ -9,6 +9,7 @@ #include "fs-util.h" #include "parse-util.h" #include "random-util.h" +#include "serialize.h" #include "special.h" #include "string-table.h" #include "string-util.h" @@ -661,21 +662,20 @@ static int timer_serialize(Unit *u, FILE *f, FDSet *fds) { assert(f); assert(fds); - unit_serialize_item(u, f, "state", timer_state_to_string(t->state)); - unit_serialize_item(u, f, "result", timer_result_to_string(t->result)); + (void) serialize_item(f, "state", timer_state_to_string(t->state)); + (void) serialize_item(f, "result", timer_result_to_string(t->result)); if (t->last_trigger.realtime > 0) - unit_serialize_item_format(u, f, "last-trigger-realtime", "%" PRIu64, t->last_trigger.realtime); + (void) serialize_usec(f, "last-trigger-realtime", t->last_trigger.realtime); if (t->last_trigger.monotonic > 0) - unit_serialize_item_format(u, f, "last-trigger-monotonic", "%" PRIu64, t->last_trigger.monotonic); + (void) serialize_usec(f, "last-trigger-monotonic", t->last_trigger.monotonic); return 0; } static int timer_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) { Timer *t = TIMER(u); - int r; assert(u); assert(key); @@ -690,6 +690,7 @@ static int timer_deserialize_item(Unit *u, const char *key, const char *value, F log_unit_debug(u, "Failed to parse state value: %s", value); else t->deserialized_state = state; + } else if (streq(key, "result")) { TimerResult f; @@ -698,19 +699,12 @@ static int timer_deserialize_item(Unit *u, const char *key, const char *value, F log_unit_debug(u, "Failed to parse result value: %s", value); else if (f != TIMER_SUCCESS) t->result = f; - } else if (streq(key, "last-trigger-realtime")) { - - r = safe_atou64(value, &t->last_trigger.realtime); - if (r < 0) - log_unit_debug(u, "Failed to parse last-trigger-realtime value: %s", value); - } else if (streq(key, "last-trigger-monotonic")) { - - r = safe_atou64(value, &t->last_trigger.monotonic); - if (r < 0) - log_unit_debug(u, "Failed to parse last-trigger-monotonic value: %s", value); - - } else + } else if (streq(key, "last-trigger-realtime")) + (void) deserialize_usec(value, &t->last_trigger.realtime); + else if (streq(key, "last-trigger-monotonic")) + (void) deserialize_usec(value, &t->last_trigger.monotonic); + else log_unit_debug(u, "Unknown serialization key: %s", key); return 0;
src/core/unit.c+68 −141 modified@@ -10,8 +10,8 @@ #include "sd-id128.h" #include "sd-messages.h" -#include "alloc-util.h" #include "all-units.h" +#include "alloc-util.h" #include "bus-common-errors.h" #include "bus-util.h" #include "cgroup-util.h" @@ -35,6 +35,7 @@ #include "parse-util.h" #include "path-util.h" #include "process-util.h" +#include "serialize.h" #include "set.h" #include "signal-util.h" #include "sparse-endian.h" @@ -3206,23 +3207,21 @@ bool unit_can_serialize(Unit *u) { return UNIT_VTABLE(u)->serialize && UNIT_VTABLE(u)->deserialize_item; } -static int unit_serialize_cgroup_mask(FILE *f, const char *key, CGroupMask mask) { +static int serialize_cgroup_mask(FILE *f, const char *key, CGroupMask mask) { _cleanup_free_ char *s = NULL; - int r = 0; + int r; assert(f); assert(key); - if (mask != 0) { - r = cg_mask_to_string(mask, &s); - if (r >= 0) { - fputs(key, f); - fputc('=', f); - fputs(s, f); - fputc('\n', f); - } - } - return r; + if (mask == 0) + return 0; + + r = cg_mask_to_string(mask, &s); + if (r < 0) + return log_error_errno(r, "Failed to format cgroup mask: %m"); + + return serialize_item(f, key, s); } static const char *ip_accounting_metric_field[_CGROUP_IP_ACCOUNTING_METRIC_MAX] = { @@ -3246,50 +3245,50 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) { return r; } - dual_timestamp_serialize(f, "state-change-timestamp", &u->state_change_timestamp); + (void) serialize_dual_timestamp(f, "state-change-timestamp", &u->state_change_timestamp); - dual_timestamp_serialize(f, "inactive-exit-timestamp", &u->inactive_exit_timestamp); - dual_timestamp_serialize(f, "active-enter-timestamp", &u->active_enter_timestamp); - dual_timestamp_serialize(f, "active-exit-timestamp", &u->active_exit_timestamp); - dual_timestamp_serialize(f, "inactive-enter-timestamp", &u->inactive_enter_timestamp); + (void) serialize_dual_timestamp(f, "inactive-exit-timestamp", &u->inactive_exit_timestamp); + (void) serialize_dual_timestamp(f, "active-enter-timestamp", &u->active_enter_timestamp); + (void) serialize_dual_timestamp(f, "active-exit-timestamp", &u->active_exit_timestamp); + (void) serialize_dual_timestamp(f, "inactive-enter-timestamp", &u->inactive_enter_timestamp); - dual_timestamp_serialize(f, "condition-timestamp", &u->condition_timestamp); - dual_timestamp_serialize(f, "assert-timestamp", &u->assert_timestamp); + (void) serialize_dual_timestamp(f, "condition-timestamp", &u->condition_timestamp); + (void) serialize_dual_timestamp(f, "assert-timestamp", &u->assert_timestamp); if (dual_timestamp_is_set(&u->condition_timestamp)) - unit_serialize_item(u, f, "condition-result", yes_no(u->condition_result)); + (void) serialize_bool(f, "condition-result", u->condition_result); if (dual_timestamp_is_set(&u->assert_timestamp)) - unit_serialize_item(u, f, "assert-result", yes_no(u->assert_result)); - - unit_serialize_item(u, f, "transient", yes_no(u->transient)); + (void) serialize_bool(f, "assert-result", u->assert_result); - unit_serialize_item(u, f, "in-audit", yes_no(u->in_audit)); + (void) serialize_bool(f, "transient", u->transient); + (void) serialize_bool(f, "in-audit", u->in_audit); - unit_serialize_item(u, f, "exported-invocation-id", yes_no(u->exported_invocation_id)); - unit_serialize_item(u, f, "exported-log-level-max", yes_no(u->exported_log_level_max)); - unit_serialize_item(u, f, "exported-log-extra-fields", yes_no(u->exported_log_extra_fields)); - unit_serialize_item(u, f, "exported-log-rate-limit-interval", yes_no(u->exported_log_rate_limit_interval)); - unit_serialize_item(u, f, "exported-log-rate-limit-burst", yes_no(u->exported_log_rate_limit_burst)); + (void) serialize_bool(f, "exported-invocation-id", u->exported_invocation_id); + (void) serialize_bool(f, "exported-log-level-max", u->exported_log_level_max); + (void) serialize_bool(f, "exported-log-extra-fields", u->exported_log_extra_fields); + (void) serialize_bool(f, "exported-log-rate-limit-interval", u->exported_log_rate_limit_interval); + (void) serialize_bool(f, "exported-log-rate-limit-burst", u->exported_log_rate_limit_burst); - unit_serialize_item_format(u, f, "cpu-usage-base", "%" PRIu64, u->cpu_usage_base); + (void) serialize_item_format(f, "cpu-usage-base", "%" PRIu64, u->cpu_usage_base); if (u->cpu_usage_last != NSEC_INFINITY) - unit_serialize_item_format(u, f, "cpu-usage-last", "%" PRIu64, u->cpu_usage_last); + (void) serialize_item_format(f, "cpu-usage-last", "%" PRIu64, u->cpu_usage_last); if (u->cgroup_path) - unit_serialize_item(u, f, "cgroup", u->cgroup_path); - unit_serialize_item(u, f, "cgroup-realized", yes_no(u->cgroup_realized)); - (void) unit_serialize_cgroup_mask(f, "cgroup-realized-mask", u->cgroup_realized_mask); - (void) unit_serialize_cgroup_mask(f, "cgroup-enabled-mask", u->cgroup_enabled_mask); - (void) unit_serialize_cgroup_mask(f, "cgroup-invalidated-mask", u->cgroup_invalidated_mask); + (void) serialize_item(f, "cgroup", u->cgroup_path); + + (void) serialize_bool(f, "cgroup-realized", u->cgroup_realized); + (void) serialize_cgroup_mask(f, "cgroup-realized-mask", u->cgroup_realized_mask); + (void) serialize_cgroup_mask(f, "cgroup-enabled-mask", u->cgroup_enabled_mask); + (void) serialize_cgroup_mask(f, "cgroup-invalidated-mask", u->cgroup_invalidated_mask); if (uid_is_valid(u->ref_uid)) - unit_serialize_item_format(u, f, "ref-uid", UID_FMT, u->ref_uid); + (void) serialize_item_format(f, "ref-uid", UID_FMT, u->ref_uid); if (gid_is_valid(u->ref_gid)) - unit_serialize_item_format(u, f, "ref-gid", GID_FMT, u->ref_gid); + (void) serialize_item_format(f, "ref-gid", GID_FMT, u->ref_gid); if (!sd_id128_is_null(u->invocation_id)) - unit_serialize_item_format(u, f, "invocation-id", SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(u->invocation_id)); + (void) serialize_item_format(f, "invocation-id", SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(u->invocation_id)); bus_track_serialize(u->bus_track, f, "ref"); @@ -3298,17 +3297,17 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) { r = unit_get_ip_accounting(u, m, &v); if (r >= 0) - unit_serialize_item_format(u, f, ip_accounting_metric_field[m], "%" PRIu64, v); + (void) serialize_item_format(f, ip_accounting_metric_field[m], "%" PRIu64, v); } if (serialize_jobs) { if (u->job) { - fprintf(f, "job\n"); + fputs("job\n", f); job_serialize(u->job, f); } if (u->nop_job) { - fprintf(f, "job\n"); + fputs("job\n", f); job_serialize(u->nop_job, f); } } @@ -3318,80 +3317,6 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) { return 0; } -int unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value) { - assert(u); - assert(f); - assert(key); - - if (!value) - return 0; - - fputs(key, f); - fputc('=', f); - fputs(value, f); - fputc('\n', f); - - return 1; -} - -int unit_serialize_item_escaped(Unit *u, FILE *f, const char *key, const char *value) { - _cleanup_free_ char *c = NULL; - - assert(u); - assert(f); - assert(key); - - if (!value) - return 0; - - c = cescape(value); - if (!c) - return -ENOMEM; - - fputs(key, f); - fputc('=', f); - fputs(c, f); - fputc('\n', f); - - return 1; -} - -int unit_serialize_item_fd(Unit *u, FILE *f, FDSet *fds, const char *key, int fd) { - int copy; - - assert(u); - assert(f); - assert(key); - - if (fd < 0) - return 0; - - copy = fdset_put_dup(fds, fd); - if (copy < 0) - return copy; - - fprintf(f, "%s=%i\n", key, copy); - return 1; -} - -void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *format, ...) { - va_list ap; - - assert(u); - assert(f); - assert(key); - assert(format); - - fputs(key, f); - fputc('=', f); - - va_start(ap, format); - vfprintf(f, format, ap); - va_end(ap); - - fputc('\n', f); -} - int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { int r; @@ -3400,21 +3325,19 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { assert(fds); for (;;) { - char line[LINE_MAX], *l, *v; + _cleanup_free_ char *line = NULL; CGroupIPAccountingMetric m; + char *l, *v; size_t k; - if (!fgets(line, sizeof(line), f)) { - if (feof(f)) - return 0; - return -errno; - } + r = read_line(f, LONG_LINE_MAX, &line); + if (r < 0) + return log_error_errno(r, "Failed to read serialization line: %m"); + if (r == 0) /* eof */ + break; - char_array_0(line); l = strstrip(line); - - /* End marker */ - if (isempty(l)) + if (isempty(l)) /* End marker */ break; k = strcspn(l, "="); @@ -3456,25 +3379,25 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { log_unit_warning(u, "Update from too old systemd versions are unsupported, cannot deserialize job: %s", v); continue; } else if (streq(l, "state-change-timestamp")) { - dual_timestamp_deserialize(v, &u->state_change_timestamp); + (void) deserialize_dual_timestamp(v, &u->state_change_timestamp); continue; } else if (streq(l, "inactive-exit-timestamp")) { - dual_timestamp_deserialize(v, &u->inactive_exit_timestamp); + (void) deserialize_dual_timestamp(v, &u->inactive_exit_timestamp); continue; } else if (streq(l, "active-enter-timestamp")) { - dual_timestamp_deserialize(v, &u->active_enter_timestamp); + (void) deserialize_dual_timestamp(v, &u->active_enter_timestamp); continue; } else if (streq(l, "active-exit-timestamp")) { - dual_timestamp_deserialize(v, &u->active_exit_timestamp); + (void) deserialize_dual_timestamp(v, &u->active_exit_timestamp); continue; } else if (streq(l, "inactive-enter-timestamp")) { - dual_timestamp_deserialize(v, &u->inactive_enter_timestamp); + (void) deserialize_dual_timestamp(v, &u->inactive_enter_timestamp); continue; } else if (streq(l, "condition-timestamp")) { - dual_timestamp_deserialize(v, &u->condition_timestamp); + (void) deserialize_dual_timestamp(v, &u->condition_timestamp); continue; } else if (streq(l, "assert-timestamp")) { - dual_timestamp_deserialize(v, &u->assert_timestamp); + (void) deserialize_dual_timestamp(v, &u->assert_timestamp); continue; } else if (streq(l, "condition-result")) { @@ -3649,7 +3572,7 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { r = strv_extend(&u->deserialized_refs, v); if (r < 0) - log_oom(); + return log_oom(); continue; } else if (streq(l, "invocation-id")) { @@ -3714,23 +3637,27 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { return 0; } -void unit_deserialize_skip(FILE *f) { +int unit_deserialize_skip(FILE *f) { + int r; assert(f); /* Skip serialized data for this unit. We don't know what it is. */ for (;;) { - char line[LINE_MAX], *l; + _cleanup_free_ char *line = NULL; + char *l; - if (!fgets(line, sizeof line, f)) - return; + r = read_line(f, LONG_LINE_MAX, &line); + if (r < 0) + return log_error_errno(r, "Failed to read serialization line: %m"); + if (r == 0) + return 0; - char_array_0(line); l = strstrip(line); /* End marker */ if (isempty(l)) - return; + return 1; } }
src/core/unit.h+1 −6 modified@@ -682,12 +682,7 @@ bool unit_can_serialize(Unit *u) _pure_; int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs); int unit_deserialize(Unit *u, FILE *f, FDSet *fds); -void unit_deserialize_skip(FILE *f); - -int unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value); -int unit_serialize_item_escaped(Unit *u, FILE *f, const char *key, const char *value); -int unit_serialize_item_fd(Unit *u, FILE *f, FDSet *fds, const char *key, int fd); -void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *value, ...) _printf_(4,5); +int unit_deserialize_skip(FILE *f); int unit_add_node_dependency(Unit *u, const char *what, bool wants, UnitDependency d, UnitDependencyMask mask);
src/login/logind-session.c+3 −2 modified@@ -26,6 +26,7 @@ #include "parse-util.h" #include "path-util.h" #include "process-util.h" +#include "serialize.h" #include "string-table.h" #include "strv.h" #include "terminal-util.h" @@ -546,9 +547,9 @@ int session_load(Session *s) { } if (realtime) - timestamp_deserialize(realtime, &s->timestamp.realtime); + (void) deserialize_usec(realtime, &s->timestamp.realtime); if (monotonic) - timestamp_deserialize(monotonic, &s->timestamp.monotonic); + (void) deserialize_usec(monotonic, &s->timestamp.monotonic); if (active) { k = parse_boolean(active);
src/login/logind-user.c+4 −3 modified@@ -23,6 +23,7 @@ #include "parse-util.h" #include "path-util.h" #include "rm-rf.h" +#include "serialize.h" #include "special.h" #include "stdio-util.h" #include "string-table.h" @@ -332,11 +333,11 @@ int user_load(User *u) { } if (realtime) - (void) timestamp_deserialize(realtime, &u->timestamp.realtime); + (void) deserialize_usec(realtime, &u->timestamp.realtime); if (monotonic) - (void) timestamp_deserialize(monotonic, &u->timestamp.monotonic); + (void) deserialize_usec(monotonic, &u->timestamp.monotonic); if (last_session_timestamp) - (void) timestamp_deserialize(last_session_timestamp, &u->last_session_timestamp); + (void) deserialize_usec(last_session_timestamp, &u->last_session_timestamp); return 0; }
src/machine/machine.c+3 −2 modified@@ -21,6 +21,7 @@ #include "mkdir.h" #include "parse-util.h" #include "process-util.h" +#include "serialize.h" #include "special.h" #include "stdio-util.h" #include "string-table.h" @@ -284,9 +285,9 @@ int machine_load(Machine *m) { } if (realtime) - timestamp_deserialize(realtime, &m->timestamp.realtime); + (void) deserialize_usec(realtime, &m->timestamp.realtime); if (monotonic) - timestamp_deserialize(monotonic, &m->timestamp.monotonic); + (void) deserialize_usec(monotonic, &m->timestamp.monotonic); if (netif) { size_t allocated = 0, nr = 0;
src/shared/meson.build+5 −3 modified@@ -52,10 +52,10 @@ shared_sources = files(''' import-util.c import-util.h initreq.h - install.c - install.h install-printf.c install-printf.h + install.c + install.h journal-util.c journal-util.h logs-show.c @@ -78,6 +78,8 @@ shared_sources = files(''' resolve-util.c resolve-util.h seccomp-util.h + serialize.c + serialize.h sleep-config.c sleep-config.h spawn-ask-password-agent.c @@ -92,8 +94,8 @@ shared_sources = files(''' sysctl-util.h tomoyo-util.c tomoyo-util.h - udev-util.h udev-util.c + udev-util.h uid-range.c uid-range.h utmp-wtmp.h
src/shared/serialize.c+190 −0 added@@ -0,0 +1,190 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include "alloc-util.h" +#include "def.h" +#include "env-util.h" +#include "escape.h" +#include "parse-util.h" +#include "serialize.h" +#include "strv.h" + +int serialize_item(FILE *f, const char *key, const char *value) { + assert(f); + assert(key); + + if (!value) + return 0; + + /* Make sure that anything we serialize we can also read back again with read_line() with a maximum line size + * of LONG_LINE_MAX. This is a safety net only. All code calling us should filter this out earlier anyway. */ + if (strlen(key) + 1 + strlen(value) + 1 > LONG_LINE_MAX) { + log_warning("Attempted to serialize overly long item '%s', refusing.", key); + return -EINVAL; + } + + fputs(key, f); + fputc('=', f); + fputs(value, f); + fputc('\n', f); + + return 1; +} + +int serialize_item_escaped(FILE *f, const char *key, const char *value) { + _cleanup_free_ char *c = NULL; + + assert(f); + assert(key); + + if (!value) + return 0; + + c = cescape(value); + if (!c) + return log_oom(); + + return serialize_item(f, key, c); +} + +int serialize_item_format(FILE *f, const char *key, const char *format, ...) { + char buf[LONG_LINE_MAX]; + va_list ap; + int k; + + assert(f); + assert(key); + assert(format); + + va_start(ap, format); + k = vsnprintf(buf, sizeof(buf), format, ap); + va_end(ap); + + if (k < 0 || (size_t) k >= sizeof(buf) || strlen(key) + 1 + k + 1 > LONG_LINE_MAX) { + log_warning("Attempted to serialize overly long item '%s', refusing.", key); + return -EINVAL; + } + + fputs(key, f); + fputc('=', f); + fputs(buf, f); + fputc('\n', f); + + return 1; +} + +int serialize_fd(FILE *f, FDSet *fds, const char *key, int fd) { + int copy; + + assert(f); + assert(key); + + if (fd < 0) + return 0; + + copy = fdset_put_dup(fds, fd); + if (copy < 0) + return log_error_errno(copy, "Failed to add file descriptor to serialization set: %m"); + + return serialize_item_format(f, key, "%i", copy); +} + +int serialize_usec(FILE *f, const char *key, usec_t usec) { + assert(f); + assert(key); + + if (usec == USEC_INFINITY) + return 0; + + return serialize_item_format(f, key, USEC_FMT, usec); +} + +int serialize_dual_timestamp(FILE *f, const char *name, const dual_timestamp *t) { + assert(f); + assert(name); + assert(t); + + if (!dual_timestamp_is_set(t)) + return 0; + + return serialize_item_format(f, name, USEC_FMT " " USEC_FMT, t->realtime, t->monotonic); +} + +int serialize_strv(FILE *f, const char *key, char **l) { + int ret = 0, r; + char **i; + + /* Returns the first error */ + + STRV_FOREACH(i, l) { + r = serialize_item_escaped(f, key, *i); + if ((ret >= 0 && r < 0) || + (ret == 0 && r > 0)) + ret = r; + } + + return ret; +} + +int deserialize_usec(const char *value, usec_t *ret) { + int r; + + assert(value); + + r = safe_atou64(value, ret); + if (r < 0) + return log_debug_errno(r, "Failed to parse usec value \"%s\": %m", value); + + return 0; +} + +int deserialize_dual_timestamp(const char *value, dual_timestamp *t) { + uint64_t a, b; + int r, pos; + + assert(value); + assert(t); + + pos = strspn(value, WHITESPACE); + if (value[pos] == '-') + return -EINVAL; + pos += strspn(value + pos, DIGITS); + pos += strspn(value + pos, WHITESPACE); + if (value[pos] == '-') + return -EINVAL; + + r = sscanf(value, "%" PRIu64 "%" PRIu64 "%n", &a, &b, &pos); + if (r != 2) { + log_debug("Failed to parse dual timestamp value \"%s\".", value); + return -EINVAL; + } + + if (value[pos] != '\0') + /* trailing garbage */ + return -EINVAL; + + t->realtime = a; + t->monotonic = b; + + return 0; +} + +int deserialize_environment(const char *value, char ***list) { + _cleanup_free_ char *unescaped = NULL; + int r; + + assert(value); + assert(list); + + /* Changes the *environment strv inline. */ + + r = cunescape(value, 0, &unescaped); + if (r < 0) + return log_error_errno(r, "Failed to unescape: %m"); + + r = strv_env_replace(list, unescaped); + if (r < 0) + return log_error_errno(r, "Failed to append environment variable: %m"); + + unescaped = NULL; /* now part of 'list' */ + return 0; +}
src/shared/serialize.h+23 −0 added@@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include <stdio.h> + +#include "fdset.h" +#include "macro.h" + +int serialize_item(FILE *f, const char *key, const char *value); +int serialize_item_escaped(FILE *f, const char *key, const char *value); +int serialize_item_format(FILE *f, const char *key, const char *value, ...) _printf_(3,4); +int serialize_fd(FILE *f, FDSet *fds, const char *key, int fd); +int serialize_usec(FILE *f, const char *key, usec_t usec); +int serialize_dual_timestamp(FILE *f, const char *key, const dual_timestamp *t); +int serialize_strv(FILE *f, const char *key, char **l); + +static inline int serialize_bool(FILE *f, const char *key, bool b) { + return serialize_item(f, key, yes_no(b)); +} + +int deserialize_usec(const char *value, usec_t *timestamp); +int deserialize_dual_timestamp(const char *value, dual_timestamp *t); +int deserialize_environment(const char *value, char ***environment);
src/test/test-env-util.c+28 −19 modified@@ -2,9 +2,11 @@ #include <string.h> +#include "def.h" #include "env-util.h" #include "fd-util.h" #include "fileio.h" +#include "serialize.h" #include "string-util.h" #include "strv.h" #include "util.h" @@ -304,52 +306,59 @@ static void test_env_assignment_is_valid(void) { } static void test_deserialize_environment(void) { - _cleanup_strv_free_ char **env = strv_new("A=1", NULL); + _cleanup_strv_free_ char **env; - assert_se(deserialize_environment(&env, "env=B=2") >= 0); - assert_se(deserialize_environment(&env, "env=FOO%%=a\\177b\\nc\\td e") >= 0); + assert_se(env = strv_new("A=1", NULL)); + + assert_se(deserialize_environment("B=2", &env) >= 0); + assert_se(deserialize_environment("FOO%%=a\\177b\\nc\\td e", &env) >= 0); assert_se(strv_equal(env, STRV_MAKE("A=1", "B=2", "FOO%%=a\177b\nc\td e"))); - assert_se(deserialize_environment(&env, "env=foo\\") < 0); - assert_se(deserialize_environment(&env, "env=bar\\_baz") < 0); + assert_se(deserialize_environment("foo\\", &env) < 0); + assert_se(deserialize_environment("bar\\_baz", &env) < 0); } static void test_serialize_environment(void) { + _cleanup_strv_free_ char **env = NULL, **env2 = NULL; char fn[] = "/tmp/test-env-util.XXXXXXX"; - int fd, r; _cleanup_fclose_ FILE *f = NULL; + int fd, r; - _cleanup_strv_free_ char **env = strv_new("A=1", - "B=2", - "C=ąęółń", - "D=D=a\\x0Ab", - "FOO%%=a\177b\nc\td e", - NULL); - _cleanup_strv_free_ char **env2 = NULL; + + assert_se(env = strv_new("A=1", + "B=2", + "C=ąęółń", + "D=D=a\\x0Ab", + "FOO%%=a\177b\nc\td e", + NULL)); fd = mkostemp_safe(fn); assert_se(fd >= 0); assert_se(f = fdopen(fd, "r+")); - assert_se(serialize_environment(f, env) == 0); + assert_se(serialize_strv(f, "env", env) > 0); assert_se(fflush_and_check(f) == 0); rewind(f); for (;;) { - char line[LINE_MAX]; + _cleanup_free_ char *line = NULL; const char *l; - if (!fgets(line, sizeof line, f)) + r = read_line(f, LONG_LINE_MAX, &line); + assert_se(r >= 0); + + if (r == 0) break; - char_array_0(line); l = strstrip(line); - r = deserialize_environment(&env2, l); - assert_se(r == 1); + assert_se(startswith(l, "env=")); + + r = deserialize_environment(l+4, &env2); + assert_se(r >= 0); } assert_se(feof(f));
src/test/test-time-util.c+10 −9 modified@@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #include "random-util.h" +#include "serialize.h" #include "string-util.h" #include "strv.h" #include "time-util.h" @@ -340,40 +341,40 @@ static void test_format_timestamp_utc(void) { test_format_timestamp_utc_one(USEC_INFINITY, NULL); } -static void test_dual_timestamp_deserialize(void) { +static void test_deserialize_dual_timestamp(void) { int r; dual_timestamp t; log_info("/* %s */", __func__); - r = dual_timestamp_deserialize("1234 5678", &t); + r = deserialize_dual_timestamp("1234 5678", &t); assert_se(r == 0); assert_se(t.realtime == 1234); assert_se(t.monotonic == 5678); - r = dual_timestamp_deserialize("1234x 5678", &t); + r = deserialize_dual_timestamp("1234x 5678", &t); assert_se(r == -EINVAL); - r = dual_timestamp_deserialize("1234 5678y", &t); + r = deserialize_dual_timestamp("1234 5678y", &t); assert_se(r == -EINVAL); - r = dual_timestamp_deserialize("-1234 5678", &t); + r = deserialize_dual_timestamp("-1234 5678", &t); assert_se(r == -EINVAL); - r = dual_timestamp_deserialize("1234 -5678", &t); + r = deserialize_dual_timestamp("1234 -5678", &t); assert_se(r == -EINVAL); /* Check that output wasn't modified. */ assert_se(t.realtime == 1234); assert_se(t.monotonic == 5678); - r = dual_timestamp_deserialize("+123 567", &t); + r = deserialize_dual_timestamp("+123 567", &t); assert_se(r == 0); assert_se(t.realtime == 123); assert_se(t.monotonic == 567); /* Check that we get "infinity" on overflow. */ - r = dual_timestamp_deserialize("18446744073709551617 0", &t); + r = deserialize_dual_timestamp("18446744073709551617 0", &t); assert_se(r == 0); assert_se(t.realtime == USEC_INFINITY); assert_se(t.monotonic == 0); @@ -461,7 +462,7 @@ int main(int argc, char *argv[]) { test_usec_sub_unsigned(); test_format_timestamp(); test_format_timestamp_utc(); - test_dual_timestamp_deserialize(); + test_deserialize_dual_timestamp(); test_usec_shift_clock(); test_in_utc_timezone();
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
11- www.exploit-db.com/exploits/45714/mitreexploitx_refsource_EXPLOIT-DB
- access.redhat.com/errata/RHSA-2019:2091mitrevendor-advisoryx_refsource_REDHAT
- access.redhat.com/errata/RHSA-2019:3222mitrevendor-advisoryx_refsource_REDHAT
- access.redhat.com/errata/RHSA-2020:0593mitrevendor-advisoryx_refsource_REDHAT
- security.gentoo.org/glsa/201810-10mitrevendor-advisoryx_refsource_GENTOO
- usn.ubuntu.com/3816-1/mitrevendor-advisoryx_refsource_UBUNTU
- www.securityfocus.com/bid/105747mitrevdb-entryx_refsource_BID
- github.com/systemd/systemd/pull/10519mitrex_refsource_MISC
- lists.apache.org/thread.html/r1b103833cb5bc8466e24ff0ecc5e75b45a705334ab6a444e64e840a0%40%3Cissues.bookkeeper.apache.org%3Emitremailing-listx_refsource_MLIST
- lists.debian.org/debian-lts-announce/2018/11/msg00017.htmlmitremailing-listx_refsource_MLIST
- www.oracle.com//security-alerts/cpujul2021.htmlmitrex_refsource_MISC
News mentions
0No linked articles in our index yet.