mirror of
https://github.com/morgan9e/systemd
synced 2026-04-14 08:25:20 +09:00
Merge pull request #32263 from YHNdnzj/cg-read-pid
core/execute: also check cg_is_threaded for clone3()
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
#include "alloc-util.h"
|
||||
#include "architecture.h"
|
||||
#include "argv-util.h"
|
||||
#include "cgroup-util.h"
|
||||
#include "dirent-util.h"
|
||||
#include "env-file.h"
|
||||
#include "env-util.h"
|
||||
@@ -2108,7 +2109,13 @@ int posix_spawn_wrapper(
|
||||
|
||||
return FLAGS_SET(flags, POSIX_SPAWN_SETCGROUP);
|
||||
}
|
||||
if (!(ERRNO_IS_NOT_SUPPORTED(r) || ERRNO_IS_PRIVILEGE(r)))
|
||||
if (ERRNO_IS_NOT_SUPPORTED(r)) {
|
||||
/* clone3() could also return EOPNOTSUPP if the target cgroup is in threaded mode. */
|
||||
if (cgroup && cg_is_threaded(cgroup) > 0)
|
||||
return -EUCLEAN;
|
||||
|
||||
/* clone3() not available? */
|
||||
} else if (!ERRNO_IS_PRIVILEGE(r))
|
||||
return -r;
|
||||
|
||||
/* Compiled on a newer host, or seccomp&friends blocking clone3()? Fallback, but need to change the
|
||||
|
||||
@@ -772,6 +772,7 @@ static int method_generic_unit_operation(
|
||||
|
||||
assert(message);
|
||||
assert(m);
|
||||
assert(handler);
|
||||
|
||||
/* Read the first argument from the command and pass the operation to the specified per-unit
|
||||
* method. */
|
||||
@@ -947,9 +948,10 @@ static int method_list_units_by_names(sd_bus_message *message, void *userdata, s
|
||||
}
|
||||
|
||||
static int method_get_unit_processes(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
/* Don't load a unit (since it won't have any processes if it's not loaded), but don't insist on the
|
||||
* unit being loaded (because even improperly loaded units might still have processes around */
|
||||
return method_generic_unit_operation(message, userdata, error, bus_unit_method_get_processes, 0);
|
||||
/* Don't load a unit actively (since it won't have any processes if it's not loaded), but don't
|
||||
* insist on the unit being loaded either (because even improperly loaded units might still have
|
||||
* processes around). */
|
||||
return method_generic_unit_operation(message, userdata, error, bus_unit_method_get_processes, /* flags = */ 0);
|
||||
}
|
||||
|
||||
static int method_attach_processes_to_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
|
||||
@@ -4264,9 +4264,10 @@ int exec_invoke(
|
||||
r = cg_attach_everywhere(params->cgroup_supported, p, 0, NULL, NULL);
|
||||
if (r == -EUCLEAN) {
|
||||
*exit_status = EXIT_CGROUP;
|
||||
return log_exec_error_errno(context, params, r, "Failed to attach process to cgroup %s "
|
||||
return log_exec_error_errno(context, params, r,
|
||||
"Failed to attach process to cgroup '%s', "
|
||||
"because the cgroup or one of its parents or "
|
||||
"siblings is in the threaded mode: %m", p);
|
||||
"siblings is in the threaded mode.", p);
|
||||
}
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_CGROUP;
|
||||
|
||||
@@ -456,6 +456,11 @@ int exec_spawn(Unit *unit,
|
||||
environ,
|
||||
cg_unified() > 0 ? subcgroup_path : NULL,
|
||||
&pidref);
|
||||
if (r == -EUCLEAN && subcgroup_path)
|
||||
return log_unit_error_errno(unit, r,
|
||||
"Failed to spawn process into cgroup '%s', because the cgroup "
|
||||
"or one of its parents or siblings is in the threaded mode.",
|
||||
subcgroup_path);
|
||||
if (r < 0)
|
||||
return log_unit_error_errno(unit, r, "Failed to spawn executor: %m");
|
||||
/* We add the new process to the cgroup both in the child (so that we can be sure that no user code is ever
|
||||
|
||||
@@ -64,7 +64,7 @@ static inline bool UNIT_IS_INACTIVE_OR_FAILED(UnitActiveState t) {
|
||||
}
|
||||
|
||||
static inline bool UNIT_IS_LOAD_COMPLETE(UnitLoadState t) {
|
||||
return t >= 0 && t < _UNIT_LOAD_STATE_MAX && t != UNIT_STUB && t != UNIT_MERGED;
|
||||
return t >= 0 && t < _UNIT_LOAD_STATE_MAX && !IN_SET(t, UNIT_STUB, UNIT_MERGED);
|
||||
}
|
||||
|
||||
static inline bool UNIT_IS_LOAD_ERROR(UnitLoadState t) {
|
||||
|
||||
@@ -598,75 +598,52 @@ int cg_migrate(
|
||||
bool done = false;
|
||||
_cleanup_set_free_ Set *s = NULL;
|
||||
int r, ret = 0;
|
||||
pid_t my_pid;
|
||||
|
||||
assert(cfrom);
|
||||
assert(pfrom);
|
||||
assert(cto);
|
||||
assert(pto);
|
||||
|
||||
s = set_new(NULL);
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
|
||||
my_pid = getpid_cached();
|
||||
|
||||
do {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
pid_t pid = 0;
|
||||
pid_t pid;
|
||||
|
||||
done = true;
|
||||
|
||||
r = cg_enumerate_processes(cfrom, pfrom, &f);
|
||||
if (r < 0) {
|
||||
if (ret >= 0 && r != -ENOENT)
|
||||
return r;
|
||||
|
||||
return ret;
|
||||
}
|
||||
if (r < 0)
|
||||
return RET_GATHER(ret, r);
|
||||
|
||||
while ((r = cg_read_pid(f, &pid)) > 0) {
|
||||
|
||||
/* This might do weird stuff if we aren't a
|
||||
* single-threaded program. However, we
|
||||
* luckily know we are not */
|
||||
if ((flags & CGROUP_IGNORE_SELF) && pid == my_pid)
|
||||
/* This might do weird stuff if we aren't a single-threaded program. However, we
|
||||
* luckily know we are. */
|
||||
if (FLAGS_SET(flags, CGROUP_IGNORE_SELF) && pid == getpid_cached())
|
||||
continue;
|
||||
|
||||
if (set_get(s, PID_TO_PTR(pid)) == PID_TO_PTR(pid))
|
||||
if (set_contains(s, PID_TO_PTR(pid)))
|
||||
continue;
|
||||
|
||||
/* Ignore kernel threads. Since they can only
|
||||
* exist in the root cgroup, we only check for
|
||||
* them there. */
|
||||
if (cfrom &&
|
||||
empty_or_root(pfrom) &&
|
||||
/* Ignore kernel threads. Since they can only exist in the root cgroup, we only
|
||||
* check for them there. */
|
||||
if (cfrom && empty_or_root(pfrom) &&
|
||||
pid_is_kernel_thread(pid) > 0)
|
||||
continue;
|
||||
|
||||
r = cg_attach(cto, pto, pid);
|
||||
if (r < 0) {
|
||||
if (ret >= 0 && r != -ESRCH)
|
||||
ret = r;
|
||||
if (r != -ESRCH)
|
||||
RET_GATHER(ret, r);
|
||||
} else if (ret == 0)
|
||||
ret = 1;
|
||||
|
||||
done = false;
|
||||
|
||||
r = set_put(s, PID_TO_PTR(pid));
|
||||
if (r < 0) {
|
||||
if (ret >= 0)
|
||||
return r;
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (r < 0) {
|
||||
if (ret >= 0)
|
||||
return r;
|
||||
|
||||
return ret;
|
||||
r = set_ensure_put(&s, /* hash_ops = */ NULL, PID_TO_PTR(pid));
|
||||
if (r < 0)
|
||||
return RET_GATHER(ret, r);
|
||||
}
|
||||
if (r < 0)
|
||||
return RET_GATHER(ret, r);
|
||||
} while (!done);
|
||||
|
||||
return ret;
|
||||
|
||||
Reference in New Issue
Block a user