Merge pull request #33016 from YHNdnzj/transient-working-dir

core: several cleanups/fixes for WorkingDirectory= handling
This commit is contained in:
Yu Watanabe
2024-05-27 09:40:26 +09:00
committed by GitHub
5 changed files with 62 additions and 37 deletions

View File

@@ -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;

View File

@@ -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");

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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"))