machined: make registration of unpriv user's VMs/containers work (#37855)

This adds missing glue to reasonably allow unpriv users VMs/containers
to register with the system machined.

This primarily adds two things:

1. machined can now properly track VMs/containers residing in subcgroups
of units, because that's effectively what happens for per-user
VMs/containers: they are placed below the system unit `user@….service`
in some user unit.

2. machines registered with machined now have an owning UID: users can
operate on their own machines withour re-authentication, but not on
others.

Note that this is only a first step regarding machined's hookup of
nspawn/vmspawn in the long run for unpriv operation.

I think eventually we should make it so that there's both a per-user and
a per-system machined instance (so far, and even with this PR there's
still one per-system instance), and per-user containers/VMs would
registering with *both*. Having two instances makes sense I think,
because it would mean we can make machined reasonably manage the
per-user image discovery, and also do the per-system network/hostname
handling.
This commit is contained in:
Lennart Poettering
2025-07-11 21:10:08 +02:00
committed by GitHub
38 changed files with 1492 additions and 336 deletions
+34 -17
View File
@@ -973,15 +973,14 @@ static const char* skip_slices(const char *p) {
}
}
int cg_path_get_unit(const char *path, char **ret) {
_cleanup_free_ char *unit = NULL;
const char *e;
int cg_path_get_unit_full(const char *path, char **ret_unit, char **ret_subgroup) {
int r;
assert(path);
e = skip_slices(path);
const char *e = skip_slices(path);
_cleanup_free_ char *unit = NULL;
r = cg_path_decode_unit(e, &unit);
if (r < 0)
return r;
@@ -990,8 +989,27 @@ int cg_path_get_unit(const char *path, char **ret) {
if (endswith(unit, ".slice"))
return -ENXIO;
if (ret)
*ret = TAKE_PTR(unit);
if (ret_subgroup) {
_cleanup_free_ char *subgroup = NULL;
e += strcspn(e, "/");
e += strspn(e, "/");
if (isempty(e))
subgroup = NULL;
else {
subgroup = strdup(e);
if (!subgroup)
return -ENOMEM;
}
path_simplify(subgroup);
*ret_subgroup = TAKE_PTR(subgroup);
}
if (ret_unit)
*ret_unit = TAKE_PTR(unit);
return 0;
}
@@ -1017,31 +1035,27 @@ int cg_path_get_unit_path(const char *path, char **ret) {
return 0;
}
int cg_pid_get_unit(pid_t pid, char **ret_unit) {
_cleanup_free_ char *cgroup = NULL;
int cg_pid_get_unit_full(pid_t pid, char **ret_unit, char **ret_subgroup) {
int r;
assert(ret_unit);
_cleanup_free_ char *cgroup = NULL;
r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
if (r < 0)
return r;
return cg_path_get_unit(cgroup, ret_unit);
return cg_path_get_unit_full(cgroup, ret_unit, ret_subgroup);
}
int cg_pidref_get_unit(const PidRef *pidref, char **ret) {
_cleanup_free_ char *unit = NULL;
int cg_pidref_get_unit_full(const PidRef *pidref, char **ret_unit, char **ret_subgroup) {
int r;
assert(ret);
if (!pidref_is_set(pidref))
return -ESRCH;
if (pidref_is_remote(pidref))
return -EREMOTE;
r = cg_pid_get_unit(pidref->pid, &unit);
_cleanup_free_ char *unit = NULL, *subgroup = NULL;
r = cg_pid_get_unit_full(pidref->pid, &unit, &subgroup);
if (r < 0)
return r;
@@ -1049,7 +1063,10 @@ int cg_pidref_get_unit(const PidRef *pidref, char **ret) {
if (r < 0)
return r;
*ret = TAKE_PTR(unit);
if (ret_unit)
*ret_unit = TAKE_PTR(unit);
if (ret_subgroup)
*ret_subgroup = TAKE_PTR(subgroup);
return 0;
}
+12 -3
View File
@@ -203,7 +203,10 @@ int cg_get_root_path(char **path);
int cg_path_get_session(const char *path, char **ret_session);
int cg_path_get_owner_uid(const char *path, uid_t *ret_uid);
int cg_path_get_unit(const char *path, char **ret_unit);
int cg_path_get_unit_full(const char *path, char **ret_unit, char **ret_subgroup);
static inline int cg_path_get_unit(const char *path, char **ret_unit) {
return cg_path_get_unit_full(path, ret_unit, NULL);
}
int cg_path_get_unit_path(const char *path, char **ret_unit);
int cg_path_get_user_unit(const char *path, char **ret_unit);
int cg_path_get_machine_name(const char *path, char **ret_machine);
@@ -217,8 +220,14 @@ int cg_pid_get_session(pid_t pid, char **ret_session);
int cg_pidref_get_session(const PidRef *pidref, char **ret);
int cg_pid_get_owner_uid(pid_t pid, uid_t *ret_uid);
int cg_pidref_get_owner_uid(const PidRef *pidref, uid_t *ret);
int cg_pid_get_unit(pid_t pid, char **ret_unit);
int cg_pidref_get_unit(const PidRef *pidref, char **ret);
int cg_pid_get_unit_full(pid_t pid, char **ret_unit, char **ret_subgroup);
static inline int cg_pid_get_unit(pid_t pid, char **ret_unit) {
return cg_pid_get_unit_full(pid, ret_unit, NULL);
}
int cg_pidref_get_unit_full(const PidRef *pidref, char **ret_unit, char **ret_subgroup);
static inline int cg_pidref_get_unit(const PidRef *pidref, char **ret_unit) {
return cg_pidref_get_unit_full(pidref, ret_unit, NULL);
}
int cg_pid_get_user_unit(pid_t pid, char **ret_unit);
int cg_pid_get_machine_name(pid_t pid, char **ret_machine);
int cg_pid_get_slice(pid_t pid, char **ret_slice);
+25
View File
@@ -118,6 +118,31 @@ int pidref_set_pid(PidRef *pidref, pid_t pid) {
return 0;
}
int pidref_set_pid_and_pidfd_id(
PidRef *pidref,
pid_t pid,
uint64_t pidfd_id) {
int r;
assert(pidref);
_cleanup_(pidref_done) PidRef n = PIDREF_NULL;
r = pidref_set_pid(&n, pid);
if (r < 0)
return r;
if (pidfd_id > 0) {
pidref_acquire_pidfd_id(&n);
if (n.fd_id != pidfd_id)
return -ESRCH;
}
*pidref = TAKE_PIDREF(n);
return 0;
}
int pidref_set_pidstr(PidRef *pidref, const char *pid) {
pid_t nr;
int r;
+1
View File
@@ -68,6 +68,7 @@ bool pidref_equal(PidRef *a, PidRef *b);
* PIDREF_MAKE_FROM_PID() above, which does not acquire a pidfd.) */
int pidref_set_pid(PidRef *pidref, pid_t pid);
int pidref_set_pidstr(PidRef *pidref, const char *pid);
int pidref_set_pid_and_pidfd_id(PidRef *pidref, pid_t pid, uint64_t pidfd_id);
int pidref_set_pidfd(PidRef *pidref, int fd);
int pidref_set_pidfd_take(PidRef *pidref, int fd); /* takes ownership of the passed pidfd on success */
int pidref_set_pidfd_consume(PidRef *pidref, int fd); /* takes ownership of the passed pidfd in both success and failure */