Compare commits

...

10 Commits

Author SHA1 Message Date
Michal Sekletar d0101552e4
Merge 50a367eb1e into 52b0351a15 2024-11-20 17:00:21 +07:00
Yu Watanabe 52b0351a15
core/exec-invoke: suppress placeholder home only in build_environment() (#35219)
Alternative to https://github.com/systemd/systemd/pull/34789
Closes #34789
2024-11-20 17:34:25 +09:00
Luca Boccassi fe077a1a58 units: add initrd directory to list of conditions for systemd-confext
systemd-sysext has the same check, but it was forgotten for confexts.
Needed to activate confexts from the ESP in the initrd.
2024-11-20 09:12:24 +01:00
Xuanjun Wen a526b9ddfc hwdb: add new Cube Mix Plus (i18D) rotation info
Added rotation information for the new version of Cube Mix Plus (i18D).
2024-11-20 05:23:34 +09:00
Mike Yuan 804dd670d1
sd-varlink: mark sd_varlink_server_{ref,unref} as _public_ (#35241)
Co-authored-by: Thorsten Kukuk <kukuk@suse.com>
2024-11-20 05:21:15 +09:00
Mike Yuan b718b86e1b
core/exec-invoke: suppress placeholder home only in build_environment()
Currently, get_fixed_user() employs USER_CREDS_SUPPRESS_PLACEHOLDER,
meaning home path is set to NULL if it's empty or root. However,
the path is also used for applying WorkingDirectory=~, and we'd
spuriously use the invoking user's home as fallback even if
User= is changed in that case.

Let's instead delegate such suppression to build_environment(),
so that home is proper initialized for usage at other steps.
shell doesn't actually suffer from such problem, but it's changed
too for consistency.

Alternative to #34789
2024-11-19 00:38:18 +01:00
Mike Yuan d911778877
core/exec-invoke: minor cleanup for apply_working_directory() error handling
Assign exit_status at the same site where error log is emitted,
for readability.
2024-11-19 00:38:18 +01:00
Mike Yuan eea9d3eb10
basic/user-util: split out placeholder suppression from USER_CREDS_CLEAN into its own flag
No functional change, preparation for later commits.
2024-11-19 00:38:18 +01:00
Mike Yuan 579ce77ead
basic/user-util: introduce shell_is_placeholder() helper 2024-11-19 00:38:18 +01:00
Michal Sekletar 50a367eb1e man: adjust description of PrivateUsers= so it is in line with reality
When the option is not available unit will not even start so there is
no security risk.

Fixes #34983
2024-11-15 23:11:09 +01:00
10 changed files with 66 additions and 47 deletions

View File

@ -376,11 +376,12 @@ sensor:modalias:acpi:KIOX000A*:dmi:*:svncube:pni1-TF:*
sensor:modalias:acpi:SMO8500*:dmi:*:svncube:pni7:*
ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
# Cube i7 Stylus, i7 Stylus I8L Model, i7 Book (i16) and Mix Plus (i18B)
# Cube i7 Stylus, i7 Stylus I8L Model, i7 Book (i16) and Mix Plus (i18B/i18D)
sensor:modalias:acpi:KIOX000A*:dmi:*:svnCube:pni7Stylus:*
sensor:modalias:acpi:KIOX000A*:dmi:*:svnCube:pni8-L:*
sensor:modalias:acpi:KIOX000A*:dmi:*:svnCube:pni16:*
sensor:modalias:acpi:KIOX000A*:dmi:*:svnCube:pni18B:*
sensor:modalias:acpi:KIOX000A*:dmi:*:svnALLDOCUBE:pni18D:*
ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1
# Cube iWork 10 Flagship

View File

@ -2045,10 +2045,6 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
databases in the root directory and on the host is reduced, as the only users and groups who need to be matched
are <literal>root</literal>, <literal>nobody</literal> and the unit's own user and group.</para>
<para>Note that the implementation of this setting might be impossible (for example if user namespaces are not
available), and the unit should be written in a way that does not solely rely on this setting for
security.</para>
<xi:include href="version-info.xml" xpointer="v232"/></listitem>
</varlistentry>

View File

@ -220,9 +220,9 @@ static int synthesize_user_creds(
if (ret_gid)
*ret_gid = GID_NOBODY;
if (ret_home)
*ret_home = FLAGS_SET(flags, USER_CREDS_CLEAN) ? NULL : "/";
*ret_home = FLAGS_SET(flags, USER_CREDS_SUPPRESS_PLACEHOLDER) ? NULL : "/";
if (ret_shell)
*ret_shell = FLAGS_SET(flags, USER_CREDS_CLEAN) ? NULL : NOLOGIN;
*ret_shell = FLAGS_SET(flags, USER_CREDS_SUPPRESS_PLACEHOLDER) ? NULL : NOLOGIN;
return 0;
}
@ -244,6 +244,7 @@ int get_user_creds(
assert(username);
assert(*username);
assert((ret_home || ret_shell) || !(flags & (USER_CREDS_SUPPRESS_PLACEHOLDER|USER_CREDS_CLEAN)));
if (!FLAGS_SET(flags, USER_CREDS_PREFER_NSS) ||
(!ret_home && !ret_shell)) {
@ -315,17 +316,14 @@ int get_user_creds(
if (ret_home)
/* Note: we don't insist on normalized paths, since there are setups that have /./ in the path */
*ret_home = (FLAGS_SET(flags, USER_CREDS_CLEAN) &&
(empty_or_root(p->pw_dir) ||
!path_is_valid(p->pw_dir) ||
!path_is_absolute(p->pw_dir))) ? NULL : p->pw_dir;
*ret_home = (FLAGS_SET(flags, USER_CREDS_SUPPRESS_PLACEHOLDER) && empty_or_root(p->pw_dir)) ||
(FLAGS_SET(flags, USER_CREDS_CLEAN) && (!path_is_valid(p->pw_dir) || !path_is_absolute(p->pw_dir)))
? NULL : p->pw_dir;
if (ret_shell)
*ret_shell = (FLAGS_SET(flags, USER_CREDS_CLEAN) &&
(isempty(p->pw_shell) ||
!path_is_valid(p->pw_shell) ||
!path_is_absolute(p->pw_shell) ||
is_nologin_shell(p->pw_shell))) ? NULL : p->pw_shell;
*ret_shell = (FLAGS_SET(flags, USER_CREDS_SUPPRESS_PLACEHOLDER) && shell_is_placeholder(p->pw_shell)) ||
(FLAGS_SET(flags, USER_CREDS_CLEAN) && (!path_is_valid(p->pw_shell) || !path_is_absolute(p->pw_shell)))
? NULL : p->pw_shell;
if (patch_username)
*username = p->pw_name;

View File

@ -12,6 +12,8 @@
#include <sys/types.h>
#include <unistd.h>
#include "string-util.h"
/* Users managed by systemd-homed. See https://systemd.io/UIDS-GIDS for details how this range fits into the rest of the world */
#define HOME_UID_MIN ((uid_t) 60001)
#define HOME_UID_MAX ((uid_t) 60513)
@ -36,10 +38,20 @@ static inline int parse_gid(const char *s, gid_t *ret_gid) {
char* getlogname_malloc(void);
char* getusername_malloc(void);
const char* default_root_shell_at(int rfd);
const char* default_root_shell(const char *root);
bool is_nologin_shell(const char *shell);
static inline bool shell_is_placeholder(const char *shell) {
return isempty(shell) || is_nologin_shell(shell);
}
typedef enum UserCredsFlags {
USER_CREDS_PREFER_NSS = 1 << 0, /* if set, only synthesize user records if database lacks them. Normally we bypass the userdb entirely for the records we can synthesize */
USER_CREDS_ALLOW_MISSING = 1 << 1, /* if a numeric UID string is resolved, be OK if there's no record for it */
USER_CREDS_CLEAN = 1 << 2, /* try to clean up shell and home fields with invalid data */
USER_CREDS_PREFER_NSS = 1 << 0, /* if set, only synthesize user records if database lacks them. Normally we bypass the userdb entirely for the records we can synthesize */
USER_CREDS_ALLOW_MISSING = 1 << 1, /* if a numeric UID string is resolved, be OK if there's no record for it */
USER_CREDS_CLEAN = 1 << 2, /* try to clean up shell and home fields with invalid data */
USER_CREDS_SUPPRESS_PLACEHOLDER = 1 << 3, /* suppress home and/or shell fields if value is placeholder (root/empty/nologin) */
} UserCredsFlags;
int get_user_creds(const char **username, uid_t *ret_uid, gid_t *ret_gid, const char **ret_home, const char **ret_shell, UserCredsFlags flags);
@ -125,10 +137,6 @@ int fgetsgent_sane(FILE *stream, struct sgrp **sg);
int putsgent_sane(const struct sgrp *sg, FILE *stream);
#endif
bool is_nologin_shell(const char *shell);
const char* default_root_shell_at(int rfd);
const char* default_root_shell(const char *root);
int is_this_me(const char *username);
const char* get_home_root(void);

View File

@ -855,9 +855,6 @@ static int get_fixed_user(
assert(user_or_uid);
assert(ret_username);
/* Note that we don't set $HOME or $SHELL if they are not particularly enlightening anyway
* (i.e. are "/" or "/bin/nologin"). */
r = get_user_creds(&user_or_uid, ret_uid, ret_gid, ret_home, ret_shell, USER_CREDS_CLEAN);
if (r < 0)
return r;
@ -1883,7 +1880,10 @@ static int build_environment(
}
}
if (home && set_user_login_env) {
/* Note that we don't set $HOME or $SHELL if they are not particularly enlightening anyway
* (i.e. are "/" or "/bin/nologin"). */
if (home && set_user_login_env && !empty_or_root(home)) {
x = strjoin("HOME=", home);
if (!x)
return -ENOMEM;
@ -1892,7 +1892,7 @@ static int build_environment(
our_env[n_env++] = x;
}
if (shell && set_user_login_env) {
if (shell && set_user_login_env && !shell_is_placeholder(shell)) {
x = strjoin("SHELL=", shell);
if (!x)
return -ENOMEM;
@ -3471,20 +3471,16 @@ static int apply_working_directory(
const ExecContext *context,
const ExecParameters *params,
ExecRuntime *runtime,
const char *home,
int *exit_status) {
const char *home) {
const char *wd;
int r;
assert(context);
assert(exit_status);
if (context->working_directory_home) {
if (!home) {
*exit_status = EXIT_CHDIR;
if (!home)
return -ENXIO;
}
wd = home;
} else
@ -3503,13 +3499,7 @@ static int apply_working_directory(
if (r >= 0)
r = RET_NERRNO(fchdir(dfd));
}
if (r < 0 && !context->working_directory_missing_ok) {
*exit_status = EXIT_CHDIR;
return r;
}
return 0;
return context->working_directory_missing_ok ? 0 : r;
}
static int apply_root_directory(
@ -3785,7 +3775,7 @@ static int acquire_home(const ExecContext *c, const char **home, char **ret_buf)
if (!c->working_directory_home)
return 0;
if (c->dynamic_user)
if (c->dynamic_user || (c->user && is_this_me(c->user) <= 0))
return -EADDRNOTAVAIL;
r = get_home_dir(ret_buf);
@ -4543,7 +4533,7 @@ int exec_invoke(
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");
return log_exec_error_errno(context, params, r, "Failed to determine $HOME for the invoking user: %m");
}
/* If a socket is connected to STDIN/STDOUT/STDERR, we must drop O_NONBLOCK */
@ -5382,9 +5372,11 @@ int exec_invoke(
* 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)
r = apply_working_directory(context, params, runtime, home);
if (r < 0) {
*exit_status = EXIT_CHDIR;
return log_exec_error_errno(context, params, r, "Changing to the requested working directory failed: %m");
}
if (needs_sandboxing) {
/* Apply other MAC contexts late, but before seccomp syscall filtering, as those should really be last to

View File

@ -1033,12 +1033,14 @@ global:
sd_varlink_server_listen_fd;
sd_varlink_server_loop_auto;
sd_varlink_server_new;
sd_varlink_server_ref;
sd_varlink_server_set_connections_max;
sd_varlink_server_set_connections_per_uid_max;
sd_varlink_server_set_description;
sd_varlink_server_set_exit_on_idle;
sd_varlink_server_set_userdata;
sd_varlink_server_shutdown;
sd_varlink_server_unref;
sd_varlink_set_allow_fd_passing_input;
sd_varlink_set_allow_fd_passing_output;
sd_varlink_set_description;

View File

@ -3265,7 +3265,7 @@ static sd_varlink_server* varlink_server_destroy(sd_varlink_server *s) {
return mfree(s);
}
DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_varlink_server, sd_varlink_server, varlink_server_destroy);
DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_varlink_server, sd_varlink_server, varlink_server_destroy);
static int validate_connection(sd_varlink_server *server, const struct ucred *ucred) {
int allowed = -1;

View File

@ -2297,7 +2297,8 @@ static int start_transient_scope(sd_bus *bus) {
uid_t uid;
gid_t gid;
r = get_user_creds(&arg_exec_user, &uid, &gid, &home, &shell, USER_CREDS_CLEAN|USER_CREDS_PREFER_NSS);
r = get_user_creds(&arg_exec_user, &uid, &gid, &home, &shell,
USER_CREDS_CLEAN|USER_CREDS_SUPPRESS_PLACEHOLDER|USER_CREDS_PREFER_NSS);
if (r < 0)
return log_error_errno(r, "Failed to resolve user %s: %m", arg_exec_user);

View File

@ -0,0 +1,20 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
set -eux
set -o pipefail
# shellcheck source=test/units/util.sh
. "$(dirname "$0")"/util.sh
(! systemd-run --wait -p DynamicUser=yes \
-p EnvironmentFile=-/usr/lib/systemd/systemd-asan-env \
-p WorkingDirectory='~' true)
assert_eq "$(systemd-run --pipe --uid=root -p WorkingDirectory='~' pwd)" "/root"
assert_eq "$(systemd-run --pipe --uid=nobody -p WorkingDirectory='~' pwd)" "/"
assert_eq "$(systemd-run --pipe --uid=testuser -p WorkingDirectory='~' pwd)" "/home/testuser"
(! systemd-run --wait -p DynamicUser=yes -p User=testuser \
-p EnvironmentFile=-/usr/lib/systemd/systemd-asan-env \
-p WorkingDirectory='~' true)

View File

@ -16,6 +16,7 @@ ConditionDirectoryNotEmpty=|/run/confexts
ConditionDirectoryNotEmpty=|/var/lib/confexts
ConditionDirectoryNotEmpty=|/usr/local/lib/confexts
ConditionDirectoryNotEmpty=|/usr/lib/confexts
ConditionDirectoryNotEmpty=|/.extra/confext
DefaultDependencies=no
After=local-fs.target