Assorted systemd-machined fixes (#37622)

This commit is contained in:
Lennart Poettering
2025-05-27 12:19:46 +02:00
committed by GitHub
10 changed files with 170 additions and 122 deletions

View File

@@ -1251,6 +1251,8 @@ node /org/freedesktop/login1/session/1 {
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly u Leader = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly t LeaderPIDFDId = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly u Audit = ...;
readonly s Type = '...';
readonly s Class = '...';
@@ -1351,6 +1353,8 @@ node /org/freedesktop/login1/session/1 {
<variablelist class="dbus-property" generated="True" extra-ref="Leader"/>
<variablelist class="dbus-property" generated="True" extra-ref="LeaderPIDFDId"/>
<variablelist class="dbus-property" generated="True" extra-ref="Audit"/>
<variablelist class="dbus-property" generated="True" extra-ref="Type"/>
@@ -1539,6 +1543,9 @@ node /org/freedesktop/login1/session/1 {
<para><varname>Leader</varname> encodes the PID of the process that registered the session.</para>
<para><varname>LeaderPIDFDId</varname> encodes the Linux pidfd inode ID of the process that registered
the session.</para>
<para><varname>Audit</varname> encodes the Kernel Audit session ID of the session if auditing is
available.</para>
@@ -1660,6 +1667,7 @@ node /org/freedesktop/login1/session/1 {
<para><function>SetDisplay()</function> was added in version 252.</para>
<para><function>SetTTY()</function> was added in version 254.</para>
<para><function>SetClass()</function> was added in version 256.</para>
<para><varname>LeaderPIDFDId</varname> was added in version 258.</para>
</refsect2>
</refsect1>

View File

@@ -513,6 +513,8 @@ node /org/freedesktop/machine1/machine/rawhide {
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly u Leader = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly t LeaderPIDFDId = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s Class = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s RootDirectory = '...';
@@ -603,6 +605,8 @@ node /org/freedesktop/machine1/machine/rawhide {
<variablelist class="dbus-property" generated="True" extra-ref="Leader"/>
<variablelist class="dbus-property" generated="True" extra-ref="LeaderPIDFDId"/>
<variablelist class="dbus-property" generated="True" extra-ref="Class"/>
<variablelist class="dbus-property" generated="True" extra-ref="RootDirectory"/>
@@ -650,6 +654,9 @@ node /org/freedesktop/machine1/machine/rawhide {
<para><varname>Leader</varname> is the PID of the leader process of the machine.</para>
<para><varname>LeaderPIDFDId</varname> encodes the Linux pidfd inode ID of the leader process of the
machine.</para>
<para><varname>Class</varname> is the class of the machine and is either the string "vm" (for real VMs
based on virtualized hardware) or "container" (for lightweight userspace virtualization sharing the
same kernel as the host).</para>
@@ -717,6 +724,7 @@ $ gdbus introspect --system \
<function>CopyToWithFlags()</function> were added in version 252.</para>
<para><function>GetSSHInfo()</function>, <varname>VSockCID</varname>, <varname>SSHAddress</varname>
and <varname>SSHPrivateKeyPath</varname> were added in version 256.</para>
<para><varname>LeaderPIDFDId</varname> was added in version 258.</para>
</refsect2>
</refsect1>

View File

@@ -10,7 +10,6 @@
#include "cgroup-util.h"
#include "dirent-util.h"
#include "env-file.h"
#include "escape.h"
#include "extract-word.h"
#include "fd-util.h"
#include "format-util.h"
@@ -837,20 +836,7 @@ _public_ int sd_session_get_class(const char *session, char **class) {
}
_public_ int sd_session_get_desktop(const char *session, char **desktop) {
_cleanup_free_ char *escaped = NULL;
int r;
ssize_t l;
assert_return(desktop, -EINVAL);
r = session_get_string(session, "DESKTOP", &escaped);
if (r < 0)
return r;
l = cunescape(escaped, 0, desktop);
if (l < 0)
return l;
return 0;
return session_get_string(session, "DESKTOP", desktop);
}
_public_ int sd_session_get_display(const char *session, char **display) {

View File

@@ -993,6 +993,7 @@ static const sd_bus_vtable session_vtable[] = {
SD_BUS_PROPERTY("Desktop", "s", NULL, offsetof(Session, desktop), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Session, scope), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Leader", "u", bus_property_get_pid, offsetof(Session, leader.pid), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("LeaderPIDFDId", "t", bus_property_get_pidfdid, offsetof(Session, leader), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Audit", "u", NULL, offsetof(Session, audit_id), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Session, type), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Session, class), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),

View File

@@ -717,7 +717,8 @@ static const sd_bus_vtable machine_vtable[] = {
SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Machine, service), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Unit", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
SD_BUS_PROPERTY("Leader", "u", NULL, offsetof(Machine, leader.pid), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Leader", "u", bus_property_get_pid, offsetof(Machine, leader.pid), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("LeaderPIDFDId", "t", bus_property_get_pidfdid, offsetof(Machine, leader), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("NetworkInterfaces", "ai", property_get_netif, 0, SD_BUS_VTABLE_PROPERTY_CONST),

View File

@@ -145,8 +145,6 @@ Machine* machine_free(Machine *m) {
}
int machine_save(Machine *m) {
_cleanup_(unlink_and_freep) char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
int r;
assert(m);
@@ -157,63 +155,47 @@ int machine_save(Machine *m) {
if (!m->started)
return 0;
_cleanup_(unlink_and_freep) char *sl = NULL; /* auto-unlink! */
if (m->unit) {
sl = strjoin("/run/systemd/machines/unit:", m->unit);
if (!sl)
return log_oom();
}
r = mkdir_safe_label("/run/systemd/machines", 0755, 0, 0, MKDIR_WARN_MODE);
if (r < 0)
goto fail;
return log_error_errno(r, "Failed to create /run/systemd/machines/: %m");
r = fopen_temporary(m->state_file, &f, &temp_path);
_cleanup_(unlink_and_freep) char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
r = fopen_tmpfile_linkable(m->state_file, O_WRONLY|O_CLOEXEC, &temp_path, &f);
if (r < 0)
goto fail;
return log_error_errno(r, "Failed to create state file '%s': %m", m->state_file);
(void) fchmod(fileno(f), 0644);
if (fchmod(fileno(f), 0644) < 0)
return log_error_errno(errno, "Failed to set access mode for state file '%s' to 0644: %m", m->state_file);
fprintf(f,
"# This is private data. Do not parse.\n"
"NAME=%s\n",
m->name);
if (m->unit) {
_cleanup_free_ char *escaped = NULL;
/* We continue to call this "SCOPE=" because it is internal only, and we want to stay compatible with old files */
env_file_fputs_assignment(f, "SCOPE=", m->unit);
env_file_fputs_assignment(f, "SCOPE_JOB=", m->scope_job);
escaped = cescape(m->unit);
if (!escaped) {
r = -ENOMEM;
goto fail;
}
fprintf(f, "SCOPE=%s\n", escaped); /* We continue to call this "SCOPE=" because it is internal only, and we want to stay compatible with old files */
}
if (m->scope_job)
fprintf(f, "SCOPE_JOB=%s\n", m->scope_job);
if (m->service) {
_cleanup_free_ char *escaped = NULL;
escaped = cescape(m->service);
if (!escaped) {
r = -ENOMEM;
goto fail;
}
fprintf(f, "SERVICE=%s\n", escaped);
}
if (m->root_directory) {
_cleanup_free_ char *escaped = NULL;
escaped = cescape(m->root_directory);
if (!escaped) {
r = -ENOMEM;
goto fail;
}
fprintf(f, "ROOT=%s\n", escaped);
}
env_file_fputs_assignment(f, "SERVICE=", m->service);
env_file_fputs_assignment(f, "ROOT=", m->root_directory);
if (!sd_id128_is_null(m->id))
fprintf(f, "ID=" SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(m->id));
if (pidref_is_set(&m->leader))
if (pidref_is_set(&m->leader)) {
fprintf(f, "LEADER="PID_FMT"\n", m->leader.pid);
(void) pidref_acquire_pidfd_id(&m->leader);
if (m->leader.fd_id != 0)
fprintf(f, "LEADER_PIDFDID=%" PRIu64 "\n", m->leader.fd_id);
}
if (m->class != _MACHINE_CLASS_INVALID)
fprintf(f, "CLASS=%s\n", machine_class_to_string(m->class));
@@ -226,56 +208,44 @@ int machine_save(Machine *m) {
m->timestamp.monotonic);
if (m->n_netif > 0) {
size_t i;
fputs("NETIF=", f);
for (i = 0; i < m->n_netif; i++) {
if (i != 0)
fputs("NETIF=\"", f);
FOREACH_ARRAY(ifi, m->netif, m->n_netif) {
if (*ifi != 0)
fputc(' ', f);
fprintf(f, "%i", m->netif[i]);
fprintf(f, "%i", *ifi);
}
fputc('\n', f);
fputs("\"\n", f);
}
r = fflush_and_check(f);
if (m->vsock_cid != 0)
fprintf(f, "VSOCK_CID=%u\n", m->vsock_cid);
env_file_fputs_assignment(f, "SSH_ADDRESS=", m->ssh_address);
env_file_fputs_assignment(f, "SSH_PRIVATE_KEY_PATH=", m->ssh_private_key_path);
r = flink_tmpfile(f, temp_path, m->state_file, LINK_TMPFILE_REPLACE);
if (r < 0)
goto fail;
return log_error_errno(r, "Failed to move '%s' into place: %m", m->state_file);
if (rename(temp_path, m->state_file) < 0) {
r = -errno;
goto fail;
}
temp_path = mfree(temp_path); /* disarm auto-destroy: temporary file does not exist anymore */
temp_path = mfree(temp_path);
if (m->unit) {
char *sl;
/* Create a symlink from the unit name to the machine
* name, so that we can quickly find the machine for
* each given unit. Ignore error. */
sl = strjoina("/run/systemd/machines/unit:", m->unit);
if (sl) {
/* Create a symlink from the unit name to the machine name, so that we can quickly find the machine
* for each given unit. Ignore error. */
(void) symlink(m->name, sl);
/* disarm auto-removal */
sl = mfree(sl);
}
return 0;
fail:
(void) unlink(m->state_file);
return log_error_errno(r, "Failed to save machine data %s: %m", m->state_file);
}
static void machine_unlink(Machine *m) {
assert(m);
if (m->unit) {
char *sl;
sl = strjoina("/run/systemd/machines/unit:", m->unit);
const char *sl = strjoina("/run/systemd/machines/unit:", m->unit);
(void) unlink(sl);
}
@@ -284,7 +254,8 @@ static void machine_unlink(Machine *m) {
}
int machine_load(Machine *m) {
_cleanup_free_ char *realtime = NULL, *monotonic = NULL, *id = NULL, *leader = NULL, *class = NULL, *netif = NULL;
_cleanup_free_ char *name = NULL, *realtime = NULL, *monotonic = NULL, *id = NULL, *leader = NULL, *leader_pidfdid = NULL,
*class = NULL, *netif = NULL, *vsock_cid = NULL;
int r;
assert(m);
@@ -293,35 +264,55 @@ int machine_load(Machine *m) {
return 0;
r = parse_env_file(NULL, m->state_file,
"SCOPE", &m->unit,
"SCOPE_JOB", &m->scope_job,
"SERVICE", &m->service,
"ROOT", &m->root_directory,
"ID", &id,
"LEADER", &leader,
"CLASS", &class,
"REALTIME", &realtime,
"MONOTONIC", &monotonic,
"NETIF", &netif);
"NAME", &name,
"SCOPE", &m->unit,
"SCOPE_JOB", &m->scope_job,
"SERVICE", &m->service,
"ROOT", &m->root_directory,
"ID", &id,
"LEADER", &leader,
"LEADER_PIDFDID", &leader_pidfdid,
"CLASS", &class,
"REALTIME", &realtime,
"MONOTONIC", &monotonic,
"NETIF", &netif,
"VSOCK_CID", &vsock_cid,
"SSH_ADDRESS", &m->ssh_address,
"SSH_PRIVATE_KEY_PATH", &m->ssh_private_key_path);
if (r == -ENOENT)
return 0;
if (r < 0)
return log_error_errno(r, "Failed to read %s: %m", m->state_file);
if (!streq_ptr(name, m->name))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "State file '%s' for machine '%s' reports a different name '%s', refusing", m->state_file, m->name, name);
if (id)
(void) sd_id128_from_string(id, &m->id);
pidref_done(&m->leader);
if (leader) {
pidref_done(&m->leader);
r = pidref_set_pidstr(&m->leader, leader);
if (r < 0)
log_debug_errno(r, "Failed to set leader PID to '%s', ignoring: %m", leader);
else if (leader_pidfdid) {
uint64_t fd_id;
r = safe_atou64(leader_pidfdid, &fd_id);
if (r < 0)
log_warning_errno(r, "Failed to parse leader pidfd ID, ignoring: %s", leader_pidfdid);
else {
(void) pidref_acquire_pidfd_id(&m->leader);
if (fd_id != m->leader.fd_id) {
log_debug("Leader PID got recycled, ignoring.");
pidref_done(&m->leader);
}
}
}
}
if (class) {
MachineClass c;
c = machine_class_from_string(class);
MachineClass c = machine_class_from_string(class);
if (c >= 0)
m->class = c;
}
@@ -331,13 +322,13 @@ int machine_load(Machine *m) {
if (monotonic)
(void) deserialize_usec(monotonic, &m->timestamp.monotonic);
m->netif = mfree(m->netif);
m->n_netif = 0;
if (netif) {
_cleanup_free_ int *ni = NULL;
size_t nr = 0;
const char *p;
p = netif;
for (;;) {
for (const char *p = netif;;) {
_cleanup_free_ char *word = NULL;
r = extract_first_word(&p, &word, NULL, 0);
@@ -360,10 +351,17 @@ int machine_load(Machine *m) {
ni[nr++] = r;
}
free_and_replace(m->netif, ni);
m->netif = TAKE_PTR(ni);
m->n_netif = nr;
}
m->vsock_cid = 0;
if (vsock_cid) {
r = safe_atou(vsock_cid, &m->vsock_cid);
if (r < 0)
log_warning_errno(r, "Failed to parse AF_VSOCK CID, ignoring: %s", vsock_cid);
}
return r;
}
@@ -574,7 +572,7 @@ int machine_stop(Machine *m) {
r = manager_stop_unit(m->manager, m->unit, &error, &job);
if (r < 0)
return log_error_errno(r, "Failed to stop machine scope: %s", bus_error_message(&error, r));
return log_error_errno(r, "Failed to stop machine unit: %s", bus_error_message(&error, r));
free_and_replace(m->scope_job, job);
}
@@ -611,22 +609,43 @@ int machine_finalize(Machine *m) {
}
bool machine_may_gc(Machine *m, bool drop_not_started) {
int r;
assert(m);
if (m->class == MACHINE_HOST)
return false;
if (!pidref_is_set(&m->leader))
return true;
if (drop_not_started && !m->started)
return true;
if (m->scope_job && manager_job_is_active(m->manager, m->scope_job))
r = pidref_is_alive(&m->leader);
if (r == -ESRCH)
return true;
if (r < 0)
log_debug_errno(r, "Unable to determine if leader PID " PID_FMT " is still alive, assuming not: %m", m->leader.pid);
if (r > 0)
return false;
if (m->unit && manager_unit_is_active(m->manager, m->unit))
return false;
if (m->scope_job) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
r = manager_job_is_active(m->manager, m->scope_job, &error);
if (r < 0)
log_debug_errno(r, "Failed to determine whether job '%s' is active, assuming it is: %s", m->scope_job, bus_error_message(&error, r));
if (r != 0)
return false;
}
if (m->unit) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
r = manager_unit_is_active(m->manager, m->unit, &error);
if (r < 0)
log_debug_errno(r, "Failed to determine whether unit '%s' is active, assuming it is: %s", m->unit, bus_error_message(&error, r));
if (r != 0)
return false;
}
return true;
}

View File

@@ -284,7 +284,7 @@ static int method_create_or_register_machine(
if (leader == 1)
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
if (!isempty(root_directory) && !path_is_absolute(root_directory))
if (!isempty(root_directory) && (!path_is_absolute(root_directory) || !path_is_valid(root_directory)))
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
if (leader == 0) {
@@ -1262,7 +1262,7 @@ int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_erro
return bus_call_method(manager->bus, bus_systemd_mgr, "KillUnit", error, NULL, "ssi", unit, "all", signo);
}
int manager_unit_is_active(Manager *manager, const char *unit) {
int manager_unit_is_active(Manager *manager, const char *unit, sd_bus_error *reterr_error) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_free_ char *path = NULL;
@@ -1294,6 +1294,7 @@ int manager_unit_is_active(Manager *manager, const char *unit) {
BUS_ERROR_LOAD_FAILED))
return false;
sd_bus_error_move(reterr_error, &error);
return r;
}
@@ -1304,7 +1305,7 @@ int manager_unit_is_active(Manager *manager, const char *unit) {
return !STR_IN_SET(state, "inactive", "failed");
}
int manager_job_is_active(Manager *manager, const char *path) {
int manager_job_is_active(Manager *manager, const char *path, sd_bus_error *reterr_error) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
int r;
@@ -1329,6 +1330,7 @@ int manager_job_is_active(Manager *manager, const char *path) {
if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
return false;
sd_bus_error_move(reterr_error, &error);
return r;
}

View File

@@ -46,8 +46,8 @@ int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *err
int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job);
int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error);
int manager_unref_unit(Manager *m, const char *unit, sd_bus_error *error);
int manager_unit_is_active(Manager *manager, const char *unit);
int manager_job_is_active(Manager *manager, const char *path);
int manager_unit_is_active(Manager *manager, const char *unit, sd_bus_error *reterr_errno);
int manager_job_is_active(Manager *manager, const char *path, sd_bus_error *reterr_errno);
int manager_find_machine_for_uid(Manager *m, uid_t host_uid, Machine **ret_machine, uid_t *ret_internal_uid);
int manager_find_machine_for_gid(Manager *m, gid_t host_gid, Machine **ret_machine, gid_t *ret_internal_gid);

View File

@@ -4,6 +4,7 @@
#include "bus-get-properties.h"
#include "bus-message-util.h"
#include "pidref.h"
#include "rlimit-util.h"
#include "string-util.h"
@@ -188,3 +189,23 @@ int bus_property_get_string_set(
return bus_message_append_string_set(reply, *s);
}
int bus_property_get_pidfdid(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
PidRef *pidref = ASSERT_PTR(userdata);
assert(bus);
assert(property);
assert(reply);
(void) pidref_acquire_pidfd_id(pidref);
return sd_bus_message_append(reply, "t", pidref->fd_id);
}

View File

@@ -54,6 +54,8 @@ int bus_property_get_rlimit(sd_bus *bus, const char *path, const char *interface
int bus_property_get_string_set(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
int bus_property_get_pidfdid(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
#define BUS_DEFINE_PROPERTY_GET_GLOBAL(function, bus_type, val) \
int function(sd_bus *bus, \
const char *path, \