mirror of
https://github.com/morgan9e/systemd
synced 2026-04-14 00:14:32 +09:00
Merge pull request #33016 from YHNdnzj/transient-working-dir
core: several cleanups/fixes for WorkingDirectory= handling
This commit is contained in:
@@ -2716,38 +2716,38 @@ int bus_exec_context_set_transient_property(
|
||||
|
||||
} else if (streq(name, "WorkingDirectory")) {
|
||||
_cleanup_free_ char *simplified = NULL;
|
||||
bool missing_ok, is_home;
|
||||
bool missing_ok = false, is_home = false;
|
||||
const char *s;
|
||||
|
||||
r = sd_bus_message_read(message, "s", &s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (s[0] == '-') {
|
||||
missing_ok = true;
|
||||
s++;
|
||||
} else
|
||||
missing_ok = false;
|
||||
if (!isempty(s)) {
|
||||
if (s[0] == '-') {
|
||||
missing_ok = true;
|
||||
s++;
|
||||
}
|
||||
|
||||
if (isempty(s))
|
||||
is_home = false;
|
||||
else if (streq(s, "~"))
|
||||
is_home = true;
|
||||
else {
|
||||
if (!path_is_absolute(s))
|
||||
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "WorkingDirectory= expects an absolute path or '~'");
|
||||
if (streq(s, "~"))
|
||||
is_home = true;
|
||||
else {
|
||||
if (!path_is_absolute(s))
|
||||
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"WorkingDirectory= expects an absolute path or '~'");
|
||||
|
||||
r = path_simplify_alloc(s, &simplified);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = path_simplify_alloc(s, &simplified);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!path_is_normalized(simplified))
|
||||
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "WorkingDirectory= expects a normalized path or '~'");
|
||||
if (!path_is_normalized(simplified))
|
||||
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"WorkingDirectory= expects a normalized path or '~'");
|
||||
|
||||
if (path_below_api_vfs(simplified))
|
||||
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "WorkingDirectory= may not be below /proc/, /sys/ or /dev/.");
|
||||
|
||||
is_home = false;
|
||||
if (path_below_api_vfs(simplified))
|
||||
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"WorkingDirectory= may not be below /proc/, /sys/ or /dev/");
|
||||
}
|
||||
}
|
||||
|
||||
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
||||
@@ -2755,7 +2755,10 @@ int bus_exec_context_set_transient_property(
|
||||
c->working_directory_home = is_home;
|
||||
c->working_directory_missing_ok = missing_ok;
|
||||
|
||||
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "WorkingDirectory=%s%s", missing_ok ? "-" : "", c->working_directory_home ? "+" : ASSERT_PTR(c->working_directory));
|
||||
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name,
|
||||
"WorkingDirectory=%s%s",
|
||||
c->working_directory_missing_ok ? "-" : "",
|
||||
c->working_directory_home ? "~" : strempty(c->working_directory));
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -3585,26 +3585,29 @@ static int send_user_lookup(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acquire_home(const ExecContext *c, uid_t uid, const char** home, char **buf) {
|
||||
static int acquire_home(const ExecContext *c, const char **home, char **ret_buf) {
|
||||
int r;
|
||||
|
||||
assert(c);
|
||||
assert(home);
|
||||
assert(buf);
|
||||
assert(ret_buf);
|
||||
|
||||
/* If WorkingDirectory=~ is set, try to acquire a usable home directory. */
|
||||
|
||||
if (*home)
|
||||
if (*home) /* Already acquired from get_fixed_user()? */
|
||||
return 0;
|
||||
|
||||
if (!c->working_directory_home)
|
||||
return 0;
|
||||
|
||||
r = get_home_dir(buf);
|
||||
if (c->dynamic_user)
|
||||
return -EADDRNOTAVAIL;
|
||||
|
||||
r = get_home_dir(ret_buf);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*home = *buf;
|
||||
*home = *ret_buf;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -4291,7 +4294,7 @@ int exec_invoke(
|
||||
|
||||
params->user_lookup_fd = safe_close(params->user_lookup_fd);
|
||||
|
||||
r = acquire_home(context, uid, &home, &home_buffer);
|
||||
r = acquire_home(context, &home, &home_buffer);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_CHDIR;
|
||||
return log_exec_error_errno(context, params, r, "Failed to determine $HOME for user: %m");
|
||||
|
||||
@@ -2608,6 +2608,7 @@ int config_parse_working_directory(
|
||||
assert(rvalue);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
c->working_directory_missing_ok = false;
|
||||
c->working_directory_home = false;
|
||||
c->working_directory = mfree(c->working_directory);
|
||||
return 0;
|
||||
|
||||
@@ -4217,6 +4217,21 @@ static int user_from_unit_name(Unit *u, char **ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unit_verify_contexts(const Unit *u, const ExecContext *ec) {
|
||||
assert(u);
|
||||
|
||||
if (!ec)
|
||||
return 0;
|
||||
|
||||
if (MANAGER_IS_USER(u->manager) && ec->dynamic_user)
|
||||
return log_unit_error_errno(u, SYNTHETIC_ERRNO(ENOEXEC), "DynamicUser= enabled for user unit, which is not supported. Refusing.");
|
||||
|
||||
if (ec->dynamic_user && ec->working_directory_home)
|
||||
return log_unit_error_errno(u, SYNTHETIC_ERRNO(ENOEXEC), "WorkingDirectory=~ is not allowed under DynamicUser=yes. Refusing.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unit_patch_contexts(Unit *u) {
|
||||
CGroupContext *cc;
|
||||
ExecContext *ec;
|
||||
@@ -4238,16 +4253,14 @@ int unit_patch_contexts(Unit *u) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (MANAGER_IS_USER(u->manager) &&
|
||||
!ec->working_directory) {
|
||||
|
||||
if (MANAGER_IS_USER(u->manager) && !ec->working_directory) {
|
||||
r = get_home_dir(&ec->working_directory);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Allow user services to run, even if the
|
||||
* home directory is missing */
|
||||
ec->working_directory_missing_ok = true;
|
||||
if (!ec->working_directory_home)
|
||||
/* If home directory is implied by us, allow it to be missing. */
|
||||
ec->working_directory_missing_ok = true;
|
||||
}
|
||||
|
||||
if (ec->private_devices)
|
||||
@@ -4342,7 +4355,7 @@ int unit_patch_contexts(Unit *u) {
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return unit_verify_contexts(u, ec);
|
||||
}
|
||||
|
||||
ExecContext *unit_get_exec_context(const Unit *u) {
|
||||
|
||||
@@ -987,6 +987,11 @@ static char* private_directory_bad(Manager *m) {
|
||||
}
|
||||
|
||||
static void test_exec_dynamicuser(Manager *m) {
|
||||
if (MANAGER_IS_USER(m)) {
|
||||
log_notice("Skipping %s for user manager", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
_cleanup_free_ char *bad = private_directory_bad(m);
|
||||
if (bad) {
|
||||
log_warning("%s: %s has bad permissions, skipping test.", __func__, bad);
|
||||
@@ -998,7 +1003,7 @@ static void test_exec_dynamicuser(Manager *m) {
|
||||
return;
|
||||
}
|
||||
|
||||
int status = can_unshare ? 0 : MANAGER_IS_SYSTEM(m) ? EXIT_NAMESPACE : EXIT_GROUP;
|
||||
int status = can_unshare ? 0 : EXIT_NAMESPACE;
|
||||
|
||||
test(m, "exec-dynamicuser-fixeduser.service", status, CLD_EXITED);
|
||||
if (check_user_has_group_with_same_name("adm"))
|
||||
|
||||
Reference in New Issue
Block a user