1
0
mirror of https://github.com/systemd/systemd synced 2025-12-28 11:54:45 +01:00

Compare commits

..

25 Commits

Author SHA1 Message Date
Zbigniew Jędrzejewski-Szmek
960b585ba1
Merge pull request #17145 from poettering/kill-chmod-and-chown-unsafe
remove chmod_and_chown_unsafe()
2020-09-24 09:40:56 +02:00
Lennart Poettering
bcaf20dc38
Merge pull request #17143 from keszybz/late-exec-resolution-alt
Late exec resolution (subset)
2020-09-24 09:38:36 +02:00
germanztz
73439a3d76
hwdb: add Medion Akoya E2221T MD60691 (#17147) 2020-09-24 09:33:43 +02:00
Charles Lee
19ad553442 Translated using Weblate (Chinese (Simplified))
Currently translated at 63.1% (118 of 187 strings)

Co-authored-by: Charles Lee <lchopn@gmail.com>
Translate-URL: https://translate.fedoraproject.org/projects/systemd/master/zh_CN/
Translation: systemd/master
2020-09-24 09:30:56 +02:00
Kyle Huey
fbccb980e5 random-util: Add an environment variable to disable RDRAND.
SYSTEMD_RDRAND=0 will prevent using RDRAND even on systems whose CPUID claims
to support it. All other values have no effect.

Fixes: #17112
2020-09-24 09:22:45 +02:00
Anita Zhang
6de6f4891f
Merge pull request #17142 from poettering/catalog-fix-de
catalog: add missing @ to German catalog file
2020-09-23 23:41:38 -07:00
Anita Zhang
8f4946dc8b
Merge pull request #17146 from poettering/use-more-proc-mounted
use proc_mounted() more
2020-09-23 23:39:20 -07:00
Lennart Poettering
4265a66a5e fs-util: check for /proc mounted in access_fd()
It's a very basic function very similar to other cases where we go via
/proc/self/fd/, hence do the explicit proc_mounted() check here too.
2020-09-23 18:20:38 +02:00
Lennart Poettering
48d837cd92 fs-util: use strna() on returned strings of fd_get_path() if we don't check its return value
Let's make sure to use strna() on the strings returned by fd_get_path()
where we knowingly ignore any failures. We got this right in most cases,
but two were missing.
2020-09-23 18:20:38 +02:00
Lennart Poettering
8fe8f3aaba basic: update fd_get_path() to use proc_mounted() helper
We use it pretty much everywhere else, hence use it here too.

This also changes the error generated from EOPNOTSUPP to ENOSYS, to
match the other cases where we do such a check. One user checked for
EOPNOTSUPP which is updated to check for ENOSYS instead.
2020-09-23 18:20:38 +02:00
Lennart Poettering
1e5bfa2ac8 fs-util: drop chmod_and_chown_unsafe() which is unused now 2020-09-23 18:00:19 +02:00
Lennart Poettering
62c03398ba sysusers: modernize file backup logic a bit
Let's use _cleanup_ magic to clean up files, let's fully operate by fds
whenever we can.
2020-09-23 18:00:19 +02:00
Zbigniew Jędrzejewski-Szmek
8038b99d0d run: let systemd resolve the path with RootDirectory=/RootImage=
Fixes #13338.
2020-09-23 14:49:37 +02:00
Zbigniew Jędrzejewski-Szmek
526e3cbbdd core: don't try to load units from non-absolute paths
The error message disagreed with the check that was actually performed. Adjust the check.
2020-09-23 14:49:37 +02:00
Lennart Poettering
3142135098 catalog: add missing @ to German catalog file 2020-09-23 13:56:51 +02:00
Zbigniew Jędrzejewski-Szmek
0af07108e4 core/execute: reduce indentation level a bit 2020-09-18 15:28:48 +02:00
Zbigniew Jędrzejewski-Szmek
9f71ba8d95 core: resolve binary names immediately before execution
This has two advantages:
- we save a bit of IO in early boot because we don't look for executables
  which we might never call
- if the executable is in a different place and it was specified as a
  non-absolute path, it is OK if it moves to a different place. This should
  solve the case paths are different in the initramfs.

Since the executable path is only available quite late, the call to
mac_selinux_get_child_mls_label() which uses the path needs to be moved down
too.

Fixes #16076.
2020-09-18 15:28:48 +02:00
Zbigniew Jędrzejewski-Szmek
92673045b5 basic/path-util: enhance find_executable() for the fixed path case 2020-09-18 15:28:48 +02:00
Zbigniew Jędrzejewski-Szmek
cd4ff5aa11 basic/path-util: inline two trivial functions
While at it, add assert() for the argument.
2020-09-18 15:28:48 +02:00
Zbigniew Jędrzejewski-Szmek
f7bc0c324a Rename find_binary to find_executable
"executable" is more correct than "binary", since scripts are OK too.
2020-09-18 15:28:48 +02:00
Zbigniew Jędrzejewski-Szmek
0706c01259 Add CLOSE_AND_REPLACE helper
Similar to free_and_replace. I think this should be uppercase to make it
clear that this is a macro. free_and_replace should probably be uppercased
too.
2020-09-18 15:28:48 +02:00
Zbigniew Jędrzejewski-Szmek
831d57953e core: use X_OK when looking for executables
Other tools silently ignore non-executable names found in path. By checking
F_OK, we would could pick non-executable path even though there is an executable
one later.
2020-09-18 15:28:48 +02:00
Zbigniew Jędrzejewski-Szmek
598c47c86e core/load-fragment: don't treat "; ;" as "/usr/bin/;"
We had a special test case that the second semicolon would be interpreted
as an executable name. We would then try to find the executable and rely
on ";" not being found to cause ENOEXEC to be returned. I think that's just
crazy. Let's treat the second semicolon as a separator and ignore the
whole thing as we would whitespace.
2020-09-18 15:28:48 +02:00
Zbigniew Jędrzejewski-Szmek
fe65d69243 test-execute: include test location in error output
test-execute is quite long and even with the test name it takes a moment
to find the relevant spot when something fails. Let's make things easier
by printing the exact location.
2020-09-18 15:28:48 +02:00
Zbigniew Jędrzejewski-Szmek
1c32257147 test-path-util: also check filename_is_valid() with paths with slashes 2020-09-18 15:27:11 +02:00
28 changed files with 440 additions and 470 deletions

View File

@ -1,7 +1,7 @@
# SPDX-License-Identifier: LGPL-2.1+
-- fc2e22bc6ee647b6b90729ab34a250b1
Subject: Speicherabbild für Prozess @COREDUMP_PID@ (@COREDUMP_COMM) generiert
Subject: Speicherabbild für Prozess @COREDUMP_PID@ (@COREDUMP_COMM@) generiert
Defined-By: systemd
Support: %SUPPORT_URL%
Documentation: man:core(5)

View File

@ -80,6 +80,9 @@ All tools:
honoured on systems built with libxcrypt and is ignored on systems using
glibc's original, internal crypt() implementation.)
* `$SYSTEMD_RDRAND=0` — if set, the RDRAND instruction will never be used,
even if the CPU supports it.
systemctl:
* `$SYSTEMCTL_FORCE_BUS=1` — if set, do not connect to PID1's private D-Bus

View File

@ -518,6 +518,11 @@ sensor:modalias:acpi:KIOX010A*:dmi:*:svnMEDION:pnE*:*
sensor:modalias:acpi:KIOX010A*:dmi:*:svnMEDION:pnMEDION*:*
ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1
# Medion Akoya E2221T MD60691
sensor:modalias:acpi:KIOX020A*:dmi:*:pnE2221TMD60691*:*
ACCEL_MOUNT_MATRIX=1, 0, 0; 0, 1, 0; 0, 0, 1
ACCEL_LOCATION=base
#########################################
# MPMAN
#########################################

View File

@ -5,20 +5,22 @@
# Frank Hill <hxf.prc@gmail.com>, 2014.
# Boyuan Yang <073plan@gmail.com>, 2015.
# Jeff Bai <jeffbai@aosc.xyz>, 2016.
# Charles Lee <lchopn@gmail.com>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: systemd\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-08-19 18:02+0200\n"
"PO-Revision-Date: 2016-03-01 20:38-0700\n"
"Last-Translator: Jeff Bai <jeffbai@aosc.xyz>\n"
"Language-Team: Chinese <i18n-zh@googlegroups.com>\n"
"PO-Revision-Date: 2020-09-24 04:29+0000\n"
"Last-Translator: Charles Lee <lchopn@gmail.com>\n"
"Language-Team: Chinese (Simplified) <https://translate.fedoraproject.org/"
"projects/systemd/master/zh_CN/>\n"
"Language: zh_CN\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 1.8.7.1\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Weblate 4.2.2\n"
#: src/core/org.freedesktop.systemd1.policy.in:22
msgid "Send passphrase back to system"
@ -294,8 +296,6 @@ msgid ""
msgstr "允许应用程序阻止系统响应笔记本上盖开关事件需要认证。"
#: src/login/org.freedesktop.login1.policy:117
#, fuzzy
#| msgid "Allow non-logged-in users to run programs"
msgid "Allow non-logged-in user to run programs"
msgstr "允许未登录用户运行程序"
@ -395,42 +395,28 @@ msgid "Halt the system"
msgstr "休眠系统"
#: src/login/org.freedesktop.login1.policy:225
#, fuzzy
#| msgid "Authentication is required to hibernate the system."
msgid "Authentication is required to halt the system."
msgstr "休眠系统需要认证。"
msgstr "停止系统需要认证。"
#: src/login/org.freedesktop.login1.policy:235
#, fuzzy
#| msgid "Hibernate the system while other users are logged in"
msgid "Halt the system while other users are logged in"
msgstr "存在其他已登录用户时仍然休眠"
msgstr "当存在其他已登录用户时仍然停止系统"
#: src/login/org.freedesktop.login1.policy:236
#, fuzzy
#| msgid ""
#| "Authentication is required to hibernate the system while other users are "
#| "logged in."
msgid ""
"Authentication is required to halt the system while other users are logged "
"in."
msgstr "存在其他已登录用户时进行休眠系统需要认证。"
msgstr "当存在其他已登录用户时停止系统需要认证。"
#: src/login/org.freedesktop.login1.policy:246
#, fuzzy
#| msgid "Hibernate the system while an application is inhibiting this"
msgid "Halt the system while an application is inhibiting this"
msgstr "有其它应用程序阻止时仍然休眠"
msgstr "当存在应用程序阻止时仍然停止系统"
#: src/login/org.freedesktop.login1.policy:247
#, fuzzy
#| msgid ""
#| "Authentication is required to hibernate the system while an application "
#| "is inhibiting this."
msgid ""
"Authentication is required to halt the system while an application is "
"inhibiting this."
msgstr "在其它应用程序阻止休眠时进行休眠需要认证。"
msgstr "当应用程序阻止时停止系统需要认证。"
#: src/login/org.freedesktop.login1.policy:257
msgid "Suspend the system"
@ -515,10 +501,8 @@ msgid "Authentication is required to set the reboot \"reason\" in the kernel."
msgstr "设置系统时区需要认证。"
#: src/login/org.freedesktop.login1.policy:352
#, fuzzy
#| msgid "Allow indication to the firmware to boot to setup interface"
msgid "Indicate to the firmware to boot to setup interface"
msgstr "允许向固件发出指示以启动至设置界面"
msgstr "指示固件以启动至设置界面"
#: src/login/org.freedesktop.login1.policy:353
msgid ""
@ -653,7 +637,7 @@ msgstr "设置系统时间需要认证。"
#: src/network/org.freedesktop.network1.policy:33
#: src/resolve/org.freedesktop.resolve1.policy:44
msgid "Set DNS servers"
msgstr ""
msgstr "设置 DNS 服务器"
#: src/network/org.freedesktop.network1.policy:34
#: src/resolve/org.freedesktop.resolve1.policy:45

View File

@ -385,11 +385,9 @@ int fd_get_path(int fd, char **ret) {
/* ENOENT can mean two things: that the fd does not exist or that /proc is not mounted. Let's make
* things debuggable and distinguish the two. */
if (access("/proc/self/fd/", F_OK) < 0)
/* /proc is not available or not set up properly, we're most likely in some chroot
* environment. */
return errno == ENOENT ? -EOPNOTSUPP : -errno;
if (proc_mounted() == 0)
return -ENOSYS; /* /proc is not available or not set up properly, we're most likely in some chroot
* environment. */
return -EBADF; /* The directory exists, hence it's the fd that doesn't. */
}
@ -731,8 +729,7 @@ int fd_duplicate_data_fd(int fd) {
if (f != 0)
return -errno;
safe_close(copy_fd);
copy_fd = TAKE_FD(tmp_fd);
CLOSE_AND_REPLACE(copy_fd, tmp_fd);
remains = mfree(remains);
remains_size = 0;
@ -865,8 +862,7 @@ int rearrange_stdio(int original_input_fd, int original_output_fd, int original_
goto finish;
}
safe_close(null_fd);
null_fd = copy;
CLOSE_AND_REPLACE(null_fd, copy);
}
}

View File

@ -93,6 +93,16 @@ static inline int make_null_stdio(void) {
_fd_; \
})
/* Like free_and_replace(), but for file descriptors */
#define CLOSE_AND_REPLACE(a, b) \
({ \
int *_fdp_ = &(a); \
safe_close(*_fdp_); \
*_fdp_ = TAKE_FD(b); \
0; \
})
int fd_reopen(int fd, int flags);
int read_nr_open(void);

View File

@ -280,52 +280,6 @@ int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid) {
return do_chown || do_chmod;
}
int chmod_and_chown_unsafe(const char *path, mode_t mode, uid_t uid, gid_t gid) {
bool do_chown, do_chmod;
struct stat st;
assert(path);
/* Change ownership and access mode of the specified path, see description of fchmod_and_chown().
* Should only be used on trusted paths. */
if (lstat(path, &st) < 0)
return -errno;
do_chown =
(uid != UID_INVALID && st.st_uid != uid) ||
(gid != GID_INVALID && st.st_gid != gid);
do_chmod =
!S_ISLNK(st.st_mode) && /* chmod is not defined on symlinks */
((mode != MODE_INVALID && ((st.st_mode ^ mode) & 07777) != 0) ||
do_chown); /* If we change ownership, make sure we reset the mode afterwards, since chown()
* modifies the access mode too */
if (mode == MODE_INVALID)
mode = st.st_mode; /* If we only shall do a chown(), save original mode, since chown() might break it. */
else if ((mode & S_IFMT) != 0 && ((mode ^ st.st_mode) & S_IFMT) != 0)
return -EINVAL; /* insist on the right file type if it was specified */
if (do_chown && do_chmod) {
mode_t minimal = st.st_mode & mode; /* the subset of the old and the new mask */
if (((minimal ^ st.st_mode) & 07777) != 0)
if (chmod(path, minimal & 07777) < 0)
return -errno;
}
if (do_chown)
if (lchown(path, uid, gid) < 0)
return -errno;
if (do_chmod)
if (chmod(path, mode & 07777) < 0)
return -errno;
return do_chown || do_chmod;
}
int fchmod_umask(int fd, mode_t m) {
mode_t u;
int r;
@ -765,7 +719,7 @@ static int log_unsafe_transition(int a, int b, const char *path, unsigned flags)
return log_warning_errno(SYNTHETIC_ERRNO(ENOLINK),
"Detected unsafe path transition %s %s %s during canonicalization of %s.",
n1, special_glyph(SPECIAL_GLYPH_ARROW), n2, path);
strna(n1), special_glyph(SPECIAL_GLYPH_ARROW), strna(n2), path);
}
static int log_autofs_mount_point(int fd, const char *path, unsigned flags) {
@ -778,7 +732,7 @@ static int log_autofs_mount_point(int fd, const char *path, unsigned flags) {
return log_warning_errno(SYNTHETIC_ERRNO(EREMOTE),
"Detected autofs mount point %s during canonicalization of %s.",
n1, path);
strna(n1), path);
}
int chase_symlinks(const char *path, const char *original_root, unsigned flags, char **ret_path, int *ret_fd) {
@ -1298,16 +1252,25 @@ int chase_symlinks_and_stat(
int access_fd(int fd, int mode) {
char p[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1];
int r;
/* Like access() but operates on an already open fd */
xsprintf(p, "/proc/self/fd/%i", fd);
r = access(p, mode);
if (r < 0)
return -errno;
if (access(p, mode) < 0) {
if (errno != ENOENT)
return -errno;
return r;
/* ENOENT can mean two things: that the fd does not exist or that /proc is not mounted. Let's
* make things debuggable and distinguish the two. */
if (proc_mounted() == 0)
return -ENOSYS; /* /proc is not available or not set up properly, we're most likely in some chroot
* environment. */
return -EBADF; /* The directory exists, hence it's the fd that doesn't. */
}
return 0;
}
void unlink_tempfilep(char (*p)[]) {
@ -1441,9 +1404,9 @@ int fsync_directory_of_file(int fd) {
if (r < 0) {
log_debug_errno(r, "Failed to query /proc/self/fd/%d%s: %m",
fd,
r == -EOPNOTSUPP ? ", ignoring" : "");
r == -ENOSYS ? ", ignoring" : "");
if (r == -EOPNOTSUPP)
if (r == -ENOSYS)
/* If /proc is not available, we're most likely running in some
* chroot environment, and syncing the directory is not very
* important in that case. Let's just silently do nothing. */

View File

@ -34,7 +34,6 @@ int readlink_and_make_absolute(const char *p, char **r);
int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid);
int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid);
int chmod_and_chown_unsafe(const char *path, mode_t mode, uid_t uid, gid_t gid);
int fchmod_umask(int fd, mode_t mode);
int fchmod_opath(int fd, mode_t m);

View File

@ -28,14 +28,6 @@
#include "time-util.h"
#include "utf8.h"
bool path_is_absolute(const char *p) {
return p[0] == '/';
}
bool is_path(const char *p) {
return !!strchr(p, '/');
}
int path_split_and_make_absolute(const char *p, char ***ret) {
char **l;
int r;
@ -593,9 +585,9 @@ char* path_join_internal(const char *first, ...) {
return joined;
}
int find_binary(const char *name, char **ret) {
int find_executable_full(const char *name, bool use_path_envvar, char **ret) {
int last_error, r;
const char *p;
const char *p = NULL;
assert(name);
@ -612,11 +604,10 @@ int find_binary(const char *name, char **ret) {
return 0;
}
/**
* Plain getenv, not secure_getenv, because we want
* to actually allow the user to pick the binary.
*/
p = getenv("PATH");
if (use_path_envvar)
/* Plain getenv, not secure_getenv, because we want to actually allow the user to pick the
* binary. */
p = getenv("PATH");
if (!p)
p = DEFAULT_PATH;
@ -649,9 +640,7 @@ int find_binary(const char *name, char **ret) {
if (access(with_dash, X_OK) >= 0)
continue;
/**
* We can't just `continue` inverting this case, since we need to update last_error.
*/
/* We can't just `continue` inverting this case, since we need to update last_error. */
if (errno == ENOTDIR) {
/* Found it! */
if (ret)
@ -704,18 +693,17 @@ bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool upd
return changed;
}
static int binary_is_good(const char *binary) {
static int executable_is_good(const char *executable) {
_cleanup_free_ char *p = NULL, *d = NULL;
int r;
r = find_binary(binary, &p);
r = find_executable(executable, &p);
if (r == -ENOENT)
return 0;
if (r < 0)
return r;
/* An fsck that is linked to /bin/true is a non-existent
* fsck */
/* An fsck that is linked to /bin/true is a non-existent fsck */
r = readlink_malloc(p, &d);
if (r == -EINVAL) /* not a symlink */
@ -738,7 +726,7 @@ int fsck_exists(const char *fstype) {
return -EINVAL;
checker = strjoina("fsck.", fstype);
return binary_is_good(checker);
return executable_is_good(checker);
}
int parse_path_argument_and_warn(const char *path, bool suppress_root, char **arg) {

View File

@ -42,9 +42,17 @@
# define DEFAULT_USER_PATH DEFAULT_PATH
#endif
bool is_path(const char *p) _pure_;
static inline bool is_path(const char *p) {
assert(p);
return strchr(p, '/');
}
static inline bool path_is_absolute(const char *p) {
assert(p);
return p[0] == '/';
}
int path_split_and_make_absolute(const char *p, char ***ret);
bool path_is_absolute(const char *p) _pure_;
char* path_make_absolute(const char *p, const char *prefix);
int safe_getcwd(char **ret);
int path_make_absolute_cwd(const char *p, char **ret);
@ -80,7 +88,10 @@ int path_strv_make_absolute_cwd(char **l);
char** path_strv_resolve(char **l, const char *root);
char** path_strv_resolve_uniq(char **l, const char *root);
int find_binary(const char *name, char **filename);
int find_executable_full(const char *name, bool use_path_envvar, char **ret);
static inline int find_executable(const char *name, char **ret) {
return find_executable_full(name, true, ret);
}
bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool update);

View File

@ -21,6 +21,7 @@
#endif
#include "alloc-util.h"
#include "env-util.h"
#include "errno-util.h"
#include "fd-util.h"
#include "fileio.h"
@ -116,6 +117,15 @@ int rdrand(unsigned long *ret) {
#endif
have_rdrand = !!(ecx & bit_RDRND);
if (have_rdrand > 0) {
/* Allow disabling use of RDRAND with SYSTEMD_RDRAND=0
If it is unset getenv_bool_secure will return a negative value. */
if (getenv_bool_secure("SYSTEMD_RDRAND") == 0) {
have_rdrand = false;
return -EOPNOTSUPP;
}
}
}
if (have_rdrand == 0)

View File

@ -1354,8 +1354,10 @@ int bus_set_transient_exec_command(
if (r < 0)
return r;
if (!path_is_absolute(path))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not absolute.", path);
if (!path_is_absolute(path) && !filename_is_valid(path))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
"\"%s\" is neither a valid executable name nor an absolute path",
path);
r = sd_bus_message_read_strv(message, &argv);
if (r < 0)

View File

@ -2881,12 +2881,11 @@ static int setup_credentials(
#if ENABLE_SMACK
static int setup_smack(
const ExecContext *context,
const ExecCommand *command) {
const char *executable) {
int r;
assert(context);
assert(command);
assert(executable);
if (context->smack_process_label) {
r = mac_smack_apply_pid(0, context->smack_process_label);
@ -2897,7 +2896,7 @@ static int setup_smack(
else {
_cleanup_free_ char *exec_label = NULL;
r = mac_smack_read(command->path, SMACK_ATTR_EXEC, &exec_label);
r = mac_smack_read(executable, SMACK_ATTR_EXEC, &exec_label);
if (r < 0 && !IN_SET(r, -ENODATA, -EOPNOTSUPP))
return r;
@ -3092,7 +3091,7 @@ static bool insist_on_sandboxing(
static int apply_mount_namespace(
const Unit *u,
const ExecCommand *command,
ExecCommandFlags command_flags,
const ExecContext *context,
const ExecParameters *params,
const ExecRuntime *runtime,
@ -3121,7 +3120,7 @@ static int apply_mount_namespace(
if (r < 0)
return r;
needs_sandboxing = (params->flags & EXEC_APPLY_SANDBOXING) && !(command->flags & EXEC_COMMAND_FULLY_PRIVILEGED);
needs_sandboxing = (params->flags & EXEC_APPLY_SANDBOXING) && !(command_flags & EXEC_COMMAND_FULLY_PRIVILEGED);
if (needs_sandboxing) {
/* The runtime struct only contains the parent of the private /tmp,
* which is non-accessible to world users. Inside of it there's a /tmp
@ -3700,11 +3699,11 @@ static int exec_child(
return log_unit_error_errno(unit, r, "Failed to close unwanted file descriptors: %m");
}
if (!context->same_pgrp)
if (setsid() < 0) {
*exit_status = EXIT_SETSID;
return log_unit_error_errno(unit, errno, "Failed to create new process session: %m");
}
if (!context->same_pgrp &&
setsid() < 0) {
*exit_status = EXIT_SETSID;
return log_unit_error_errno(unit, errno, "Failed to create new process session: %m");
}
exec_context_tty_reset(context, params);
@ -3725,8 +3724,8 @@ static int exec_child(
return 0;
}
*exit_status = EXIT_CONFIRM;
log_unit_error(unit, "Execution cancelled by the user");
return -ECANCELED;
return log_unit_error_errno(unit, SYNTHETIC_ERRNO(ECANCELED),
"Execution cancelled by the user");
}
}
@ -4085,47 +4084,33 @@ static int exec_child(
}
}
if (needs_setuid) {
if (needs_setuid && context->pam_name && username) {
/* Let's call into PAM after we set up our own idea of resource limits to that pam_limits
* wins here. (See above.) */
if (context->pam_name && username) {
r = setup_pam(context->pam_name, username, uid, gid, context->tty_path, &accum_env, fds, n_fds);
if (r < 0) {
*exit_status = EXIT_PAM;
return log_unit_error_errno(unit, r, "Failed to set up PAM session: %m");
}
r = setup_pam(context->pam_name, username, uid, gid, context->tty_path, &accum_env, fds, n_fds);
if (r < 0) {
*exit_status = EXIT_PAM;
return log_unit_error_errno(unit, r, "Failed to set up PAM session: %m");
}
ngids_after_pam = getgroups_alloc(&gids_after_pam);
if (ngids_after_pam < 0) {
*exit_status = EXIT_MEMORY;
return log_unit_error_errno(unit, ngids_after_pam, "Failed to obtain groups after setting up PAM: %m");
}
ngids_after_pam = getgroups_alloc(&gids_after_pam);
if (ngids_after_pam < 0) {
*exit_status = EXIT_MEMORY;
return log_unit_error_errno(unit, ngids_after_pam, "Failed to obtain groups after setting up PAM: %m");
}
}
if (needs_sandboxing) {
#if HAVE_SELINUX
if (use_selinux && params->selinux_context_net && socket_fd >= 0) {
r = mac_selinux_get_child_mls_label(socket_fd, command->path, context->selinux_context, &mac_selinux_context_net);
if (r < 0) {
*exit_status = EXIT_SELINUX_CONTEXT;
return log_unit_error_errno(unit, r, "Failed to determine SELinux context: %m");
}
}
#endif
if (needs_sandboxing && context->private_users && !have_effective_cap(CAP_SYS_ADMIN)) {
/* If we're unprivileged, set up the user namespace first to enable use of the other namespaces.
* Users with CAP_SYS_ADMIN can set up user namespaces last because they will be able to
* set up the all of the other namespaces (i.e. network, mount, UTS) without a user namespace. */
if (context->private_users && !have_effective_cap(CAP_SYS_ADMIN)) {
userns_set_up = true;
r = setup_private_users(saved_uid, saved_gid, uid, gid);
if (r < 0) {
*exit_status = EXIT_USER;
return log_unit_error_errno(unit, r, "Failed to set up user namespacing for unprivileged user: %m");
}
userns_set_up = true;
r = setup_private_users(saved_uid, saved_gid, uid, gid);
if (r < 0) {
*exit_status = EXIT_USER;
return log_unit_error_errno(unit, r, "Failed to set up user namespacing for unprivileged user: %m");
}
}
@ -4152,7 +4137,7 @@ static int exec_child(
if (needs_mount_namespace) {
_cleanup_free_ char *error_path = NULL;
r = apply_mount_namespace(unit, command, context, params, runtime, &error_path);
r = apply_mount_namespace(unit, command->flags, context, params, runtime, &error_path);
if (r < 0) {
*exit_status = EXIT_NAMESPACE;
return log_unit_error_errno(unit, r, "Failed to set up mount namespacing%s%s: %m",
@ -4206,6 +4191,43 @@ static int exec_child(
}
}
/* Now that the mount namespace has been set up and privileges adjusted, let's look for the thing we
* shall execute. */
_cleanup_free_ char *executable = NULL;
r = find_executable_full(command->path, false, &executable);
if (r < 0) {
if (r != -ENOMEM && (command->flags & EXEC_COMMAND_IGNORE_FAILURE)) {
log_struct_errno(LOG_INFO, r,
"MESSAGE_ID=" SD_MESSAGE_SPAWN_FAILED_STR,
LOG_UNIT_ID(unit),
LOG_UNIT_INVOCATION_ID(unit),
LOG_UNIT_MESSAGE(unit, "Executable %s missing, skipping: %m",
command->path),
"EXECUTABLE=%s", command->path);
return 0;
}
*exit_status = EXIT_EXEC;
return log_struct_errno(LOG_INFO, r,
"MESSAGE_ID=" SD_MESSAGE_SPAWN_FAILED_STR,
LOG_UNIT_ID(unit),
LOG_UNIT_INVOCATION_ID(unit),
LOG_UNIT_MESSAGE(unit, "Failed to locate executable %s: %m",
command->path),
"EXECUTABLE=%s", command->path);
}
#if HAVE_SELINUX
if (needs_sandboxing && use_selinux && params->selinux_context_net && socket_fd >= 0) {
r = mac_selinux_get_child_mls_label(socket_fd, executable, context->selinux_context, &mac_selinux_context_net);
if (r < 0) {
*exit_status = EXIT_SELINUX_CONTEXT;
return log_unit_error_errno(unit, r, "Failed to determine SELinux context: %m");
}
}
#endif
/* We repeat the fd closing here, to make sure that nothing is leaked from the PAM modules. Note that we are
* more aggressive this time since socket_fd and the netns fds we don't need anymore. We do keep the exec_fd
* however if we have it as we want to keep it open until the final execve(). */
@ -4225,8 +4247,7 @@ static int exec_child(
return log_unit_error_errno(unit, errno, "Couldn't move exec fd up: %m");
}
safe_close(exec_fd);
exec_fd = moved_fd;
CLOSE_AND_REPLACE(exec_fd, moved_fd);
} else {
/* This fd should be FD_CLOEXEC already, but let's make sure. */
r = fd_cloexec(exec_fd, true);
@ -4279,7 +4300,7 @@ static int exec_child(
/* LSM Smack needs the capability CAP_MAC_ADMIN to change the current execution security context of the
* process. This is the latest place before dropping capabilities. Other MAC context are set later. */
if (use_smack) {
r = setup_smack(context, command);
r = setup_smack(context, executable);
if (r < 0) {
*exit_status = EXIT_SMACK_PROCESS_LABEL;
return log_unit_error_errno(unit, r, "Failed to set SMACK process label: %m");
@ -4531,7 +4552,7 @@ static int exec_child(
line = exec_command_line(final_argv);
if (line)
log_struct(LOG_DEBUG,
"EXECUTABLE=%s", command->path,
"EXECUTABLE=%s", executable,
LOG_UNIT_MESSAGE(unit, "Executing: %s", line),
LOG_UNIT_ID(unit),
LOG_UNIT_INVOCATION_ID(unit));
@ -4549,7 +4570,7 @@ static int exec_child(
}
}
execve(command->path, final_argv, accum_env);
execve(executable, final_argv, accum_env);
r = -errno;
if (exec_fd >= 0) {
@ -4564,19 +4585,8 @@ static int exec_child(
}
}
if (r == -ENOENT && (command->flags & EXEC_COMMAND_IGNORE_FAILURE)) {
log_struct_errno(LOG_INFO, r,
"MESSAGE_ID=" SD_MESSAGE_SPAWN_FAILED_STR,
LOG_UNIT_ID(unit),
LOG_UNIT_INVOCATION_ID(unit),
LOG_UNIT_MESSAGE(unit, "Executable %s missing, skipping: %m",
command->path),
"EXECUTABLE=%s", command->path);
return 0;
}
*exit_status = EXIT_EXEC;
return log_unit_error_errno(unit, r, "Failed to execute command: %m");
return log_unit_error_errno(unit, r, "Failed to execute %s: %m", executable);
}
static int exec_context_load_environment(const Unit *unit, const ExecContext *c, char ***l);
@ -4638,13 +4648,16 @@ int exec_spawn(Unit *unit,
if (!line)
return log_oom();
/* fork with up-to-date SELinux label database, so the child inherits the up-to-date db
and, until the next SELinux policy changes, we safe further reloads in future children */
/* Fork with up-to-date SELinux label database, so the child inherits the up-to-date db
and, until the next SELinux policy changes, we save further reloads in future children. */
mac_selinux_maybe_reload();
log_struct(LOG_DEBUG,
LOG_UNIT_MESSAGE(unit, "About to execute: %s", line),
"EXECUTABLE=%s", command->path,
LOG_UNIT_MESSAGE(unit, "About to execute %s", line),
"EXECUTABLE=%s", command->path, /* We won't know the real executable path until we create
the mount namespace in the child, but we want to log
from the parent, so we need to use the (possibly
inaccurate) path here. */
LOG_UNIT_ID(unit),
LOG_UNIT_INVOCATION_ID(unit));

View File

@ -721,6 +721,12 @@ int config_parse_exec(
if (r <= 0)
return 0;
/* A lone ";" is a separator. Let's make sure we don't treat it as an executable name. */
if (streq(firstword, ";")) {
semicolon = true;
continue;
}
f = firstword;
for (;;) {
/* We accept an absolute path as first argument. If it's prefixed with - and the path doesn't
@ -783,38 +789,11 @@ int config_parse_exec(
return ignore ? 0 : -ENOEXEC;
}
if (!path_is_absolute(path)) {
const char *prefix;
bool found = false;
if (!filename_is_valid(path)) {
log_syntax(unit, ignore ? LOG_WARNING : LOG_ERR, filename, line, 0,
"Neither a valid executable name nor an absolute path%s: %s",
ignore ? ", ignoring" : "", path);
return ignore ? 0 : -ENOEXEC;
}
/* Resolve a single-component name to a full path */
NULSTR_FOREACH(prefix, DEFAULT_PATH_NULSTR) {
_cleanup_free_ char *fullpath = NULL;
fullpath = path_join(prefix, path);
if (!fullpath)
return log_oom();
if (access(fullpath, F_OK) >= 0) {
free_and_replace(path, fullpath);
found = true;
break;
}
}
if (!found) {
log_syntax(unit, ignore ? LOG_WARNING : LOG_ERR, filename, line, 0,
"Executable \"%s\" not found in path \"%s\"%s",
path, DEFAULT_PATH, ignore ? ", ignoring" : "");
return ignore ? 0 : -ENOEXEC;
}
if (!path_is_absolute(path) && !filename_is_valid(path)) {
log_syntax(unit, ignore ? LOG_WARNING : LOG_ERR, filename, line, 0,
"Neither a valid executable name nor an absolute path%s: %s",
ignore ? ", ignoring" : "", path);
return ignore ? 0 : -ENOEXEC;
}
if (!separate_argv0) {

View File

@ -1973,10 +1973,9 @@ int manager_load_unit_prepare(
assert(m);
assert(_ret);
/* This will prepare the unit for loading, but not actually
* load anything from disk. */
/* This will prepare the unit for loading, but not actually load anything from disk. */
if (path && !is_path(path))
if (path && !path_is_absolute(path))
return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not absolute.", path);
if (!name) {

View File

@ -185,9 +185,7 @@ static int raw_import_maybe_convert_qcow2(RawImport *i) {
(void) unlink(i->temp_path);
free_and_replace(i->temp_path, t);
safe_close(i->output_fd);
i->output_fd = TAKE_FD(converted_fd);
CLOSE_AND_REPLACE(i->output_fd, converted_fd);
return 1;
}

View File

@ -253,9 +253,7 @@ static int raw_pull_maybe_convert_qcow2(RawPull *i) {
(void) unlink(i->temp_path);
free_and_replace(i->temp_path, t);
safe_close(i->raw_job->disk_fd);
i->raw_job->disk_fd = TAKE_FD(converted_fd);
CLOSE_AND_REPLACE(i->raw_job->disk_fd, converted_fd);
return 1;
}

View File

@ -176,7 +176,7 @@ _unused_ static void test_compress_stream(const char *compression,
_cleanup_free_ char *cmd = NULL, *cmd2 = NULL;
struct stat st = {};
r = find_binary(cat, NULL);
r = find_executable(cat, NULL);
if (r < 0) {
log_error_errno(r, "Skipping %s, could not find %s binary: %m", __func__, cat);
return;

View File

@ -471,8 +471,7 @@ int sd_ipv4acd_start(sd_ipv4acd *acd, bool reset_conflicts) {
if (r < 0)
return r;
safe_close(acd->fd);
acd->fd = r;
CLOSE_AND_REPLACE(acd->fd, r);
acd->defend_window = 0;
if (reset_conflicts)

View File

@ -195,8 +195,7 @@ static int session_device_start(SessionDevice *sd) {
/* For evdev devices, the file descriptor might be left uninitialized. This might happen while resuming
* into a session and logind has been restarted right before. */
safe_close(sd->fd);
sd->fd = r;
CLOSE_AND_REPLACE(sd->fd, r);
break;
case DEVICE_TYPE_UNKNOWN:

View File

@ -1720,12 +1720,16 @@ static int run(int argc, char* argv[]) {
if (r <= 0)
return r;
if (!strv_isempty(arg_cmdline) && arg_transport == BUS_TRANSPORT_LOCAL) {
if (!strv_isempty(arg_cmdline) &&
arg_transport == BUS_TRANSPORT_LOCAL &&
!strv_find_startswith(arg_property, "RootDirectory=") &&
!strv_find_startswith(arg_property, "RootImage=")) {
/* Patch in an absolute path to fail early for user convenience, but only when we can do it
* (i.e. we will be running from the same file system). This also uses the user's $PATH,
* while we use a fixed search path in the manager. */
_cleanup_free_ char *command = NULL;
/* Patch in an absolute path */
r = find_binary(arg_cmdline[0], &command);
r = find_executable(arg_cmdline[0], &command);
if (r < 0)
return log_error_errno(r, "Failed to find executable %s: %m", arg_cmdline[0]);

View File

@ -20,7 +20,7 @@ int mkfs_exists(const char *fstype) {
if (!filename_is_valid(mkfs)) /* refuse file system types with slashes and similar */
return -EINVAL;
r = find_binary(mkfs, NULL);
r = find_executable(mkfs, NULL);
if (r == -ENOENT)
return false;
if (r < 0)
@ -44,7 +44,7 @@ int make_filesystem(
assert(label);
if (streq(fstype, "swap")) {
r = find_binary("mkswap", &mkfs);
r = find_executable("mkswap", &mkfs);
if (r == -ENOENT)
return log_error_errno(SYNTHETIC_ERRNO(EPROTONOSUPPORT), "mkswap binary not available.");
if (r < 0)

View File

@ -201,14 +201,16 @@ static int load_group_database(void) {
}
static int make_backup(const char *target, const char *x) {
_cleanup_close_ int src = -1;
_cleanup_(unlink_and_freep) char *dst_tmp = NULL;
_cleanup_fclose_ FILE *dst = NULL;
_cleanup_free_ char *dst_tmp = NULL;
char *backup;
struct timespec ts[2];
_cleanup_close_ int src = -1;
const char *backup;
struct stat st;
int r;
assert(target);
assert(x);
src = open(x, O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (src < 0) {
if (errno == ENOENT) /* No backup necessary... */
@ -220,43 +222,38 @@ static int make_backup(const char *target, const char *x) {
if (fstat(src, &st) < 0)
return -errno;
r = fopen_temporary_label(target, x, &dst, &dst_tmp);
r = fopen_temporary_label(
target, /* The path for which to the lookup the label */
x, /* Where we want the file actually to end up */
&dst,
&dst_tmp /* The temporary file we write to */);
if (r < 0)
return r;
r = copy_bytes(src, fileno(dst), (uint64_t) -1, COPY_REFLINK);
if (r < 0)
goto fail;
/* Don't fail on chmod() or chown(). If it stays owned by us
* and/or unreadable by others, then it isn't too bad... */
return r;
backup = strjoina(x, "-");
/* Copy over the access mask */
r = chmod_and_chown_unsafe(dst_tmp, st.st_mode & 07777, st.st_uid, st.st_gid);
/* Copy over the access mask. Don't fail on chmod() or chown(). If it stays owned by us and/or
* unreadable by others, then it isn't too bad... */
r = fchmod_and_chown(fileno(dst), st.st_mode & 07777, st.st_uid, st.st_gid);
if (r < 0)
log_warning_errno(r, "Failed to change access mode or ownership of %s: %m", backup);
ts[0] = st.st_atim;
ts[1] = st.st_mtim;
if (futimens(fileno(dst), ts) < 0)
if (futimens(fileno(dst), (const struct timespec[2]) { st.st_atim, st.st_mtim }) < 0)
log_warning_errno(errno, "Failed to fix access and modification time of %s: %m", backup);
r = fflush_sync_and_check(dst);
r = fsync_full(fileno(dst));
if (r < 0)
goto fail;
return r;
if (rename(dst_tmp, backup) < 0) {
r = -errno;
goto fail;
}
if (rename(dst_tmp, backup) < 0)
return errno;
dst_tmp = mfree(dst_tmp); /* disable the unlink_and_freep() hook now that the file has been renamed*/
return 0;
fail:
(void) unlink(dst_tmp);
return r;
}
static int putgrent_with_members(const struct group *gr, FILE *group) {

View File

@ -71,7 +71,8 @@ static void wait_for_service_finish(Manager *m, Unit *unit) {
}
}
static void check_main_result(const char *func, Manager *m, Unit *unit, int status_expected, int code_expected) {
static void check_main_result(const char *file, unsigned line, const char *func,
Manager *m, Unit *unit, int status_expected, int code_expected) {
Service *service = NULL;
assert_se(m);
@ -83,21 +84,23 @@ static void check_main_result(const char *func, Manager *m, Unit *unit, int stat
exec_status_dump(&service->main_exec_status, stdout, "\t");
if (cld_dumped_to_killed(service->main_exec_status.code) != cld_dumped_to_killed(code_expected)) {
log_error("%s: %s: exit code %d, expected %d",
func, unit->id,
log_error("%s:%u:%s %s: exit code %d, expected %d",
file, line, func,
unit->id,
service->main_exec_status.code, code_expected);
abort();
}
if (service->main_exec_status.status != status_expected) {
log_error("%s: %s: exit status %d, expected %d",
func, unit->id,
log_error("%s:%u:%s: %s: exit status %d, expected %d",
file, line, func, unit->id,
service->main_exec_status.status, status_expected);
abort();
}
}
static void check_service_result(const char *func, Manager *m, Unit *unit, ServiceResult result_expected) {
static void check_service_result(const char *file, unsigned line, const char *func,
Manager *m, Unit *unit, ServiceResult result_expected) {
Service *service = NULL;
assert_se(m);
@ -108,8 +111,9 @@ static void check_service_result(const char *func, Manager *m, Unit *unit, Servi
service = SERVICE(unit);
if (service->result != result_expected) {
log_error("%s: %s: service end result %s, expected %s",
func, unit->id,
log_error("%s:%u:%s: %s: service end result %s, expected %s",
file, line, func,
unit->id,
service_result_to_string(service->result),
service_result_to_string(result_expected));
abort();
@ -198,31 +202,37 @@ static bool is_inaccessible_available(void) {
return true;
}
static void test(const char *func, Manager *m, const char *unit_name, int status_expected, int code_expected) {
static void _test(const char *file, unsigned line, const char *func,
Manager *m, const char *unit_name, int status_expected, int code_expected) {
Unit *unit;
assert_se(unit_name);
assert_se(manager_load_startable_unit_or_warn(m, unit_name, NULL, &unit) >= 0);
assert_se(unit_start(unit) >= 0);
check_main_result(func, m, unit, status_expected, code_expected);
check_main_result(file, line, func, m, unit, status_expected, code_expected);
}
#define test(m, unit_name, status_expected, code_expected) \
_test(PROJECT_FILE, __LINE__, __func__, m, unit_name, status_expected, code_expected)
static void test_service(const char *func, Manager *m, const char *unit_name, ServiceResult result_expected) {
static void _test_service(const char *file, unsigned line, const char *func,
Manager *m, const char *unit_name, ServiceResult result_expected) {
Unit *unit;
assert_se(unit_name);
assert_se(manager_load_startable_unit_or_warn(m, unit_name, NULL, &unit) >= 0);
assert_se(unit_start(unit) >= 0);
check_service_result(func, m, unit, result_expected);
check_service_result(file, line, func, m, unit, result_expected);
}
#define test_service(m, unit_name, result_expected) \
_test_service(PROJECT_FILE, __LINE__, __func__, m, unit_name, result_expected)
static void test_exec_bindpaths(Manager *m) {
assert_se(mkdir_p("/tmp/test-exec-bindpaths", 0755) >= 0);
assert_se(mkdir_p("/tmp/test-exec-bindreadonlypaths", 0755) >= 0);
test(__func__, m, "exec-bindpaths.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(m, "exec-bindpaths.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
(void) rm_rf("/tmp/test-exec-bindpaths", REMOVE_ROOT|REMOVE_PHYSICAL);
(void) rm_rf("/tmp/test-exec-bindreadonlypaths", REMOVE_ROOT|REMOVE_PHYSICAL);
@ -239,8 +249,8 @@ static void test_exec_cpuaffinity(Manager *m) {
return;
}
test(__func__, m, "exec-cpuaffinity1.service", 0, CLD_EXITED);
test(__func__, m, "exec-cpuaffinity2.service", 0, CLD_EXITED);
test(m, "exec-cpuaffinity1.service", 0, CLD_EXITED);
test(m, "exec-cpuaffinity2.service", 0, CLD_EXITED);
if (!CPU_ISSET_S(1, c.allocated, c.set) ||
!CPU_ISSET_S(2, c.allocated, c.set)) {
@ -248,53 +258,53 @@ static void test_exec_cpuaffinity(Manager *m) {
return;
}
test(__func__, m, "exec-cpuaffinity3.service", 0, CLD_EXITED);
test(m, "exec-cpuaffinity3.service", 0, CLD_EXITED);
}
static void test_exec_workingdirectory(Manager *m) {
assert_se(mkdir_p("/tmp/test-exec_workingdirectory", 0755) >= 0);
test(__func__, m, "exec-workingdirectory.service", 0, CLD_EXITED);
test(__func__, m, "exec-workingdirectory-trailing-dot.service", 0, CLD_EXITED);
test(m, "exec-workingdirectory.service", 0, CLD_EXITED);
test(m, "exec-workingdirectory-trailing-dot.service", 0, CLD_EXITED);
(void) rm_rf("/tmp/test-exec_workingdirectory", REMOVE_ROOT|REMOVE_PHYSICAL);
}
static void test_exec_personality(Manager *m) {
#if defined(__x86_64__)
test(__func__, m, "exec-personality-x86-64.service", 0, CLD_EXITED);
test(m, "exec-personality-x86-64.service", 0, CLD_EXITED);
#elif defined(__s390__)
test(__func__, m, "exec-personality-s390.service", 0, CLD_EXITED);
test(m, "exec-personality-s390.service", 0, CLD_EXITED);
#elif defined(__powerpc64__)
# if __BYTE_ORDER == __BIG_ENDIAN
test(__func__, m, "exec-personality-ppc64.service", 0, CLD_EXITED);
test(m, "exec-personality-ppc64.service", 0, CLD_EXITED);
# else
test(__func__, m, "exec-personality-ppc64le.service", 0, CLD_EXITED);
test(m, "exec-personality-ppc64le.service", 0, CLD_EXITED);
# endif
#elif defined(__aarch64__)
test(__func__, m, "exec-personality-aarch64.service", 0, CLD_EXITED);
test(m, "exec-personality-aarch64.service", 0, CLD_EXITED);
#elif defined(__i386__)
test(__func__, m, "exec-personality-x86.service", 0, CLD_EXITED);
test(m, "exec-personality-x86.service", 0, CLD_EXITED);
#else
log_notice("Unknown personality, skipping %s", __func__);
#endif
}
static void test_exec_ignoresigpipe(Manager *m) {
test(__func__, m, "exec-ignoresigpipe-yes.service", 0, CLD_EXITED);
test(__func__, m, "exec-ignoresigpipe-no.service", SIGPIPE, CLD_KILLED);
test(m, "exec-ignoresigpipe-yes.service", 0, CLD_EXITED);
test(m, "exec-ignoresigpipe-no.service", SIGPIPE, CLD_KILLED);
}
static void test_exec_privatetmp(Manager *m) {
assert_se(touch("/tmp/test-exec_privatetmp") >= 0);
test(__func__, m, "exec-privatetmp-yes.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
test(__func__, m, "exec-privatetmp-no.service", 0, CLD_EXITED);
test(__func__, m, "exec-privatetmp-disabled-by-prefix.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
test(m, "exec-privatetmp-yes.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
test(m, "exec-privatetmp-no.service", 0, CLD_EXITED);
test(m, "exec-privatetmp-disabled-by-prefix.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
unlink("/tmp/test-exec_privatetmp");
}
@ -311,23 +321,23 @@ static void test_exec_privatedevices(Manager *m) {
return;
}
test(__func__, m, "exec-privatedevices-yes.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
test(__func__, m, "exec-privatedevices-no.service", 0, CLD_EXITED);
test(__func__, m, "exec-privatedevices-disabled-by-prefix.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
test(__func__, m, "exec-privatedevices-yes-with-group.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
test(m, "exec-privatedevices-yes.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
test(m, "exec-privatedevices-no.service", 0, CLD_EXITED);
test(m, "exec-privatedevices-disabled-by-prefix.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
test(m, "exec-privatedevices-yes-with-group.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
/* We use capsh to test if the capabilities are
* properly set, so be sure that it exists */
r = find_binary("capsh", NULL);
r = find_executable("capsh", NULL);
if (r < 0) {
log_notice_errno(r, "Could not find capsh binary, skipping remaining tests in %s: %m", __func__);
return;
}
test(__func__, m, "exec-privatedevices-yes-capability-mknod.service", 0, CLD_EXITED);
test(__func__, m, "exec-privatedevices-no-capability-mknod.service", 0, CLD_EXITED);
test(__func__, m, "exec-privatedevices-yes-capability-sys-rawio.service", 0, CLD_EXITED);
test(__func__, m, "exec-privatedevices-no-capability-sys-rawio.service", 0, CLD_EXITED);
test(m, "exec-privatedevices-yes-capability-mknod.service", 0, CLD_EXITED);
test(m, "exec-privatedevices-no-capability-mknod.service", 0, CLD_EXITED);
test(m, "exec-privatedevices-yes-capability-sys-rawio.service", 0, CLD_EXITED);
test(m, "exec-privatedevices-no-capability-sys-rawio.service", 0, CLD_EXITED);
}
static void test_exec_protecthome(Manager *m) {
@ -336,7 +346,7 @@ static void test_exec_protecthome(Manager *m) {
return;
}
test(__func__, m, "exec-protecthome-tmpfs-vs-protectsystem-strict.service", 0, CLD_EXITED);
test(m, "exec-protecthome-tmpfs-vs-protectsystem-strict.service", 0, CLD_EXITED);
}
static void test_exec_protectkernelmodules(Manager *m) {
@ -351,29 +361,29 @@ static void test_exec_protectkernelmodules(Manager *m) {
return;
}
r = find_binary("capsh", NULL);
r = find_executable("capsh", NULL);
if (r < 0) {
log_notice_errno(r, "Skipping %s, could not find capsh binary: %m", __func__);
return;
}
test(__func__, m, "exec-protectkernelmodules-no-capabilities.service", 0, CLD_EXITED);
test(__func__, m, "exec-protectkernelmodules-yes-capabilities.service", 0, CLD_EXITED);
test(__func__, m, "exec-protectkernelmodules-yes-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
test(m, "exec-protectkernelmodules-no-capabilities.service", 0, CLD_EXITED);
test(m, "exec-protectkernelmodules-yes-capabilities.service", 0, CLD_EXITED);
test(m, "exec-protectkernelmodules-yes-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
}
static void test_exec_readonlypaths(Manager *m) {
test(__func__, m, "exec-readonlypaths-simple.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
test(m, "exec-readonlypaths-simple.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
if (path_is_read_only_fs("/var") > 0) {
log_notice("Directory /var is readonly, skipping remaining tests in %s", __func__);
return;
}
test(__func__, m, "exec-readonlypaths.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
test(__func__, m, "exec-readonlypaths-with-bindpaths.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(__func__, m, "exec-readonlypaths-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
test(m, "exec-readonlypaths.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
test(m, "exec-readonlypaths-with-bindpaths.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(m, "exec-readonlypaths-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
}
static void test_exec_readwritepaths(Manager *m) {
@ -383,7 +393,7 @@ static void test_exec_readwritepaths(Manager *m) {
return;
}
test(__func__, m, "exec-readwritepaths-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
test(m, "exec-readwritepaths-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
}
static void test_exec_inaccessiblepaths(Manager *m) {
@ -393,22 +403,22 @@ static void test_exec_inaccessiblepaths(Manager *m) {
return;
}
test(__func__, m, "exec-inaccessiblepaths-sys.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
test(m, "exec-inaccessiblepaths-sys.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
if (path_is_read_only_fs("/") > 0) {
log_notice("Root directory is readonly, skipping remaining tests in %s", __func__);
return;
}
test(__func__, m, "exec-inaccessiblepaths-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
test(m, "exec-inaccessiblepaths-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
}
static void test_exec_temporaryfilesystem(Manager *m) {
test(__func__, m, "exec-temporaryfilesystem-options.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(__func__, m, "exec-temporaryfilesystem-ro.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(__func__, m, "exec-temporaryfilesystem-rw.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(__func__, m, "exec-temporaryfilesystem-usr.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(m, "exec-temporaryfilesystem-options.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(m, "exec-temporaryfilesystem-ro.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(m, "exec-temporaryfilesystem-rw.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(m, "exec-temporaryfilesystem-usr.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
}
static void test_exec_systemcallfilter(Manager *m) {
@ -420,22 +430,22 @@ static void test_exec_systemcallfilter(Manager *m) {
return;
}
test(__func__, m, "exec-systemcallfilter-not-failing.service", 0, CLD_EXITED);
test(__func__, m, "exec-systemcallfilter-not-failing2.service", 0, CLD_EXITED);
test(__func__, m, "exec-systemcallfilter-failing.service", SIGSYS, CLD_KILLED);
test(__func__, m, "exec-systemcallfilter-failing2.service", SIGSYS, CLD_KILLED);
test(m, "exec-systemcallfilter-not-failing.service", 0, CLD_EXITED);
test(m, "exec-systemcallfilter-not-failing2.service", 0, CLD_EXITED);
test(m, "exec-systemcallfilter-failing.service", SIGSYS, CLD_KILLED);
test(m, "exec-systemcallfilter-failing2.service", SIGSYS, CLD_KILLED);
r = find_binary("python3", NULL);
r = find_executable("python3", NULL);
if (r < 0) {
log_notice_errno(r, "Skipping remaining tests in %s, could not find python3 binary: %m", __func__);
return;
}
test(__func__, m, "exec-systemcallfilter-with-errno-name.service", errno_from_name("EILSEQ"), CLD_EXITED);
test(__func__, m, "exec-systemcallfilter-with-errno-number.service", 255, CLD_EXITED);
test(__func__, m, "exec-systemcallfilter-with-errno-multi.service", errno_from_name("EILSEQ"), CLD_EXITED);
test(__func__, m, "exec-systemcallfilter-override-error-action.service", SIGSYS, CLD_KILLED);
test(__func__, m, "exec-systemcallfilter-override-error-action2.service", errno_from_name("EILSEQ"), CLD_EXITED);
test(m, "exec-systemcallfilter-with-errno-name.service", errno_from_name("EILSEQ"), CLD_EXITED);
test(m, "exec-systemcallfilter-with-errno-number.service", 255, CLD_EXITED);
test(m, "exec-systemcallfilter-with-errno-multi.service", errno_from_name("EILSEQ"), CLD_EXITED);
test(m, "exec-systemcallfilter-override-error-action.service", SIGSYS, CLD_KILLED);
test(m, "exec-systemcallfilter-override-error-action2.service", errno_from_name("EILSEQ"), CLD_EXITED);
#endif
}
@ -448,14 +458,14 @@ static void test_exec_systemcallerrornumber(Manager *m) {
return;
}
r = find_binary("python3", NULL);
r = find_executable("python3", NULL);
if (r < 0) {
log_notice_errno(r, "Skipping %s, could not find python3 binary: %m", __func__);
return;
}
test(__func__, m, "exec-systemcallerrornumber-name.service", errno_from_name("EACCES"), CLD_EXITED);
test(__func__, m, "exec-systemcallerrornumber-number.service", 255, CLD_EXITED);
test(m, "exec-systemcallerrornumber-name.service", errno_from_name("EACCES"), CLD_EXITED);
test(m, "exec-systemcallerrornumber-number.service", 255, CLD_EXITED);
#endif
}
@ -466,13 +476,13 @@ static void test_exec_restrictnamespaces(Manager *m) {
return;
}
test(__func__, m, "exec-restrictnamespaces-no.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
test(__func__, m, "exec-restrictnamespaces-yes.service", 1, CLD_EXITED);
test(__func__, m, "exec-restrictnamespaces-mnt.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
test(__func__, m, "exec-restrictnamespaces-mnt-deny-list.service", 1, CLD_EXITED);
test(__func__, m, "exec-restrictnamespaces-merge-and.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
test(__func__, m, "exec-restrictnamespaces-merge-or.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
test(__func__, m, "exec-restrictnamespaces-merge-all.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
test(m, "exec-restrictnamespaces-no.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
test(m, "exec-restrictnamespaces-yes.service", 1, CLD_EXITED);
test(m, "exec-restrictnamespaces-mnt.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
test(m, "exec-restrictnamespaces-mnt-deny-list.service", 1, CLD_EXITED);
test(m, "exec-restrictnamespaces-merge-and.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
test(m, "exec-restrictnamespaces-merge-or.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
test(m, "exec-restrictnamespaces-merge-all.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
#endif
}
@ -488,7 +498,7 @@ static void test_exec_systemcallfilter_system(Manager *m) {
return;
}
test(__func__, m, "exec-systemcallfilter-system-user.service", 0, CLD_EXITED);
test(m, "exec-systemcallfilter-system-user.service", 0, CLD_EXITED);
if (!check_nobody_user_and_group()) {
log_notice("nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
@ -500,12 +510,12 @@ static void test_exec_systemcallfilter_system(Manager *m) {
return;
}
test(__func__, m, "exec-systemcallfilter-system-user-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
test(m, "exec-systemcallfilter-system-user-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
#endif
}
static void test_exec_user(Manager *m) {
test(__func__, m, "exec-user.service", 0, CLD_EXITED);
test(m, "exec-user.service", 0, CLD_EXITED);
if (!check_nobody_user_and_group()) {
log_notice("nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
@ -517,11 +527,11 @@ static void test_exec_user(Manager *m) {
return;
}
test(__func__, m, "exec-user-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
test(m, "exec-user-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
}
static void test_exec_group(Manager *m) {
test(__func__, m, "exec-group.service", 0, CLD_EXITED);
test(m, "exec-group.service", 0, CLD_EXITED);
if (!check_nobody_user_and_group()) {
log_notice("nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
@ -533,16 +543,16 @@ static void test_exec_group(Manager *m) {
return;
}
test(__func__, m, "exec-group-" NOBODY_GROUP_NAME ".service", 0, CLD_EXITED);
test(m, "exec-group-" NOBODY_GROUP_NAME ".service", 0, CLD_EXITED);
}
static void test_exec_supplementarygroups(Manager *m) {
test(__func__, m, "exec-supplementarygroups.service", 0, CLD_EXITED);
test(__func__, m, "exec-supplementarygroups-single-group.service", 0, CLD_EXITED);
test(__func__, m, "exec-supplementarygroups-single-group-user.service", 0, CLD_EXITED);
test(__func__, m, "exec-supplementarygroups-multiple-groups-default-group-user.service", 0, CLD_EXITED);
test(__func__, m, "exec-supplementarygroups-multiple-groups-withgid.service", 0, CLD_EXITED);
test(__func__, m, "exec-supplementarygroups-multiple-groups-withuid.service", 0, CLD_EXITED);
test(m, "exec-supplementarygroups.service", 0, CLD_EXITED);
test(m, "exec-supplementarygroups-single-group.service", 0, CLD_EXITED);
test(m, "exec-supplementarygroups-single-group-user.service", 0, CLD_EXITED);
test(m, "exec-supplementarygroups-multiple-groups-default-group-user.service", 0, CLD_EXITED);
test(m, "exec-supplementarygroups-multiple-groups-withgid.service", 0, CLD_EXITED);
test(m, "exec-supplementarygroups-multiple-groups-withuid.service", 0, CLD_EXITED);
}
static char* private_directory_bad(Manager *m) {
@ -569,14 +579,14 @@ static void test_exec_dynamicuser(Manager *m) {
return;
}
test(__func__, m, "exec-dynamicuser-fixeduser.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(m, "exec-dynamicuser-fixeduser.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
if (check_user_has_group_with_same_name("adm"))
test(__func__, m, "exec-dynamicuser-fixeduser-adm.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(m, "exec-dynamicuser-fixeduser-adm.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
if (check_user_has_group_with_same_name("games"))
test(__func__, m, "exec-dynamicuser-fixeduser-games.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(__func__, m, "exec-dynamicuser-fixeduser-one-supplementarygroup.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(__func__, m, "exec-dynamicuser-supplementarygroups.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(__func__, m, "exec-dynamicuser-statedir.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(m, "exec-dynamicuser-fixeduser-games.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(m, "exec-dynamicuser-fixeduser-one-supplementarygroup.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(m, "exec-dynamicuser-supplementarygroups.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(m, "exec-dynamicuser-statedir.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
(void) rm_rf("/var/lib/quux", REMOVE_ROOT|REMOVE_PHYSICAL);
(void) rm_rf("/var/lib/test-dynamicuser-migrate", REMOVE_ROOT|REMOVE_PHYSICAL);
@ -587,25 +597,25 @@ static void test_exec_dynamicuser(Manager *m) {
(void) rm_rf("/var/lib/private/test-dynamicuser-migrate2", REMOVE_ROOT|REMOVE_PHYSICAL);
(void) rm_rf("/var/lib/private/waldo", REMOVE_ROOT|REMOVE_PHYSICAL);
test(__func__, m, "exec-dynamicuser-statedir-migrate-step1.service", 0, CLD_EXITED);
test(__func__, m, "exec-dynamicuser-statedir-migrate-step2.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(__func__, m, "exec-dynamicuser-statedir-migrate-step1.service", 0, CLD_EXITED);
test(m, "exec-dynamicuser-statedir-migrate-step1.service", 0, CLD_EXITED);
test(m, "exec-dynamicuser-statedir-migrate-step2.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(m, "exec-dynamicuser-statedir-migrate-step1.service", 0, CLD_EXITED);
(void) rm_rf("/var/lib/test-dynamicuser-migrate", REMOVE_ROOT|REMOVE_PHYSICAL);
(void) rm_rf("/var/lib/test-dynamicuser-migrate2", REMOVE_ROOT|REMOVE_PHYSICAL);
(void) rm_rf("/var/lib/private/test-dynamicuser-migrate", REMOVE_ROOT|REMOVE_PHYSICAL);
(void) rm_rf("/var/lib/private/test-dynamicuser-migrate2", REMOVE_ROOT|REMOVE_PHYSICAL);
test(__func__, m, "exec-dynamicuser-runtimedirectory1.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(__func__, m, "exec-dynamicuser-runtimedirectory2.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(__func__, m, "exec-dynamicuser-runtimedirectory3.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(m, "exec-dynamicuser-runtimedirectory1.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(m, "exec-dynamicuser-runtimedirectory2.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
test(m, "exec-dynamicuser-runtimedirectory3.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
}
static void test_exec_environment(Manager *m) {
test(__func__, m, "exec-environment-no-substitute.service", 0, CLD_EXITED);
test(__func__, m, "exec-environment.service", 0, CLD_EXITED);
test(__func__, m, "exec-environment-multiple.service", 0, CLD_EXITED);
test(__func__, m, "exec-environment-empty.service", 0, CLD_EXITED);
test(m, "exec-environment-no-substitute.service", 0, CLD_EXITED);
test(m, "exec-environment.service", 0, CLD_EXITED);
test(m, "exec-environment-multiple.service", 0, CLD_EXITED);
test(m, "exec-environment-empty.service", 0, CLD_EXITED);
}
static void test_exec_environmentfile(Manager *m) {
@ -625,7 +635,7 @@ static void test_exec_environmentfile(Manager *m) {
r = write_string_file("/tmp/test-exec_environmentfile.conf", e, WRITE_STRING_FILE_CREATE);
assert_se(r == 0);
test(__func__, m, "exec-environmentfile.service", 0, CLD_EXITED);
test(m, "exec-environmentfile.service", 0, CLD_EXITED);
(void) unlink("/tmp/test-exec_environmentfile.conf");
}
@ -647,26 +657,26 @@ static void test_exec_passenvironment(Manager *m) {
assert_se(setenv("VAR3", "$word 5 6", 1) == 0);
assert_se(setenv("VAR4", "new\nline", 1) == 0);
assert_se(setenv("VAR5", "passwordwithbackslashes", 1) == 0);
test(__func__, m, "exec-passenvironment.service", 0, CLD_EXITED);
test(__func__, m, "exec-passenvironment-repeated.service", 0, CLD_EXITED);
test(__func__, m, "exec-passenvironment-empty.service", 0, CLD_EXITED);
test(m, "exec-passenvironment.service", 0, CLD_EXITED);
test(m, "exec-passenvironment-repeated.service", 0, CLD_EXITED);
test(m, "exec-passenvironment-empty.service", 0, CLD_EXITED);
assert_se(unsetenv("VAR1") == 0);
assert_se(unsetenv("VAR2") == 0);
assert_se(unsetenv("VAR3") == 0);
assert_se(unsetenv("VAR4") == 0);
assert_se(unsetenv("VAR5") == 0);
test(__func__, m, "exec-passenvironment-absent.service", 0, CLD_EXITED);
test(m, "exec-passenvironment-absent.service", 0, CLD_EXITED);
}
static void test_exec_umask(Manager *m) {
test(__func__, m, "exec-umask-default.service", 0, CLD_EXITED);
test(__func__, m, "exec-umask-0177.service", 0, CLD_EXITED);
test(m, "exec-umask-default.service", 0, CLD_EXITED);
test(m, "exec-umask-0177.service", 0, CLD_EXITED);
}
static void test_exec_runtimedirectory(Manager *m) {
test(__func__, m, "exec-runtimedirectory.service", 0, CLD_EXITED);
test(__func__, m, "exec-runtimedirectory-mode.service", 0, CLD_EXITED);
test(__func__, m, "exec-runtimedirectory-owner.service", 0, CLD_EXITED);
test(m, "exec-runtimedirectory.service", 0, CLD_EXITED);
test(m, "exec-runtimedirectory-mode.service", 0, CLD_EXITED);
test(m, "exec-runtimedirectory-owner.service", 0, CLD_EXITED);
if (!check_nobody_user_and_group()) {
log_notice("nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
@ -678,13 +688,13 @@ static void test_exec_runtimedirectory(Manager *m) {
return;
}
test(__func__, m, "exec-runtimedirectory-owner-" NOBODY_GROUP_NAME ".service", 0, CLD_EXITED);
test(m, "exec-runtimedirectory-owner-" NOBODY_GROUP_NAME ".service", 0, CLD_EXITED);
}
static void test_exec_capabilityboundingset(Manager *m) {
int r;
r = find_binary("capsh", NULL);
r = find_executable("capsh", NULL);
if (r < 0) {
log_notice_errno(r, "Skipping %s, could not find capsh binary: %m", __func__);
return;
@ -697,14 +707,14 @@ static void test_exec_capabilityboundingset(Manager *m) {
return;
}
test(__func__, m, "exec-capabilityboundingset-simple.service", 0, CLD_EXITED);
test(__func__, m, "exec-capabilityboundingset-reset.service", 0, CLD_EXITED);
test(__func__, m, "exec-capabilityboundingset-merge.service", 0, CLD_EXITED);
test(__func__, m, "exec-capabilityboundingset-invert.service", 0, CLD_EXITED);
test(m, "exec-capabilityboundingset-simple.service", 0, CLD_EXITED);
test(m, "exec-capabilityboundingset-reset.service", 0, CLD_EXITED);
test(m, "exec-capabilityboundingset-merge.service", 0, CLD_EXITED);
test(m, "exec-capabilityboundingset-invert.service", 0, CLD_EXITED);
}
static void test_exec_basic(Manager *m) {
test(__func__, m, "exec-basic.service", 0, CLD_EXITED);
test(m, "exec-basic.service", 0, CLD_EXITED);
}
static void test_exec_ambientcapabilities(Manager *m) {
@ -726,8 +736,8 @@ static void test_exec_ambientcapabilities(Manager *m) {
return;
}
test(__func__, m, "exec-ambientcapabilities.service", 0, CLD_EXITED);
test(__func__, m, "exec-ambientcapabilities-merge.service", 0, CLD_EXITED);
test(m, "exec-ambientcapabilities.service", 0, CLD_EXITED);
test(m, "exec-ambientcapabilities-merge.service", 0, CLD_EXITED);
if (!check_nobody_user_and_group()) {
log_notice("nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
@ -739,71 +749,71 @@ static void test_exec_ambientcapabilities(Manager *m) {
return;
}
test(__func__, m, "exec-ambientcapabilities-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
test(__func__, m, "exec-ambientcapabilities-merge-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
test(m, "exec-ambientcapabilities-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
test(m, "exec-ambientcapabilities-merge-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
}
static void test_exec_privatenetwork(Manager *m) {
int r;
r = find_binary("ip", NULL);
r = find_executable("ip", NULL);
if (r < 0) {
log_notice_errno(r, "Skipping %s, could not find ip binary: %m", __func__);
return;
}
test(__func__, m, "exec-privatenetwork-yes.service", can_unshare ? 0 : EXIT_NETWORK, CLD_EXITED);
test(m, "exec-privatenetwork-yes.service", can_unshare ? 0 : EXIT_NETWORK, CLD_EXITED);
}
static void test_exec_oomscoreadjust(Manager *m) {
test(__func__, m, "exec-oomscoreadjust-positive.service", 0, CLD_EXITED);
test(m, "exec-oomscoreadjust-positive.service", 0, CLD_EXITED);
if (detect_container() > 0) {
log_notice("Testing in container, skipping remaining tests in %s", __func__);
return;
}
test(__func__, m, "exec-oomscoreadjust-negative.service", 0, CLD_EXITED);
test(m, "exec-oomscoreadjust-negative.service", 0, CLD_EXITED);
}
static void test_exec_ioschedulingclass(Manager *m) {
test(__func__, m, "exec-ioschedulingclass-none.service", 0, CLD_EXITED);
test(__func__, m, "exec-ioschedulingclass-idle.service", 0, CLD_EXITED);
test(__func__, m, "exec-ioschedulingclass-best-effort.service", 0, CLD_EXITED);
test(m, "exec-ioschedulingclass-none.service", 0, CLD_EXITED);
test(m, "exec-ioschedulingclass-idle.service", 0, CLD_EXITED);
test(m, "exec-ioschedulingclass-best-effort.service", 0, CLD_EXITED);
if (detect_container() > 0) {
log_notice("Testing in container, skipping remaining tests in %s", __func__);
return;
}
test(__func__, m, "exec-ioschedulingclass-realtime.service", 0, CLD_EXITED);
test(m, "exec-ioschedulingclass-realtime.service", 0, CLD_EXITED);
}
static void test_exec_unsetenvironment(Manager *m) {
test(__func__, m, "exec-unsetenvironment.service", 0, CLD_EXITED);
test(m, "exec-unsetenvironment.service", 0, CLD_EXITED);
}
static void test_exec_specifier(Manager *m) {
test(__func__, m, "exec-specifier.service", 0, CLD_EXITED);
test(__func__, m, "exec-specifier@foo-bar.service", 0, CLD_EXITED);
test(__func__, m, "exec-specifier-interpolation.service", 0, CLD_EXITED);
test(m, "exec-specifier.service", 0, CLD_EXITED);
test(m, "exec-specifier@foo-bar.service", 0, CLD_EXITED);
test(m, "exec-specifier-interpolation.service", 0, CLD_EXITED);
}
static void test_exec_standardinput(Manager *m) {
test(__func__, m, "exec-standardinput-data.service", 0, CLD_EXITED);
test(__func__, m, "exec-standardinput-file.service", 0, CLD_EXITED);
test(__func__, m, "exec-standardinput-file-cat.service", 0, CLD_EXITED);
test(m, "exec-standardinput-data.service", 0, CLD_EXITED);
test(m, "exec-standardinput-file.service", 0, CLD_EXITED);
test(m, "exec-standardinput-file-cat.service", 0, CLD_EXITED);
}
static void test_exec_standardoutput(Manager *m) {
test(__func__, m, "exec-standardoutput-file.service", 0, CLD_EXITED);
test(m, "exec-standardoutput-file.service", 0, CLD_EXITED);
}
static void test_exec_standardoutput_append(Manager *m) {
test(__func__, m, "exec-standardoutput-append.service", 0, CLD_EXITED);
test(m, "exec-standardoutput-append.service", 0, CLD_EXITED);
}
static void test_exec_condition(Manager *m) {
test_service(__func__, m, "exec-condition-failed.service", SERVICE_FAILURE_EXIT_CODE);
test_service(__func__, m, "exec-condition-skip.service", SERVICE_SKIP_CONDITION);
test_service(m, "exec-condition-failed.service", SERVICE_FAILURE_EXIT_CODE);
test_service(m, "exec-condition-skip.service", SERVICE_SKIP_CONDITION);
}
typedef struct test_entry {

View File

@ -802,50 +802,6 @@ static void test_chmod_and_chown(void) {
assert_se(S_ISLNK(st.st_mode));
}
static void test_chmod_and_chown_unsafe(void) {
_cleanup_(rm_rf_physical_and_freep) char *d = NULL;
_unused_ _cleanup_umask_ mode_t u = umask(0000);
struct stat st;
const char *p;
if (geteuid() != 0)
return;
log_info("/* %s */", __func__);
assert_se(mkdtemp_malloc(NULL, &d) >= 0);
p = strjoina(d, "/reg");
assert_se(mknod(p, S_IFREG | 0123, 0) >= 0);
assert_se(chmod_and_chown_unsafe(p, S_IFREG | 0321, 1, 2) >= 0);
assert_se(chmod_and_chown_unsafe(p, S_IFDIR | 0555, 3, 4) == -EINVAL);
assert_se(lstat(p, &st) >= 0);
assert_se(S_ISREG(st.st_mode));
assert_se((st.st_mode & 07777) == 0321);
p = strjoina(d, "/dir");
assert_se(mkdir(p, 0123) >= 0);
assert_se(chmod_and_chown_unsafe(p, S_IFDIR | 0321, 1, 2) >= 0);
assert_se(chmod_and_chown_unsafe(p, S_IFREG | 0555, 3, 4) == -EINVAL);
assert_se(lstat(p, &st) >= 0);
assert_se(S_ISDIR(st.st_mode));
assert_se((st.st_mode & 07777) == 0321);
p = strjoina(d, "/lnk");
assert_se(symlink("idontexist", p) >= 0);
assert_se(chmod_and_chown_unsafe(p, S_IFLNK | 0321, 1, 2) >= 0);
assert_se(chmod_and_chown_unsafe(p, S_IFREG | 0555, 3, 4) == -EINVAL);
assert_se(chmod_and_chown_unsafe(p, S_IFDIR | 0555, 3, 4) == -EINVAL);
assert_se(lstat(p, &st) >= 0);
assert_se(S_ISLNK(st.st_mode));
}
static void test_path_is_encrypted_one(const char *p, int expect) {
int r;
@ -895,7 +851,6 @@ int main(int argc, char *argv[]) {
test_fsync_directory_of_file();
test_rename_noreplace();
test_chmod_and_chown();
test_chmod_and_chown_unsafe();
test_path_is_encrypted();
return 0;

View File

@ -202,12 +202,11 @@ static void test_config_parse_exec(void) {
"-@/RValue argv0 r1 ; ; "
"/goo/goo boo",
&c, u);
assert_se(r == -ENOEXEC);
assert_se(r >= 0);
c1 = c1->command_next;
check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true);
/* second command fails because the executable name is ";" */
assert_se(c1->command_next == NULL);
c1 = c1->command_next;
check_execcommand(c1, "/goo/goo", "/goo/goo", "boo", NULL, false);
log_info("/* trailing semicolon */");
r = config_parse_exec(NULL, "fake", 5, "section", 1,

View File

@ -164,31 +164,76 @@ static void test_path_equal_root(void) {
assert_se(!path_equal_or_files_same("/", "/.../", AT_SYMLINK_NOFOLLOW));
}
static void test_find_binary(const char *self) {
static void test_find_executable_full(void) {
char *p;
log_info("/* %s */", __func__);
assert_se(find_binary("/bin/sh", &p) == 0);
assert_se(find_executable_full("sh", true, &p) == 0);
puts(p);
assert_se(streq(basename(p), "sh"));
free(p);
assert_se(find_executable_full("sh", false, &p) == 0);
puts(p);
assert_se(streq(basename(p), "sh"));
free(p);
_cleanup_free_ char *oldpath = NULL;
p = getenv("PATH");
if (p)
assert_se(oldpath = strdup(p));
assert_se(unsetenv("PATH") >= 0);
assert_se(find_executable_full("sh", true, &p) == 0);
puts(p);
assert_se(streq(basename(p), "sh"));
free(p);
assert_se(find_executable_full("sh", false, &p) == 0);
puts(p);
assert_se(streq(basename(p), "sh"));
free(p);
if (oldpath)
assert_se(setenv("PATH", oldpath, true) >= 0);
}
static void test_find_executable(const char *self) {
char *p;
log_info("/* %s */", __func__);
assert_se(find_executable("/bin/sh", &p) == 0);
puts(p);
assert_se(path_equal(p, "/bin/sh"));
free(p);
assert_se(find_binary(self, &p) == 0);
assert_se(find_executable(self, &p) == 0);
puts(p);
/* libtool might prefix the binary name with "lt-" */
assert_se(endswith(p, "/lt-test-path-util") || endswith(p, "/test-path-util"));
assert_se(endswith(p, "/test-path-util"));
assert_se(path_is_absolute(p));
free(p);
assert_se(find_binary("sh", &p) == 0);
assert_se(find_executable("sh", &p) == 0);
puts(p);
assert_se(endswith(p, "/sh"));
assert_se(path_is_absolute(p));
free(p);
assert_se(find_binary("xxxx-xxxx", &p) == -ENOENT);
assert_se(find_binary("/some/dir/xxxx-xxxx", &p) == -ENOENT);
assert_se(find_executable("/bin/touch", &p) == 0);
assert_se(streq(p, "/bin/touch"));
free(p);
assert_se(find_executable("touch", &p) == 0);
assert_se(path_is_absolute(p));
assert_se(streq(basename(p), "touch"));
free(p);
assert_se(find_executable("xxxx-xxxx", &p) == -ENOENT);
assert_se(find_executable("/some/dir/xxxx-xxxx", &p) == -ENOENT);
assert_se(find_executable("/proc/filesystems", &p) == -EACCES);
}
static void test_prefixes(void) {
@ -537,6 +582,9 @@ static void test_filename_is_valid(void) {
assert_se(!filename_is_valid("/"));
assert_se(!filename_is_valid("."));
assert_se(!filename_is_valid(".."));
assert_se(!filename_is_valid("bar/foo"));
assert_se(!filename_is_valid("bar/foo/"));
assert_se(!filename_is_valid("bar//"));
for (i=0; i<FILENAME_MAX+1; i++)
foo[i] = 'a';
@ -667,7 +715,8 @@ int main(int argc, char **argv) {
test_print_paths();
test_path();
test_path_equal_root();
test_find_binary(argv[0]);
test_find_executable_full();
test_find_executable(argv[0]);
test_prefixes();
test_path_join();
test_fsck_exists();

View File

@ -405,7 +405,7 @@ int xdg_autostart_format_exec_start(
/* This is the executable, find it in $PATH */
first_arg = false;
r = find_binary(c, &executable);
r = find_executable(c, &executable);
if (r < 0)
return log_info_errno(r, "Exec binary '%s' does not exist: %m", c);
@ -481,7 +481,7 @@ static int xdg_autostart_generate_desktop_condition(
if (!isempty(condition)) {
_cleanup_free_ char *gnome_autostart_condition_path = NULL, *e_autostart_condition = NULL;
r = find_binary(test_binary, &gnome_autostart_condition_path);
r = find_executable(test_binary, &gnome_autostart_condition_path);
if (r < 0) {
log_full_errno(r == -ENOENT ? LOG_INFO : LOG_WARNING, r,
"%s not found: %m", test_binary);
@ -536,10 +536,10 @@ int xdg_autostart_service_generate_unit(
/*
* The TryExec key cannot be checked properly from the systemd unit,
* it is trivial to check using find_binary though.
* it is trivial to check using find_executable though.
*/
if (service->try_exec) {
r = find_binary(service->try_exec, NULL);
r = find_executable(service->try_exec, NULL);
if (r < 0) {
log_full_errno(r == -ENOENT ? LOG_INFO : LOG_WARNING, r,
"Not generating service for XDG autostart %s, could not find TryExec= binary %s: %m",