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

Compare commits

...

20 Commits

Author SHA1 Message Date
Lennart Poettering
ce9fb09e96
Merge pull request #17809 from yuwata/network-address-fixes-17803
network: two fixes for configuring address correctly
2020-12-03 21:04:58 +01:00
Lennart Poettering
61bd7d1ed5 random-util: open /dev/urandom implicitly in random_write_entropy() if needed 2020-12-03 20:14:17 +01:00
Lennart Poettering
e267d76f73
Merge pull request #17836 from poettering/tpm2-condition
Add ConditionSecurity=tpm2
2020-12-03 20:13:45 +01:00
Lennart Poettering
6dd16814a5
Merge pull request #17079 from keszybz/late-exec-resolution
Resolve executable paths before execution, use fexecve()
2020-12-03 14:58:20 +01:00
Lennart Poettering
03d8ebb935
Merge pull request #17812 from poettering/systemctl-version-feature-update
build.h: add a bunch of missing features strings
2020-12-03 14:34:08 +01:00
Zbigniew Jędrzejewski-Szmek
91b79ba84e shared/build: make the version string definition less terrible
The BLKID and ELFUTILS strings were present twice. Let's reaarange things so that
each times requires definition in exactly one place.

Also let's sort things a bit:
the "heavy hitters" like PAM/MAC first,
then crypto libs,
then other libs, alphabetically,
compressors,
and external compat integrations.

I think it's useful for users to group similar concepts together to some extent.
For example, when checking what compression is available, it helps a lot to have
them listed together.

FDISK is renamed to LIBFDISK to make it clear that this is about he library and
the executable.
2020-12-03 12:16:02 +01:00
Lennart Poettering
699c0f2d30 update TODO 2020-12-03 12:04:11 +01:00
Lennart Poettering
bce334a31c core: add ConditionSecurity=tpm2 support 2020-12-03 12:03:58 +01:00
Lennart Poettering
6c822dc2d5 build.h: add a bunch of missing features strings
Let's make "systemctl --version" more useful for detecting when
build-time features/deps are enabled and which ones arent't again.
2020-12-03 09:24:55 +01:00
Yu Watanabe
2a236f9fc0 network: ignore broadcast address for /31 or /32 addresses
As they do not have broadcast address.
See https://tools.ietf.org/html/rfc3021
2020-12-03 10:23:12 +09:00
Yu Watanabe
05a7023d24 network: fix verification for broadcast address
Fixes a bug caused by fe841414ef157f7f01d339c5d5730126e7b5fe0a.
2020-12-03 10:23:12 +09:00
Yu Watanabe
df8aa08642 network: do not set broadcast if prefixlen is 31 or 32
After fe841414ef157f7f01d339c5d5730126e7b5fe0a, broadcast address is
also compared with existing one to determine whether the address is
foregin or not. So, the address object should not contain unnecessary
information.

Fixes #17803.
2020-12-03 10:22:50 +09:00
Zbigniew Jędrzejewski-Szmek
ceedbf8185 meson: add option for fexecve use
There are downsides to using fexecve:

when fexecve is used (for normal executables), /proc/pid/status shows Name: 3,
which means that ps -C foobar doesn't work. pidof works, because it checks
/proc/self/cmdline. /proc/self/exe also shows the correct link, but requires
privileges to read. /proc/self/comm also shows "3".

I think this can be considered a kernel deficiency: when O_CLOEXEC is used, this
"3" is completely meaningless. It could be any number. The kernel should use
argv[0] instead, which at least has *some* meaning.

I think the approach with fexecve/execveat is instersting, so let's provide it
as opt-in.
2020-11-06 15:20:34 +01:00
Zbigniew Jędrzejewski-Szmek
3f51bbff55 shared/exec-util: fall back to execve() also on permission errors 2020-11-06 15:20:34 +01:00
Zbigniew Jędrzejewski-Szmek
f98ca3a11d test-execute: make sure shell execs the child
echo is a built-in, so we were testing execve in our own code, and not in
the running child.
2020-11-06 15:20:34 +01:00
Zbigniew Jędrzejewski-Szmek
8939eeae52 shared/exec-util: use our own execveat() wrapper instead of fexecve()
For scripts, when we call fexecve(), on new kernels glibc calls execveat(),
which fails with ENOENT, and then we fall back to execve() which succeeds:
[pid 63039] execveat(3, "", ["/home/zbyszek/src/systemd/test/test-path-util/script.sh", "--version"], 0x7ffefa3633f0 /* 0 vars */, AT_EMPTY_PATH) = -1 ENOENT (No such file or directory)
[pid 63039] execve("/home/zbyszek/src/systemd/test/test-path-util/script.sh", ["/home/zbyszek/src/systemd/test/test-path-util/script.sh", "--version"], 0x7ffefa3633f0 /* 0 vars */) = 0

But on older kernels glibc (some versions?) implement a fallback which falls
into the same trap with bash $0:
[pid 13534] execve("/proc/self/fd/3", ["/home/test/systemd/test/test-path-util/script.sh", "--version"], 0x7fff84995870 /* 0 vars */) = 0

We don't want that, so let's call execveat() ourselves. Then we can do the
execve() fallback as we want.
2020-11-06 15:20:34 +01:00
Zbigniew Jędrzejewski-Szmek
a6d9111c67 core/execute: fall back to execve() for scripts
fexecve() fails with ENOENT and we need a fallback. Add appropriate test.
2020-11-06 15:14:13 +01:00
Zbigniew Jędrzejewski-Szmek
b83d505087 core: use fexecve() to spawn children
We base the smack/selinux setup on the executable. Let's open the file
once and use the same fd for that setup and the subsequent execve.
2020-11-06 15:13:01 +01:00
Zbigniew Jędrzejewski-Szmek
5ca9139ace basic/path-util: let find_executable_full() optionally return an fd 2020-11-06 15:12:54 +01:00
Zbigniew Jędrzejewski-Szmek
1da37e58ff core/execute: refactor creation of array with fds to keep during execution
We close fds in two phases, first some and then the some more. When passing
a list of fds to exclude from closing to the closing function, we would
pass some in an array and the rest as separate arguments. For the fds which
should be excluded in both closing phases, let's always create the array
and put the relevant fds there. This has the advantage that if more fds to
exclude in both phases are added later, we don't need to add more positional
arguments.

The list passed to setup_pam() is not changed. I think we could pass more fds
to close there, but I'm leaving that unchanged.

The setting of FD_CLOEXEC on an already open fds is dropped. The fd is opened
in service_allocate_exec_fd() and there is no reason to suspect that it might
have been opened incorrectly. If some rogue code is unsetting our FD_CLOEXEC
bits, then it might flip any fd, no reason to single this one out.
2020-10-14 18:29:25 +02:00
28 changed files with 536 additions and 312 deletions

2
TODO
View File

@ -113,8 +113,6 @@ Features:
* systemd-firstboot: make sure to always use chase_symlinks() before
reading/writing files
* add ConditionSecurity=tpm2
* Remove any support for booting without /usr pre-mounted in the initrd entirely.
Update INITRD_INTERFACE.md accordingly.

View File

@ -1257,9 +1257,9 @@
<listitem><para><varname>ConditionSecurity=</varname> may be used to check whether the given
security technology is enabled on the system. Currently, the recognized values are
<literal>selinux</literal>, <literal>apparmor</literal>, <literal>tomoyo</literal>,
<literal>ima</literal>, <literal>smack</literal>, <literal>audit</literal> and
<literal>uefi-secureboot</literal>. The test may be negated by prepending an exclamation
mark.</para>
<literal>ima</literal>, <literal>smack</literal>, <literal>audit</literal>,
<literal>uefi-secureboot</literal> and <literal>tpm2</literal>. The test may be negated by prepending
an exclamation mark.</para>
</listitem>
</varlistentry>

View File

@ -216,6 +216,7 @@ conf.set_quoted('SYSTEM_SYSVRCND_PATH', sysvrcnd_path)
conf.set_quoted('RC_LOCAL_PATH', get_option('rc-local'))
conf.set('ANSI_OK_COLOR', 'ANSI_' + get_option('ok-color').underscorify().to_upper())
conf.set10('ENABLE_FEXECVE', get_option('fexecve'))
conf.set_quoted('USER_CONFIG_UNIT_DIR', join_paths(pkgsysconfdir, 'user'))
conf.set_quoted('USER_DATA_UNIT_DIR', userunitdir)
@ -534,6 +535,7 @@ foreach ident : [
#include <signal.h>
#include <sys/wait.h>'''],
['mallinfo', '''#include <malloc.h>'''],
['execveat', '''#include <unistd.h>'''],
['close_range', '''#include <unistd.h>'''],
]
@ -3832,6 +3834,7 @@ foreach tuple : [
['link-timesyncd-shared', get_option('link-timesyncd-shared')],
['kernel-install', get_option('kernel-install')],
['systemd-analyze', conf.get('ENABLE_ANALYZE') == 1],
['fexecve'],
]
if tuple.length() >= 2

View File

@ -375,13 +375,15 @@ option('fuzz-tests', type : 'boolean', value : 'false',
option('install-tests', type : 'boolean', value : 'false',
description : 'install test executables')
option('ok-color', type: 'combo',
option('ok-color', type : 'combo',
choices : ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan',
'white', 'highlight-black', 'highlight-red', 'highlight-green',
'highlight-yellow', 'highlight-blue', 'highlight-magenta',
'highlight-cyan', 'highlight-white'],
value : 'green',
description: 'color of the "OK" status message')
option('fexecve', type : 'boolean', value : 'false',
description : 'use fexecve() to spawn children')
option('oss-fuzz', type : 'boolean', value : 'false',
description : 'build against oss-fuzz')

216
src/basic/build.c Normal file
View File

@ -0,0 +1,216 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "build.h"
const char* const systemd_features =
/* PAM and MAC frameworks */
#if HAVE_PAM
"+PAM"
#else
"-PAM"
#endif
#if HAVE_AUDIT
" +AUDIT"
#else
" -AUDIT"
#endif
#if HAVE_SELINUX
" +SELINUX"
#else
" -SELINUX"
#endif
#if HAVE_APPARMOR
" +APPARMOR"
#else
" -APPARMOR"
#endif
#if ENABLE_IMA
" +IMA"
#else
" -IMA"
#endif
#if ENABLE_SMACK
" +SMACK"
#else
" -SMACK"
#endif
#if HAVE_SECCOMP
" +SECCOMP"
#else
" -SECCOMP"
#endif
/* crypto libraries */
#if HAVE_GCRYPT
" +GCRYPT"
#else
" -GCRYPT"
#endif
#if HAVE_GNUTLS
" +GNUTLS"
#else
" -GNUTLS"
#endif
#if HAVE_OPENSSL
" +OPENSSL"
#else
" -OPENSSL"
#endif
/* all other libraries, sorted alphabetically */
#if HAVE_ACL
" +ACL"
#else
" -ACL"
#endif
#if HAVE_BLKID
" +BLKID"
#else
" -BLKID"
#endif
#if HAVE_LIBCURL
" +CURL"
#else
" -CURL"
#endif
#if HAVE_ELFUTILS
" +ELFUTILS"
#else
" -ELFUTILS"
#endif
#if HAVE_LIBFIDO2
" +FIDO2"
#else
" -FIDO2"
#endif
#if HAVE_LIBIDN2
" +IDN2"
#else
" -IDN2"
#endif
#if HAVE_LIBIDN
" +IDN"
#else
" -IDN"
#endif
#if HAVE_LIBIPTC
" +IPTC"
#else
" -IPTC"
#endif
#if HAVE_KMOD
" +KMOD"
#else
" -KMOD"
#endif
#if HAVE_LIBCRYPTSETUP
" +LIBCRYPTSETUP"
#else
" -LIBCRYPTSETUP"
#endif
#if HAVE_LIBFDISK
" +LIBFDISK"
#else
" -LIBFDISK"
#endif
#if HAVE_PCRE2
" +PCRE2"
#else
" -PCRE2"
#endif
#if HAVE_PWQUALITY
" +PWQUALITY"
#else
" -PWQUALITY"
#endif
#if HAVE_P11KIT
" +P11KIT"
#else
" -P11KIT"
#endif
#if HAVE_QRENCODE
" +QRENCODE"
#else
" -QRENCODE"
#endif
/* compressors */
#if HAVE_BZIP2
" +BZIP2"
#else
" -BZIP2"
#endif
#if HAVE_LZ4
" +LZ4"
#else
" -LZ4"
#endif
#if HAVE_XZ
" +XZ"
#else
" -XZ"
#endif
#if HAVE_ZLIB
" +ZLIB"
#else
" -ZLIB"
#endif
#if HAVE_ZSTD
" +ZSTD"
#else
" -ZSTD"
#endif
/* other stuff that doesn't fit above */
#if HAVE_XKBCOMMON
" +XKBCOMMON"
#else
" -XKBCOMMON"
#endif
#if ENABLE_UTMP
" +UTMP"
#else
" -UTMP"
#endif
#if HAVE_SYSV_COMPAT
" +SYSVINIT"
#else
" -SYSVINIT"
#endif
" default-hierarchy=" DEFAULT_HIERARCHY_NAME
;

View File

@ -3,164 +3,7 @@
#include "version.h"
#if HAVE_PAM
#define _PAM_FEATURE_ "+PAM"
#else
#define _PAM_FEATURE_ "-PAM"
#endif
#if HAVE_AUDIT
#define _AUDIT_FEATURE_ "+AUDIT"
#else
#define _AUDIT_FEATURE_ "-AUDIT"
#endif
#if HAVE_SELINUX
#define _SELINUX_FEATURE_ "+SELINUX"
#else
#define _SELINUX_FEATURE_ "-SELINUX"
#endif
#if HAVE_APPARMOR
#define _APPARMOR_FEATURE_ "+APPARMOR"
#else
#define _APPARMOR_FEATURE_ "-APPARMOR"
#endif
#if ENABLE_IMA
#define _IMA_FEATURE_ "+IMA"
#else
#define _IMA_FEATURE_ "-IMA"
#endif
#if ENABLE_SMACK
#define _SMACK_FEATURE_ "+SMACK"
#else
#define _SMACK_FEATURE_ "-SMACK"
#endif
#if HAVE_SYSV_COMPAT
#define _SYSVINIT_FEATURE_ "+SYSVINIT"
#else
#define _SYSVINIT_FEATURE_ "-SYSVINIT"
#endif
#if ENABLE_UTMP
#define _UTMP_FEATURE_ "+UTMP"
#else
#define _UTMP_FEATURE_ "-UTMP"
#endif
#if HAVE_LIBCRYPTSETUP
#define _LIBCRYPTSETUP_FEATURE_ "+LIBCRYPTSETUP"
#else
#define _LIBCRYPTSETUP_FEATURE_ "-LIBCRYPTSETUP"
#endif
#if HAVE_GCRYPT
#define _GCRYPT_FEATURE_ "+GCRYPT"
#else
#define _GCRYPT_FEATURE_ "-GCRYPT"
#endif
#if HAVE_GNUTLS
#define _GNUTLS_FEATURE_ "+GNUTLS"
#else
#define _GNUTLS_FEATURE_ "-GNUTLS"
#endif
#if HAVE_ACL
#define _ACL_FEATURE_ "+ACL"
#else
#define _ACL_FEATURE_ "-ACL"
#endif
#if HAVE_XZ
#define _XZ_FEATURE_ "+XZ"
#else
#define _XZ_FEATURE_ "-XZ"
#endif
#if HAVE_LZ4
#define _LZ4_FEATURE_ "+LZ4"
#else
#define _LZ4_FEATURE_ "-LZ4"
#endif
#if HAVE_ZSTD
#define _ZSTD_FEATURE_ "+ZSTD"
#else
#define _ZSTD_FEATURE_ "-ZSTD"
#endif
#if HAVE_SECCOMP
#define _SECCOMP_FEATURE_ "+SECCOMP"
#else
#define _SECCOMP_FEATURE_ "-SECCOMP"
#endif
#if HAVE_BLKID
#define _BLKID_FEATURE_ "+BLKID"
#else
#define _BLKID_FEATURE_ "-BLKID"
#endif
#if HAVE_ELFUTILS
#define _ELFUTILS_FEATURE_ "+ELFUTILS"
#else
#define _ELFUTILS_FEATURE_ "-ELFUTILS"
#endif
#if HAVE_KMOD
#define _KMOD_FEATURE_ "+KMOD"
#else
#define _KMOD_FEATURE_ "-KMOD"
#endif
#if HAVE_LIBIDN2
#define _IDN2_FEATURE_ "+IDN2"
#else
#define _IDN2_FEATURE_ "-IDN2"
#endif
#if HAVE_LIBIDN
#define _IDN_FEATURE_ "+IDN"
#else
#define _IDN_FEATURE_ "-IDN"
#endif
#if HAVE_PCRE2
#define _PCRE2_FEATURE_ "+PCRE2"
#else
#define _PCRE2_FEATURE_ "-PCRE2"
#endif
#define _CGROUP_HIERARCHY_ "default-hierarchy=" DEFAULT_HIERARCHY_NAME
#define SYSTEMD_FEATURES \
_PAM_FEATURE_ " " \
_AUDIT_FEATURE_ " " \
_SELINUX_FEATURE_ " " \
_IMA_FEATURE_ " " \
_APPARMOR_FEATURE_ " " \
_SMACK_FEATURE_ " " \
_SYSVINIT_FEATURE_ " " \
_UTMP_FEATURE_ " " \
_LIBCRYPTSETUP_FEATURE_ " " \
_GCRYPT_FEATURE_ " " \
_GNUTLS_FEATURE_ " " \
_ACL_FEATURE_ " " \
_XZ_FEATURE_ " " \
_LZ4_FEATURE_ " " \
_ZSTD_FEATURE_ " " \
_SECCOMP_FEATURE_ " " \
_BLKID_FEATURE_ " " \
_ELFUTILS_FEATURE_ " " \
_KMOD_FEATURE_ " " \
_IDN2_FEATURE_ " " \
_IDN_FEATURE_ " " \
_PCRE2_FEATURE_ " " \
_CGROUP_HIERARCHY_
extern const char* const systemd_features;
enum {
BUILD_MODE_DEVELOPER,

View File

@ -19,6 +19,7 @@ basic_sources = files('''
blockdev-util.h
btrfs-util.c
btrfs-util.h
build.c
build.h
bus-label.c
bus-label.h

View File

@ -749,6 +749,25 @@ static inline int missing_rt_sigqueueinfo(pid_t tgid, int sig, siginfo_t *info)
# define rt_sigqueueinfo missing_rt_sigqueueinfo
#endif
/* ======================================================================= */
#if !HAVE_EXECVEAT
static inline int missing_execveat(int dirfd, const char *pathname,
char *const argv[], char *const envp[],
int flags) {
# if defined __NR_execveat && __NR_execveat >= 0
return syscall(__NR_execveat, dirfd, pathname, argv, envp, flags);
# else
errno = ENOSYS;
return -1;
# endif
}
# undef AT_EMPTY_PATH
# define AT_EMPTY_PATH 0x1000
# define execveat missing_execveat
#endif
/* ======================================================================= */
#define systemd_NR_close_range systemd_SC_arch_bias(436)

View File

@ -585,22 +585,53 @@ char* path_join_internal(const char *first, ...) {
return joined;
}
int find_executable_full(const char *name, bool use_path_envvar, char **ret) {
static int check_x_access(const char *path, int *ret_fd) {
if (ret_fd) {
_cleanup_close_ int fd = -1;
int r;
/* We need to use O_PATH because there may be executables for which we have only exec
* permissions, but not read (usually suid executables). */
fd = open(path, O_PATH|O_CLOEXEC);
if (fd < 0)
return -errno;
r = access_fd(fd, X_OK);
if (r < 0)
return r;
*ret_fd = TAKE_FD(fd);
} else {
/* Let's optimize things a bit by not opening the file if we don't need the fd. */
if (access(path, X_OK) < 0)
return -errno;
}
return 0;
}
int find_executable_full(const char *name, bool use_path_envvar, char **ret_filename, int *ret_fd) {
int last_error, r;
const char *p = NULL;
assert(name);
if (is_path(name)) {
if (access(name, X_OK) < 0)
return -errno;
_cleanup_close_ int fd = -1;
if (ret) {
r = path_make_absolute_cwd(name, ret);
r = check_x_access(name, ret_fd ? &fd : NULL);
if (r < 0)
return r;
if (ret_filename) {
r = path_make_absolute_cwd(name, ret_filename);
if (r < 0)
return r;
}
if (ret_fd)
*ret_fd = TAKE_FD(fd);
return 0;
}
@ -613,8 +644,10 @@ int find_executable_full(const char *name, bool use_path_envvar, char **ret) {
last_error = -ENOENT;
/* Resolve a single-component name to a full path */
for (;;) {
_cleanup_free_ char *j = NULL, *element = NULL;
_cleanup_close_ int fd = -1;
r = extract_first_word(&p, &element, ":", EXTRACT_RELAX|EXTRACT_DONT_COALESCE_SEPARATORS);
if (r < 0)
@ -629,7 +662,8 @@ int find_executable_full(const char *name, bool use_path_envvar, char **ret) {
if (!j)
return -ENOMEM;
if (access(j, X_OK) >= 0) {
r = check_x_access(j, ret_fd ? &fd : NULL);
if (r >= 0) {
_cleanup_free_ char *with_dash;
with_dash = strjoin(j, "/");
@ -643,8 +677,10 @@ int find_executable_full(const char *name, bool use_path_envvar, char **ret) {
/* We can't just `continue` inverting this case, since we need to update last_error. */
if (errno == ENOTDIR) {
/* Found it! */
if (ret)
*ret = path_simplify(TAKE_PTR(j), false);
if (ret_filename)
*ret_filename = path_simplify(TAKE_PTR(j), false);
if (ret_fd)
*ret_fd = TAKE_FD(fd);
return 0;
}

View File

@ -88,9 +88,9 @@ 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_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);
int find_executable_full(const char *name, bool use_path_envvar, char **ret_filename, int *ret_fd);
static inline int find_executable(const char *name, char **ret_filename) {
return find_executable_full(name, true, ret_filename, NULL);
}
bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool update);

View File

@ -452,10 +452,21 @@ size_t random_pool_size(void) {
}
int random_write_entropy(int fd, const void *seed, size_t size, bool credit) {
_cleanup_close_ int opened_fd = -1;
int r;
assert(fd >= 0);
assert(seed && size > 0);
assert(seed || size == 0);
if (size == 0)
return 0;
if (fd < 0) {
opened_fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY);
if (opened_fd < 0)
return -errno;
fd = opened_fd;
}
if (credit) {
_cleanup_free_ struct rand_pool_info *info = NULL;
@ -481,5 +492,5 @@ int random_write_entropy(int fd, const void *seed, size_t size, bool credit) {
return r;
}
return 0;
return 1;
}

View File

@ -193,8 +193,8 @@ int container_get_leader(const char *machine, pid_t *pid) {
}
int version(void) {
puts("systemd " STRINGIFY(PROJECT_VERSION) " (" GIT_VERSION ")\n"
SYSTEMD_FEATURES);
printf("systemd " STRINGIFY(PROJECT_VERSION) " (" GIT_VERSION ")\n%s\n",
systemd_features);
return 0;
}

View File

@ -49,7 +49,7 @@ static UnitFileFlags unit_file_bools_to_flags(bool runtime, bool force) {
BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_oom_policy, oom_policy, OOMPolicy);
static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_version, "s", GIT_VERSION);
static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_features, "s", SYSTEMD_FEATURES);
static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_features, "s", systemd_features);
static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_architecture, "s", architecture_to_string(uname_architecture()));
static BUS_DEFINE_PROPERTY_GET2(property_get_system_state, "s", Manager, manager_state, manager_state_to_string);
static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_timer_slack_nsec, "t", (uint64_t) prctl(PR_GET_TIMERSLACK));

View File

@ -43,7 +43,6 @@ static void lock_down_efi_variables(void) {
int efi_take_random_seed(void) {
_cleanup_free_ void *value = NULL;
_cleanup_close_ int random_fd = -1;
size_t size;
int r;
@ -77,17 +76,13 @@ int efi_take_random_seed(void) {
if (size == 0)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Random seed passed from boot loader has zero size? Ignoring.");
random_fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY);
if (random_fd < 0)
return log_warning_errno(errno, "Failed to open /dev/urandom for writing, ignoring: %m");
/* Before we use the seed, let's mark it as used, so that we never credit it twice. Also, it's a nice
* way to let users known that we successfully acquired entropy from the boot laoder. */
r = touch("/run/systemd/efi-random-seed-taken");
if (r < 0)
return log_warning_errno(r, "Unable to mark EFI random seed as used, not using it: %m");
r = random_write_entropy(random_fd, value, size, true);
r = random_write_entropy(-1, value, size, true);
if (r < 0)
return log_warning_errno(errno, "Failed to credit entropy, ignoring: %m");

View File

@ -1248,8 +1248,8 @@ static int setup_pam(
* termination */
barrier_set_role(&barrier, BARRIER_CHILD);
/* Make sure we don't keep open the passed fds in this child. We assume that otherwise only those fds
* are open here that have been opened by PAM. */
/* Make sure we don't keep open the passed fds in this child. We assume that otherwise only
* those fds are open here that have been opened by PAM. */
(void) close_many(fds, n_fds);
/* Drop privileges - we don't need any to pam_close_session
@ -2893,11 +2893,11 @@ static int setup_credentials(
#if ENABLE_SMACK
static int setup_smack(
const ExecContext *context,
const char *executable) {
int executable_fd) {
int r;
assert(context);
assert(executable);
assert(executable_fd >= 0);
if (context->smack_process_label) {
r = mac_smack_apply_pid(0, context->smack_process_label);
@ -2908,7 +2908,7 @@ static int setup_smack(
else {
_cleanup_free_ char *exec_label = NULL;
r = mac_smack_read(executable, SMACK_ATTR_EXEC, &exec_label);
r = mac_smack_read_fd(executable_fd, SMACK_ATTR_EXEC, &exec_label);
if (r < 0 && !IN_SET(r, -ENODATA, -EOPNOTSUPP))
return r;
@ -3419,7 +3419,6 @@ static int close_remaining_fds(
const DynamicCreds *dcreds,
int user_lookup_fd,
int socket_fd,
int exec_fd,
const int *fds, size_t n_fds) {
size_t n_dont_close = 0;
@ -3436,8 +3435,6 @@ static int close_remaining_fds(
if (socket_fd >= 0)
dont_close[n_dont_close++] = socket_fd;
if (exec_fd >= 0)
dont_close[n_dont_close++] = exec_fd;
if (n_fds > 0) {
memcpy(dont_close + n_dont_close, fds, sizeof(int) * n_fds);
n_dont_close += n_fds;
@ -3614,6 +3611,35 @@ bool exec_context_get_cpu_affinity_from_numa(const ExecContext *c) {
return c->cpu_affinity_from_numa;
}
static int add_shifted_fd(int *fds, size_t fds_size, size_t *n_fds, int fd, int *ret_fd) {
int r;
assert(fds);
assert(n_fds);
assert(*n_fds < fds_size);
assert(ret_fd);
if (fd < 0) {
*ret_fd = -1;
return 0;
}
if (fd < 3 + (int) *n_fds) {
/* Let's move the fd up, so that it's outside of the fd range we will use to store
* the fds we pass to the process (or which are closed only during execve). */
r = fcntl(fd, F_DUPFD_CLOEXEC, 3 + (int) *n_fds);
if (r < 0)
return -errno;
CLOSE_AND_REPLACE(fd, r);
}
*ret_fd = fds[*n_fds] = fd;
(*n_fds) ++;
return 1;
}
static int exec_child(
Unit *unit,
const ExecCommand *command,
@ -3631,7 +3657,7 @@ static int exec_child(
int *exit_status) {
_cleanup_strv_free_ char **our_env = NULL, **pass_env = NULL, **accum_env = NULL, **replaced_argv = NULL;
int *fds_with_exec_fd, n_fds_with_exec_fd, r, ngids = 0, exec_fd = -1;
int r, ngids = 0, exec_fd;
_cleanup_free_ gid_t *supplementary_gids = NULL;
const char *username = NULL, *groupname = NULL;
_cleanup_free_ char *home_buffer = NULL;
@ -3658,7 +3684,8 @@ static int exec_child(
gid_t saved_gid = getgid();
uid_t uid = UID_INVALID;
gid_t gid = GID_INVALID;
size_t n_fds;
size_t n_fds = n_socket_fds + n_storage_fds, /* fds to pass to the child */
n_keep_fds; /* total number of fds not to close */
int secure_bits;
_cleanup_free_ gid_t *gids_after_pam = NULL;
int ngids_after_pam = 0;
@ -3702,8 +3729,17 @@ static int exec_child(
/* In case anything used libc syslog(), close this here, too */
closelog();
n_fds = n_socket_fds + n_storage_fds;
r = close_remaining_fds(params, runtime, dcreds, user_lookup_fd, socket_fd, params->exec_fd, fds, n_fds);
int keep_fds[n_fds + 2];
memcpy_safe(keep_fds, fds, n_fds * sizeof(int));
n_keep_fds = n_fds;
r = add_shifted_fd(keep_fds, ELEMENTSOF(keep_fds), &n_keep_fds, params->exec_fd, &exec_fd);
if (r < 0) {
*exit_status = EXIT_FDS;
return log_unit_error_errno(unit, r, "Failed to shift fd and set FD_CLOEXEC: %m");
}
r = close_remaining_fds(params, runtime, dcreds, user_lookup_fd, socket_fd, keep_fds, n_keep_fds);
if (r < 0) {
*exit_status = EXIT_FDS;
return log_unit_error_errno(unit, r, "Failed to close unwanted file descriptors: %m");
@ -4095,6 +4131,7 @@ static int exec_child(
/* Let's call into PAM after we set up our own idea of resource limits to that pam_limits
* wins here. (See above.) */
/* All fds passed in the fds array will be closed in the pam child process. */
r = setup_pam(context->pam_name, username, uid, gid, context->tty_path, &accum_env, fds, n_fds);
if (r < 0) {
*exit_status = EXIT_PAM;
@ -4202,7 +4239,8 @@ static int exec_child(
* shall execute. */
_cleanup_free_ char *executable = NULL;
r = find_executable_full(command->path, false, &executable);
_cleanup_close_ int executable_fd = -1;
r = find_executable_full(command->path, false, &executable, &executable_fd);
if (r < 0) {
if (r != -ENOMEM && (command->flags & EXEC_COMMAND_IGNORE_FAILURE)) {
log_struct_errno(LOG_INFO, r,
@ -4225,6 +4263,12 @@ static int exec_child(
"EXECUTABLE=%s", command->path);
}
r = add_shifted_fd(keep_fds, ELEMENTSOF(keep_fds), &n_keep_fds, executable_fd, &executable_fd);
if (r < 0) {
*exit_status = EXIT_FDS;
return log_unit_error_errno(unit, r, "Failed to shift fd and set FD_CLOEXEC: %m");
}
#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);
@ -4239,41 +4283,7 @@ static int exec_child(
* 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(). */
if (params->exec_fd >= 0) {
exec_fd = params->exec_fd;
if (exec_fd < 3 + (int) n_fds) {
int moved_fd;
/* Let's move the exec fd far up, so that it's outside of the fd range we want to pass to the
* process we are about to execute. */
moved_fd = fcntl(exec_fd, F_DUPFD_CLOEXEC, 3 + (int) n_fds);
if (moved_fd < 0) {
*exit_status = EXIT_FDS;
return log_unit_error_errno(unit, errno, "Couldn't move exec fd up: %m");
}
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);
if (r < 0) {
*exit_status = EXIT_FDS;
return log_unit_error_errno(unit, r, "Failed to make exec fd FD_CLOEXEC: %m");
}
}
fds_with_exec_fd = newa(int, n_fds + 1);
memcpy_safe(fds_with_exec_fd, fds, n_fds * sizeof(int));
fds_with_exec_fd[n_fds] = exec_fd;
n_fds_with_exec_fd = n_fds + 1;
} else {
fds_with_exec_fd = fds;
n_fds_with_exec_fd = n_fds;
}
r = close_all_fds(fds_with_exec_fd, n_fds_with_exec_fd);
r = close_all_fds(keep_fds, n_keep_fds);
if (r >= 0)
r = shift_fds(fds, n_fds);
if (r >= 0)
@ -4307,7 +4317,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, executable);
r = setup_smack(context, executable_fd);
if (r < 0) {
*exit_status = EXIT_SMACK_PROCESS_LABEL;
return log_unit_error_errno(unit, r, "Failed to set SMACK process label: %m");
@ -4577,8 +4587,7 @@ static int exec_child(
}
}
execve(executable, final_argv, accum_env);
r = -errno;
r = fexecve_or_execve(executable_fd, executable, final_argv, accum_env);
if (exec_fd >= 0) {
uint8_t hot = 0;

View File

@ -1605,7 +1605,6 @@ static void apply_clock_update(void) {
}
static void cmdline_take_random_seed(void) {
_cleanup_close_ int random_fd = -1;
size_t suggested;
int r;
@ -1622,13 +1621,7 @@ static void cmdline_take_random_seed(void) {
log_warning("Random seed specified on kernel command line has size %zu, but %zu bytes required to fill entropy pool.",
arg_random_seed_size, suggested);
random_fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY);
if (random_fd < 0) {
log_warning_errno(errno, "Failed to open /dev/urandom for writing, ignoring: %m");
return;
}
r = random_write_entropy(random_fd, arg_random_seed, arg_random_seed_size, true);
r = random_write_entropy(-1, arg_random_seed, arg_random_seed_size, true);
if (r < 0) {
log_warning_errno(r, "Failed to credit entropy specified on kernel command line, ignoring: %m");
return;
@ -1987,8 +1980,9 @@ static void log_execution_mode(bool *ret_first_boot) {
if (arg_system) {
int v;
log_info("systemd " GIT_VERSION " running in %ssystem mode. (" SYSTEMD_FEATURES ")",
arg_action == ACTION_TEST ? "test " : "" );
log_info("systemd " GIT_VERSION " running in %ssystem mode. (%s)",
arg_action == ACTION_TEST ? "test " : "",
systemd_features);
v = detect_virtualization();
if (v > 0)
@ -2026,8 +2020,9 @@ static void log_execution_mode(bool *ret_first_boot) {
_cleanup_free_ char *t;
t = uid_to_name(getuid());
log_debug("systemd " GIT_VERSION " running in %suser mode for user " UID_FMT "/%s. (" SYSTEMD_FEATURES ")",
arg_action == ACTION_TEST ? " test" : "", getuid(), strna(t));
log_debug("systemd " GIT_VERSION " running in %suser mode for user " UID_FMT "/%s. (%s)",
arg_action == ACTION_TEST ? " test" : "",
getuid(), strna(t), systemd_features);
}
*ret_first_boot = false;

View File

@ -144,29 +144,35 @@ Address *address_free(Address *address) {
return mfree(address);
}
static bool address_may_have_broadcast(const Address *a) {
assert(a);
/* A /31 or /32 IPv4 address does not have a broadcast address.
* See https://tools.ietf.org/html/rfc3021 */
return a->family == AF_INET && in4_addr_is_null(&a->in_addr_peer.in) && a->prefixlen <= 30;
}
void address_hash_func(const Address *a, struct siphash *state) {
assert(a);
siphash24_compress(&a->family, sizeof(a->family), state);
switch (a->family) {
case AF_INET:
siphash24_compress(&a->broadcast, sizeof(a->broadcast), state);
if (!IN_SET(a->family, AF_INET, AF_INET6))
/* treat non-IPv4 or IPv6 address family as AF_UNSPEC */
return;
if (a->family == AF_INET)
siphash24_compress_string(a->label, state);
_fallthrough_;
case AF_INET6:
siphash24_compress(&a->prefixlen, sizeof(a->prefixlen), state);
/* local address */
siphash24_compress(&a->in_addr, FAMILY_ADDRESS_SIZE(a->family), state);
/* peer address */
siphash24_compress(&a->in_addr_peer, FAMILY_ADDRESS_SIZE(a->family), state);
siphash24_compress(&a->prefixlen, sizeof(a->prefixlen), state);
/* local address */
siphash24_compress(&a->in_addr, FAMILY_ADDRESS_SIZE(a->family), state);
/* peer address */
siphash24_compress(&a->in_addr_peer, FAMILY_ADDRESS_SIZE(a->family), state);
break;
default:
/* treat any other address family as AF_UNSPEC */
break;
}
if (address_may_have_broadcast(a))
siphash24_compress(&a->broadcast, sizeof(a->broadcast), state);
}
int address_compare_func(const Address *a1, const Address *a2) {
@ -176,32 +182,32 @@ int address_compare_func(const Address *a1, const Address *a2) {
if (r != 0)
return r;
switch (a1->family) {
/* use the same notion of equality as the kernel does */
case AF_INET:
r = CMP(a1->broadcast.s_addr, a2->broadcast.s_addr);
if (r != 0)
return r;
if (!IN_SET(a1->family, AF_INET, AF_INET6))
/* treat non-IPv4 or IPv6 address family as AF_UNSPEC */
return 0;
if (a1->family == AF_INET) {
r = strcmp_ptr(a1->label, a2->label);
if (r != 0)
return r;
_fallthrough_;
case AF_INET6:
r = CMP(a1->prefixlen, a2->prefixlen);
if (r != 0)
return r;
r = memcmp(&a1->in_addr, &a2->in_addr, FAMILY_ADDRESS_SIZE(a1->family));
if (r != 0)
return r;
return memcmp(&a1->in_addr_peer, &a2->in_addr_peer, FAMILY_ADDRESS_SIZE(a1->family));
default:
/* treat any other address family as AF_UNSPEC */
return 0;
}
r = CMP(a1->prefixlen, a2->prefixlen);
if (r != 0)
return r;
r = memcmp(&a1->in_addr, &a2->in_addr, FAMILY_ADDRESS_SIZE(a1->family));
if (r != 0)
return r;
r = memcmp(&a1->in_addr_peer, &a2->in_addr_peer, FAMILY_ADDRESS_SIZE(a1->family));
if (r != 0)
return r;
if (address_may_have_broadcast(a1))
return CMP(a1->broadcast.s_addr, a2->broadcast.s_addr);
return 0;
}
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(address_hash_ops, Address, address_hash_func, address_compare_func, address_free);
@ -222,18 +228,21 @@ static int address_copy(Address *dest, const Address *src) {
assert(dest);
assert(src);
r = free_and_strdup(&dest->label, src->label);
if (r < 0)
return r;
if (src->family == AF_INET) {
r = free_and_strdup(&dest->label, src->label);
if (r < 0)
return r;
}
dest->family = src->family;
dest->prefixlen = src->prefixlen;
dest->scope = src->scope;
dest->flags = src->flags;
dest->broadcast = src->broadcast;
dest->cinfo = src->cinfo;
dest->in_addr = src->in_addr;
dest->in_addr_peer = src->in_addr_peer;
if (address_may_have_broadcast(src))
dest->broadcast = src->broadcast;
dest->duplicate_address_detection = src->duplicate_address_detection;
return 0;
@ -840,13 +849,13 @@ int address_configure(
r = netlink_message_append_in_addr_union(req, IFA_ADDRESS, address->family, &address->in_addr_peer);
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFA_ADDRESS attribute: %m");
} else if (address->family == AF_INET && address->prefixlen <= 30) {
} else if (address_may_have_broadcast(address)) {
r = sd_netlink_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFA_BROADCAST attribute: %m");
}
if (address->label) {
if (address->family == AF_INET && address->label) {
r = sd_netlink_message_append_string(req, IFA_LABEL, address->label);
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFA_LABEL attribute: %m");
@ -1809,10 +1818,10 @@ static int address_section_verify(Address *address) {
address->section->filename, address->section->line);
}
if (address->family == AF_INET && in_addr_is_null(address->family, &address->in_addr_peer) &&
address->broadcast.s_addr == 0 && address->prefixlen <= 30)
address->broadcast.s_addr = address->in_addr.in.s_addr | htobe32(0xfffffffflu >> address->prefixlen);
else if (address->broadcast.s_addr != 0) {
if (address_may_have_broadcast(address)) {
if (address->broadcast.s_addr == 0)
address->broadcast.s_addr = address->in_addr.in.s_addr | htobe32(0xfffffffflu >> address->prefixlen);
} else if (address->broadcast.s_addr != 0) {
log_warning("%s: broadcast address is set for IPv6 address or IPv4 address with prefixlength larger than 30. "
"Ignoring Broadcast= setting in the [Address] section from line %u.",
address->section->filename, address->section->line);

View File

@ -865,7 +865,8 @@ static int dhcp4_update_address(Link *link, bool announce) {
addr->cinfo.ifa_prefered = lifetime;
addr->cinfo.ifa_valid = lifetime;
addr->prefixlen = prefixlen;
addr->broadcast.s_addr = address.s_addr | ~netmask.s_addr;
if (prefixlen <= 30)
addr->broadcast.s_addr = address.s_addr | ~netmask.s_addr;
SET_FLAG(addr->flags, IFA_F_NOPREFIXROUTE, !link_prefixroute(link));
/* allow reusing an existing address and simply update its lifetime

View File

@ -480,6 +480,21 @@ static int condition_test_ac_power(Condition *c, char **env) {
return (on_ac_power() != 0) == !!r;
}
static int has_tpm2(void) {
int r;
/* Checks whether the system has at least one TPM2 resource manager device, i.e. at least one "tpmrm"
* class device */
r = dir_is_empty("/sys/class/tpmrm");
if (r == -ENOENT)
return false;
if (r < 0)
return log_debug_errno(r, "Failed to determine whether system has TPM2 support: %m");
return !r;
}
static int condition_test_security(Condition *c, char **env) {
assert(c);
assert(c->parameter);
@ -499,6 +514,8 @@ static int condition_test_security(Condition *c, char **env) {
return mac_tomoyo_use();
if (streq(c->parameter, "uefi-secureboot"))
return is_efi_secure_boot();
if (streq(c->parameter, "tpm2"))
return has_tpm2();
return false;
}

View File

@ -11,11 +11,13 @@
#include "conf-files.h"
#include "env-file.h"
#include "env-util.h"
#include "errno-util.h"
#include "exec-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "hashmap.h"
#include "macro.h"
#include "missing_syscall.h"
#include "process-util.h"
#include "rlimit-util.h"
#include "serialize.h"
@ -33,7 +35,6 @@
assert_cc(EAGAIN == EWOULDBLOCK);
static int do_spawn(const char *path, char *argv[], int stdout_fd, pid_t *pid) {
pid_t _pid;
int r;
@ -444,3 +445,26 @@ ExecCommandFlags exec_command_flags_from_string(const char *s) {
else
return 1 << idx;
}
int fexecve_or_execve(int executable_fd, const char *executable, char *const argv[], char *const envp[]) {
#if ENABLE_FEXECVE
execveat(executable_fd, "", argv, envp, AT_EMPTY_PATH);
if (IN_SET(errno, ENOSYS, ENOENT) || ERRNO_IS_PRIVILEGE(errno))
/* Old kernel or a script or an overzealous seccomp filter? Let's fall back to execve().
*
* fexecve(3): "If fd refers to a script (i.e., it is an executable text file that names a
* script interpreter with a first line that begins with the characters #!) and the
* close-on-exec flag has been set for fd, then fexecve() fails with the error ENOENT. This
* error occurs because, by the time the script interpreter is executed, fd has already been
* closed because of the close-on-exec flag. Thus, the close-on-exec flag can't be set on fd
* if it refers to a script."
*
* Unfortunately, if we unset close-on-exec, the script will be executed just fine, but (at
* least in case of bash) the script name, $0, will be shown as /dev/fd/nnn, which breaks
* scripts which make use of $0. Thus, let's fall back to execve() in this case.
*/
#endif
execve(executable, argv, envp);
return -errno;
}

View File

@ -45,3 +45,5 @@ extern const gather_stdout_callback_t gather_environment[_STDOUT_CONSUME_MAX];
const char* exec_command_flags_to_string(ExecCommandFlags i);
ExecCommandFlags exec_command_flags_from_string(const char *s);
int fexecve_or_execve(int executable_fd, const char *executable, char *const argv[], char *const envp[]);

View File

@ -671,7 +671,6 @@ int pkcs11_token_acquire_rng(
CK_SESSION_HANDLE session) {
_cleanup_free_ void *buffer = NULL;
_cleanup_close_ int fd = -1;
size_t rps;
CK_RV rv;
int r;
@ -696,11 +695,7 @@ int pkcs11_token_acquire_rng(
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"Failed to generate RNG data on security token: %s", p11_kit_strerror(rv));
fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0)
return log_debug_errno(errno, "Failed to open /dev/urandom for writing: %m");
r = loop_write(fd, buffer, rps, false);
r = random_write_entropy(-1, buffer, rps, false);
if (r < 0)
return log_debug_errno(r, "Failed to write PKCS#11 acquired random data to /dev/urandom: %m");

View File

@ -18,7 +18,7 @@ static void test_is_wanted_print(bool header) {
assert_se(proc_cmdline(&cmdline) >= 0);
log_info("cmdline: %s", cmdline);
if (header) {
log_info(_CGROUP_HIERARCHY_);
log_info("default-hierarchy=" DEFAULT_HIERARCHY_NAME);
(void) system("findmnt -n /sys/fs/cgroup");
}

View File

@ -4,10 +4,12 @@
#include <unistd.h>
#include "alloc-util.h"
#include "exec-util.h"
#include "fd-util.h"
#include "macro.h"
#include "mountpoint-util.h"
#include "path-util.h"
#include "process-util.h"
#include "rm-rf.h"
#include "stat-util.h"
#include "string-util.h"
@ -169,12 +171,12 @@ static void test_find_executable_full(void) {
log_info("/* %s */", __func__);
assert_se(find_executable_full("sh", true, &p) == 0);
assert_se(find_executable_full("sh", true, &p, NULL) == 0);
puts(p);
assert_se(streq(basename(p), "sh"));
free(p);
assert_se(find_executable_full("sh", false, &p) == 0);
assert_se(find_executable_full("sh", false, &p, NULL) == 0);
puts(p);
assert_se(streq(basename(p), "sh"));
free(p);
@ -186,12 +188,12 @@ static void test_find_executable_full(void) {
assert_se(unsetenv("PATH") == 0);
assert_se(find_executable_full("sh", true, &p) == 0);
assert_se(find_executable_full("sh", true, &p, NULL) == 0);
puts(p);
assert_se(streq(basename(p), "sh"));
free(p);
assert_se(find_executable_full("sh", false, &p) == 0);
assert_se(find_executable_full("sh", false, &p, NULL) == 0);
puts(p);
assert_se(streq(basename(p), "sh"));
free(p);
@ -236,6 +238,43 @@ static void test_find_executable(const char *self) {
assert_se(find_executable("/proc/filesystems", &p) == -EACCES);
}
static void test_find_executable_exec_one(const char *path) {
_cleanup_free_ char *t = NULL;
_cleanup_close_ int fd = -1;
pid_t pid;
int r;
r = find_executable_full(path, false, &t, &fd);
log_info_errno(r, "%s: %s → %s: %d/%m", __func__, path, t ?: "-", fd);
assert_se(fd > STDERR_FILENO);
assert_se(path_is_absolute(t));
if (path_is_absolute(path))
assert_se(streq(t, path));
pid = fork();
assert_se(pid >= 0);
if (pid == 0) {
r = fexecve_or_execve(fd, t, STRV_MAKE(t, "--version"), STRV_MAKE(NULL));
log_error_errno(r, "[f]execve: %m");
_exit(EXIT_FAILURE);
}
assert_se(wait_for_terminate_and_check(t, pid, WAIT_LOG) == 0);
}
static void test_find_executable_exec(void) {
log_info("/* %s */", __func__);
test_find_executable_exec_one("touch");
test_find_executable_exec_one("/bin/touch");
_cleanup_free_ char *script = NULL;
assert_se(get_testdata_dir("test-path-util/script.sh", &script) >= 0);
test_find_executable_exec_one(script);
}
static void test_prefixes(void) {
static const char* const values[] = {
"/a/b/c/d",
@ -717,6 +756,7 @@ int main(int argc, char **argv) {
test_path_equal_root();
test_find_executable_full();
test_find_executable(argv[0]);
test_find_executable_exec();
test_prefixes();
test_path_join();
test_fsck_exists();

View File

@ -11,6 +11,8 @@ if install_tests
install_dir : testdata_dir)
install_subdir('test-path',
install_dir : testdata_dir)
install_subdir('test-path-util',
install_dir : testdata_dir)
install_subdir('test-umount',
install_dir : testdata_dir)
install_subdir('test-network-generator-conversion',

View File

@ -2,7 +2,7 @@
Description=Test for SystemCallFilter
[Service]
ExecStart=/bin/sh -c 'echo "This should not be seen"'
ExecStart=/bin/sh -c '/bin/echo "This should not be seen"'
Type=oneshot
LimitCORE=0
SystemCallFilter=ioperm

View File

@ -2,7 +2,7 @@
Description=Test for SystemCallFilter
[Service]
ExecStart=/bin/sh -c 'echo "This should not be seen"'
ExecStart=/bin/sh -c '/bin/echo "This should not be seen"'
Type=oneshot
LimitCORE=0
SystemCallFilter=~write open execve exit_group close mmap munmap fstat DONOTEXIST
SystemCallFilter=~write open execve fexecve execveat exit_group close mmap munmap fstat DONOTEXIST

6
test/test-path-util/script.sh Executable file
View File

@ -0,0 +1,6 @@
#!/bin/sh
echo "$0 $@"
test "$(basename $0)" = "script.sh" || exit 1
test "$1" = "--version" || exit 2
echo "Life is good"