Merge pull request #31210 from poettering/chdir-hardening

WorkingDirectory= hardening
This commit is contained in:
Luca Boccassi
2024-02-06 12:41:43 +00:00
committed by GitHub
10 changed files with 146 additions and 57 deletions
+26 -15
View File
@@ -2721,8 +2721,9 @@ int bus_exec_context_set_transient_property(
return 1;
} else if (streq(name, "WorkingDirectory")) {
_cleanup_free_ char *simplified = NULL;
bool missing_ok, is_home;
const char *s;
bool missing_ok;
r = sd_bus_message_read(message, "s", &s);
if (r < 0)
@@ -2734,23 +2735,33 @@ int bus_exec_context_set_transient_property(
} else
missing_ok = false;
if (!isempty(s) && !streq(s, "~") && !path_is_absolute(s))
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "WorkingDirectory= expects an absolute path or '~'");
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 '~'");
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_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 (!UNIT_WRITE_FLAGS_NOOP(flags)) {
if (streq(s, "~")) {
c->working_directory = mfree(c->working_directory);
c->working_directory_home = true;
} else {
r = free_and_strdup(&c->working_directory, empty_to_null(s));
if (r < 0)
return r;
c->working_directory_home = false;
}
free_and_replace(c->working_directory, simplified);
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 ? "-" : "", s);
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "WorkingDirectory=%s%s", missing_ok ? "-" : "", c->working_directory_home ? "+" : ASSERT_PTR(c->working_directory));
}
return 1;
+20 -10
View File
@@ -3337,31 +3337,39 @@ static int apply_working_directory(
const char *home,
int *exit_status) {
const char *d, *wd;
const char *wd;
int r;
assert(context);
assert(exit_status);
if (context->working_directory_home) {
if (!home) {
*exit_status = EXIT_CHDIR;
return -ENXIO;
}
wd = home;
} else
wd = empty_to_root(context->working_directory);
if (params->flags & EXEC_APPLY_CHROOT)
d = wd;
else
d = prefix_roota((runtime ? runtime->ephemeral_copy : NULL) ?: context->root_directory, wd);
r = RET_NERRNO(chdir(wd));
else {
_cleanup_close_ int dfd = -EBADF;
if (chdir(d) < 0 && !context->working_directory_missing_ok) {
r = chase(wd,
(runtime ? runtime->ephemeral_copy : NULL) ?: context->root_directory,
CHASE_PREFIX_ROOT|CHASE_AT_RESOLVE_IN_ROOT,
/* ret_path= */ NULL,
&dfd);
if (r >= 0)
r = RET_NERRNO(fchdir(dfd));
}
if (r < 0 && !context->working_directory_missing_ok) {
*exit_status = EXIT_CHDIR;
return -errno;
return r;
}
return 0;
@@ -5032,8 +5040,10 @@ int exec_invoke(
}
}
/* Apply working directory here, because the working directory might be on NFS and only the user running
* this service might have the correct privilege to change to the working directory */
/* Apply working directory here, because the working directory might be on NFS and only the user
* running this service might have the correct privilege to change to the working directory. Also, it
* is absolutely 💣 crucial 💣 we applied all mount namespacing rearrangements before this, so that
* the cwd cannot be used to pin directories outside of the sandbox. */
r = apply_working_directory(context, params, runtime, home, exit_status);
if (r < 0)
return log_exec_error_errno(context, params, r, "Changing to the requested working directory failed: %m");
+6 -6
View File
@@ -606,7 +606,7 @@ int config_parse_socket_listen(
return 0;
}
r = path_simplify_and_warn(k, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
r = path_simplify_and_warn(k, PATH_CHECK_ABSOLUTE|PATH_CHECK_NON_API_VFS, unit, filename, line, lvalue);
if (r < 0)
return 0;
@@ -2660,7 +2660,7 @@ int config_parse_working_directory(
return missing_ok ? 0 : -ENOEXEC;
}
r = path_simplify_and_warn(k, PATH_CHECK_ABSOLUTE | (missing_ok ? 0 : PATH_CHECK_FATAL), unit, filename, line, lvalue);
r = path_simplify_and_warn(k, PATH_CHECK_ABSOLUTE|PATH_CHECK_NON_API_VFS|(missing_ok ? 0 : PATH_CHECK_FATAL), unit, filename, line, lvalue);
if (r < 0)
return missing_ok ? 0 : -ENOEXEC;
@@ -5422,7 +5422,7 @@ int config_parse_mount_images(
continue;
}
r = path_simplify_and_warn(sresolved, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
r = path_simplify_and_warn(sresolved, PATH_CHECK_ABSOLUTE|PATH_CHECK_NON_API_VFS, unit, filename, line, lvalue);
if (r < 0)
continue;
@@ -5438,7 +5438,7 @@ int config_parse_mount_images(
continue;
}
r = path_simplify_and_warn(dresolved, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
r = path_simplify_and_warn(dresolved, PATH_CHECK_ABSOLUTE|PATH_CHECK_NON_API_VFS, unit, filename, line, lvalue);
if (r < 0)
continue;
@@ -5580,7 +5580,7 @@ int config_parse_extension_images(
continue;
}
r = path_simplify_and_warn(sresolved, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
r = path_simplify_and_warn(sresolved, PATH_CHECK_ABSOLUTE|PATH_CHECK_NON_API_VFS, unit, filename, line, lvalue);
if (r < 0)
continue;
@@ -5801,7 +5801,7 @@ int config_parse_pid_file(
return log_oom();
/* Check that the result is a sensible path */
r = path_simplify_and_warn(n, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
r = path_simplify_and_warn(n, PATH_CHECK_ABSOLUTE|PATH_CHECK_NON_API_VFS, unit, filename, line, lvalue);
if (r < 0)
return r;