Compare commits

...

16 Commits

Author SHA1 Message Date
Lennart Poettering 97033ba455 pager: set PR_DEATHSIG for pager to SIGINT rather than SIGTERM
"less" doesn't properly reset its terminal on SIGTERM, it does so only
on SIGINT. Let's thus configure SIGINT instead of SIGTERM.

I think this is something less should fix too, and clean up things
correctly on SIGTERM, too. However, given that we explicitly enable
SIGINT behaviour by passing "K" to $LESS I figure it makes sense if we
also send SIGINT instead of SIGTERM to match it.

Fixes: #16084
2020-06-10 10:31:22 +02:00
Lennart Poettering c85b6ff1b2 docs: point contributors to list of most recent systemd releases
Fixes: #16083
2020-06-10 10:30:02 +02:00
Zbigniew Jędrzejewski-Szmek 51b367b86d
Merge pull request #16111 from poettering/bitlck-fix
bitlocker cryptsetup fix
2020-06-10 10:25:36 +02:00
Zbigniew Jędrzejewski-Szmek 9664be199a
Merge pull request #16118 from poettering/inaccessible-fixlets
move $XDG_RUNTIME_DIR/inaccessible/ to $XDG_RUNTIME_DIR/systemd/inaccessible
2020-06-10 10:23:13 +02:00
Zbigniew Jędrzejewski-Szmek 2befe404d4
Merge pull request #16120 from poettering/udevd-fixlets
minor udev fixlets
2020-06-10 10:18:36 +02:00
Zbigniew Jędrzejewski-Szmek 02939ee001
Merge pull request #16087 from mrc0mmand/travis-build-check
travis: check build with various compiler options
2020-06-10 09:06:14 +02:00
Lennart Poettering dad28bffd6 tree-wide: check POLLNVAL everywhere
poll() sets POLLNVAL inside of the poll structures if an invalid fd is
passed. So far we generally didn't check for that, thus not taking
notice of the error. Given that this specific kind of error is generally
indication of a programming error, and given that our code is embedded
into our projects via NSS or because people link against our library,
let's explicitly check for this and convert it to EBADF.

(I ran into a busy loop because of this missing check when some of my
test code accidentally closed an fd it shouldn't close, so this is a
real thing)
2020-06-10 08:57:31 +02:00
Frantisek Sumsal dfa64b64a7 tree-wide: mark assert()-only variables as unused
to make a compilation with -Db_ndebug=true and --werror pass once again.
2020-06-09 21:31:10 +02:00
Frantisek Sumsal b36746c90e travis: check build with various compiler options
In the past we occasionally stumbled upon a build issue which could be
reproduced only with specific optimization level or other compilation
option. Let's try to build the current revision with several most common
compiler options causing such issues to catch them early.
2020-06-09 21:27:07 +02:00
Lennart Poettering 48b747fa03 inaccessible: move inaccessible file nodes to /systemd/ subdir in runtime dir always
Let's make sure $XDG_RUNTIME_DIR for the user instance and /run for the
system instance is always organized the same way: the "inaccessible"
device nodes should be placed in a subdir of either called "systemd" and
a subdir of that called "inaccessible".

This way we can emphasize the common behaviour, and only differ where
really necessary.

Follow-up for #13823
2020-06-09 16:23:56 +02:00
Lennart Poettering b8c9074534 login: use ERRNO_IS_PRIVILEGE() where appropriate 2020-06-09 16:13:51 +02:00
Lennart Poettering d582afe144 mkdir: use log_full_errno() where appropriate 2020-06-09 16:13:16 +02:00
Lennart Poettering 6b2229c6c6 udev: set fewer process properties
On systemd systems we generally don't need to chdir() to root, we don't
need to setup /dev/ ourselves (as PID 1 does that during earliest boot),
and we don't need to set the OOM adjustment values, as that's done via
unit files.

Hence, drop this. if people want to use udev from other init systems
they should do this on their own, I am very sure it's a good thing to do
it from outside of udevd, so that fewer privileges are required by udevd. In
particular the dev_setup() stuff is something that people who build
their own non-systemd distros want to set up themselves anyway, in
particular as they already have to mount devtmpfs themselves anyway.

Note that this only drops stuff that isn't really necessary for testing
stuff, i.e. process properties and settings that don't matter if you
quickly want to invoke udev from a terminal session to test something.
2020-06-09 15:40:20 +02:00
Lennart Poettering fe56acd8e0 udevd: use cpus_in_affinity_mask()
Let's make use of our own helpers. This has the benefit that we can deal
with arbitrarily sized affinity masks.
2020-06-09 15:39:53 +02:00
Lennart Poettering 6930d069a3 cryptsetup: pass selected mode to crypt_load() when doing LUKS
This doesn't fix anything IRL, but is a bit cleaner, since it makes sure
that arg_type is properly passed to crypt_load() in all cases.

We actually never set arg_type to CRYPT_LUKS2, which is why this wasn't
noticed before, but theoretically this might change one day, and
existing comments suggest it as possible value for arg_type, hence let's
process it properly.
2020-06-09 14:24:21 +02:00
Lennart Poettering 5af39ac850 cryptsetup: try to load bitlocker superblock only if requested
let's do automatic discovery only for our native LUKS/LUKS2 headers,
since they are Linux stuff, and let's require that BitLocker to be
requested explicitly.

This makes sure cryptsetup without either "luks" nor "bitlk" in the
option string will work. Right now it would fail because we'd load the
superblock once with luks and once with bitlk and one of them would
necessarily fail.

Follow-up for #15979
2020-06-09 14:24:15 +02:00
37 changed files with 338 additions and 143 deletions

View File

@ -7,7 +7,8 @@ about: A report of an error in a recent systemd version
**systemd version the issue has been seen with**
> ...
<!-- **NOTE:** Do not submit bug reports about anything but the two most recently released systemd versions upstream! -->
<!-- **NOTE:** Do not submit bug reports about anything but the two most recently released (non-rc) systemd versions upstream! -->
<!-- See https://github.com/systemd/systemd/releases for the list of most recent releases. -->
<!-- For older version please use distribution trackers (see https://systemd.io/CONTRIBUTING#filing-issues). -->
**Used distribution**

View File

@ -11,6 +11,9 @@ env:
- REPO_ROOT="$TRAVIS_BUILD_DIR"
stages:
- name: Build check
if: type != cron
- name: Build & test
if: type != cron
@ -20,6 +23,45 @@ stages:
jobs:
include:
- stage: Build check
name: Fedora Rawhide (gcc)
language: bash
env:
- FEDORA_RELEASE="rawhide"
- CONT_NAME="systemd-fedora-$FEDORA_RELEASE"
- DOCKER_EXEC="docker exec -ti $CONT_NAME"
before_install:
- sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
- docker --version
install:
- $CI_MANAGERS/fedora.sh SETUP
script:
- set -e
# Build systemd
- $CI_MANAGERS/fedora.sh RUN_BUILD_CHECK_GCC
- set +e
after_script:
- $CI_MANAGERS/fedora.sh CLEANUP
- name: Fedora Rawhide (clang)
language: bash
env:
- FEDORA_RELEASE="rawhide"
- CONT_NAME="systemd-fedora-$FEDORA_RELEASE"
- DOCKER_EXEC="docker exec -ti $CONT_NAME"
before_install:
- sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
- docker --version
install:
- $CI_MANAGERS/fedora.sh SETUP
script:
- set -e
# Build systemd
- $CI_MANAGERS/fedora.sh RUN_BUILD_CHECK_CLANG
- set +e
after_script:
- $CI_MANAGERS/fedora.sh CLEANUP
- stage: Build & test
name: Debian Testing
language: bash

View File

@ -11,7 +11,7 @@ We welcome contributions from everyone. However, please follow the following gui
## Filing Issues
* We use [GitHub Issues](https://github.com/systemd/systemd/issues) **exclusively** for tracking **bugs** and **feature** **requests** of systemd. If you are looking for help, please contact [systemd-devel mailing list](https://lists.freedesktop.org/mailman/listinfo/systemd-devel) instead.
* We only track bugs in the **two** **most** **recently** **released** **versions** of systemd in the GitHub Issue tracker. If you are using an older version of systemd, please contact your distribution's bug tracker instead.
* We only track bugs in the **two** **most** **recently** **released** (non-rc) **versions** of systemd in the GitHub Issue tracker. If you are using an older version of systemd, please contact your distribution's bug tracker instead (see below). See [GitHub Release Page](https://github.com/systemd/systemd/releases) for the list of most recent releases.
* When filing an issue, specify the **systemd** **version** you are experiencing the issue with. Also, indicate which **distribution** you are using.
* Please include an explanation how to reproduce the issue you are pointing out.

View File

@ -33,10 +33,13 @@ int flush_fd(int fd) {
continue;
return -errno;
} else if (r == 0)
}
if (r == 0)
return count;
if (pollfd.revents & POLLNVAL)
return -EBADF;
l = read(fd, buf, sizeof(buf));
if (l < 0) {
@ -169,6 +172,9 @@ int pipe_eof(int fd) {
if (r == 0)
return 0;
if (pollfd.revents & POLLNVAL)
return -EBADF;
return pollfd.revents & POLLHUP;
}
@ -188,6 +194,9 @@ int fd_wait_for_event(int fd, int event, usec_t t) {
if (r == 0)
return 0;
if (pollfd.revents & POLLNVAL)
return -EBADF;
return pollfd.revents;
}

View File

@ -14,11 +14,18 @@
#include "stdio-util.h"
#include "user-util.h"
int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdir_func_t _mkdir) {
int mkdir_safe_internal(
const char *path,
mode_t mode,
uid_t uid, gid_t gid,
MkdirFlags flags,
mkdir_func_t _mkdir) {
struct stat st;
int r;
assert(_mkdir != mkdir);
assert(path);
assert(_mkdir && _mkdir != mkdir);
if (_mkdir(path, mode) >= 0) {
r = chmod_and_chown(path, mode, uid, gid);
@ -44,19 +51,16 @@ int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, Mkd
return -errno;
}
if (!S_ISDIR(st.st_mode)) {
log_full(flags & MKDIR_WARN_MODE ? LOG_WARNING : LOG_DEBUG,
"Path \"%s\" already exists and is not a directory, refusing.", path);
return -ENOTDIR;
}
if (!S_ISDIR(st.st_mode))
return log_full_errno(flags & MKDIR_WARN_MODE ? LOG_WARNING : LOG_DEBUG, SYNTHETIC_ERRNO(ENOTDIR),
"Path \"%s\" already exists and is not a directory, refusing.", path);
if ((st.st_mode & 0007) > (mode & 0007) ||
(st.st_mode & 0070) > (mode & 0070) ||
(st.st_mode & 0700) > (mode & 0700)) {
log_full(flags & MKDIR_WARN_MODE ? LOG_WARNING : LOG_DEBUG,
"Directory \"%s\" already exists, but has mode %04o that is too permissive (%04o was requested), refusing.",
path, st.st_mode & 0777, mode);
return -EEXIST;
}
(st.st_mode & 0700) > (mode & 0700))
return log_full_errno(flags & MKDIR_WARN_MODE ? LOG_WARNING : LOG_DEBUG, SYNTHETIC_ERRNO(EEXIST),
"Directory \"%s\" already exists, but has mode %04o that is too permissive (%04o was requested), refusing.",
path, st.st_mode & 0777, mode);
if ((uid != UID_INVALID && st.st_uid != uid) ||
(gid != GID_INVALID && st.st_gid != gid)) {
char u[DECIMAL_STR_MAX(uid_t)] = "-", g[DECIMAL_STR_MAX(gid_t)] = "-";
@ -65,10 +69,9 @@ int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, Mkd
xsprintf(u, UID_FMT, uid);
if (gid != UID_INVALID)
xsprintf(g, GID_FMT, gid);
log_full(flags & MKDIR_WARN_MODE ? LOG_WARNING : LOG_DEBUG,
"Directory \"%s\" already exists, but is owned by "UID_FMT":"GID_FMT" (%s:%s was requested), refusing.",
path, st.st_uid, st.st_gid, u, g);
return -EEXIST;
return log_full_errno(flags & MKDIR_WARN_MODE ? LOG_WARNING : LOG_DEBUG, SYNTHETIC_ERRNO(EEXIST),
"Directory \"%s\" already exists, but is owned by "UID_FMT":"GID_FMT" (%s:%s was requested), refusing.",
path, st.st_uid, st.st_gid, u, g);
}
return 0;

View File

@ -1301,8 +1301,8 @@ int safe_fork_full(
r, "Failed to rename process, ignoring: %m");
}
if (flags & FORK_DEATHSIG)
if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0) {
if (flags & (FORK_DEATHSIG|FORK_DEATHSIG_SIGINT))
if (prctl(PR_SET_PDEATHSIG, (flags & FORK_DEATHSIG_SIGINT) ? SIGINT : SIGTERM) < 0) {
log_full_errno(prio, errno, "Failed to set death signal: %m");
_exit(EXIT_FAILURE);
}

View File

@ -150,15 +150,16 @@ int must_be_root(void);
typedef enum ForkFlags {
FORK_RESET_SIGNALS = 1 << 0, /* Reset all signal handlers and signal mask */
FORK_CLOSE_ALL_FDS = 1 << 1, /* Close all open file descriptors in the child, except for 0,1,2 */
FORK_DEATHSIG = 1 << 2, /* Set PR_DEATHSIG in the child */
FORK_NULL_STDIO = 1 << 3, /* Connect 0,1,2 to /dev/null */
FORK_REOPEN_LOG = 1 << 4, /* Reopen log connection */
FORK_LOG = 1 << 5, /* Log above LOG_DEBUG log level about failures */
FORK_WAIT = 1 << 6, /* Wait until child exited */
FORK_NEW_MOUNTNS = 1 << 7, /* Run child in its own mount namespace */
FORK_MOUNTNS_SLAVE = 1 << 8, /* Make child's mount namespace MS_SLAVE */
FORK_RLIMIT_NOFILE_SAFE = 1 << 9, /* Set RLIMIT_NOFILE soft limit to 1K for select() compat */
FORK_STDOUT_TO_STDERR = 1 << 10, /* Make stdout a copy of stderr */
FORK_DEATHSIG = 1 << 2, /* Set PR_DEATHSIG in the child to SIGTERM */
FORK_DEATHSIG_SIGINT = 1 << 3, /* Set PR_DEATHSIG in the child to SIGINT */
FORK_NULL_STDIO = 1 << 4, /* Connect 0,1,2 to /dev/null */
FORK_REOPEN_LOG = 1 << 5, /* Reopen log connection */
FORK_LOG = 1 << 6, /* Log above LOG_DEBUG log level about failures */
FORK_WAIT = 1 << 7, /* Wait until child exited */
FORK_NEW_MOUNTNS = 1 << 8, /* Run child in its own mount namespace */
FORK_MOUNTNS_SLAVE = 1 << 9, /* Make child's mount namespace MS_SLAVE */
FORK_RLIMIT_NOFILE_SAFE = 1 << 10, /* Set RLIMIT_NOFILE soft limit to 1K for select() compat */
FORK_STDOUT_TO_STDERR = 1 << 11, /* Make stdout a copy of stderr */
} ForkFlags;
int safe_fork_full(const char *name, const int except_fds[], size_t n_except_fds, ForkFlags flags, pid_t *ret_pid);

View File

@ -1002,6 +1002,9 @@ int flush_accept(int fd) {
if (r == 0)
return 0;
if (pollfd.revents & POLLNVAL)
return -EBADF;
if (iteration >= MAX_FLUSH_ITERATIONS)
return log_debug_errno(SYNTHETIC_ERRNO(EBUSY),
"Failed to flush connections within " STRINGIFY(MAX_FLUSH_ITERATIONS) " iterations.");

View File

@ -347,7 +347,7 @@ static int property_set_kexec_watchdog(
void *userdata,
sd_bus_error *error) {
Manager *m = userdata;
_unused_ Manager *m = userdata;
assert(m);
assert(bus);

View File

@ -535,9 +535,9 @@ int mount_setup(bool loaded_policy, bool leave_propagation) {
(void) mkdir_label("/run/systemd", 0755);
(void) mkdir_label("/run/systemd/system", 0755);
/* Also create /run/systemd/inaccessible nodes, so that we always have something to mount inaccessible nodes
* from. */
(void) make_inaccessible_nodes("/run/systemd", UID_INVALID, GID_INVALID);
/* Also create /run/systemd/inaccessible nodes, so that we always have something to mount
* inaccessible nodes from. */
(void) make_inaccessible_nodes(NULL, UID_INVALID, GID_INVALID);
return 0;
}

View File

@ -939,10 +939,10 @@ static int apply_mount(
}
if (geteuid() == 0)
runtime_dir = "/run/systemd";
runtime_dir = "/run";
else {
if (asprintf(&tmp, "/run/user/"UID_FMT, geteuid()) < 0)
log_oom();
if (asprintf(&tmp, "/run/user/" UID_FMT, geteuid()) < 0)
return -ENOMEM;
runtime_dir = tmp;
}

View File

@ -932,8 +932,8 @@ static int run(int argc, char *argv[]) {
log_warning("Key file %s is world-readable. This is not a good idea!", key_file);
}
if (!arg_type || STR_IN_SET(arg_type, ANY_LUKS, CRYPT_LUKS1)) {
r = crypt_load(cd, CRYPT_LUKS, NULL);
if (!arg_type || STR_IN_SET(arg_type, ANY_LUKS, CRYPT_LUKS1, CRYPT_LUKS2)) {
r = crypt_load(cd, !arg_type || streq(arg_type, ANY_LUKS) ? CRYPT_LUKS : arg_type, NULL);
if (r < 0)
return log_error_errno(r, "Failed to load LUKS superblock on device %s: %m", crypt_get_device_name(cd));
@ -957,7 +957,7 @@ static int run(int argc, char *argv[]) {
/* since cryptsetup 2.3.0 (Feb 2020) */
#ifdef CRYPT_BITLK
if (!arg_type || STR_IN_SET(arg_type, ANY_LUKS, CRYPT_BITLK)) {
if (streq_ptr(arg_type, CRYPT_BITLK)) {
r = crypt_load(cd, CRYPT_BITLK, NULL);
if (r < 0)
return log_error_errno(r, "Failed to load Bitlocker superblock on device %s: %m", crypt_get_device_name(cd));

View File

@ -96,7 +96,7 @@ _public_ int sd_journal_printv(int priority, const char *format, va_list ap) {
/* Allocate large buffer to accommodate big message */
if (len >= LINE_MAX) {
int rlen;
_unused_ int rlen;
buffer = alloca(len + 9);
memcpy(buffer, "MESSAGE=", 8);
rlen = vsnprintf(buffer + 8, len + 1, format, ap);
@ -474,7 +474,7 @@ _public_ int sd_journal_printv_with_location(int priority, const char *file, con
/* Allocate large buffer to accommodate big message */
if (len >= LINE_MAX) {
int rlen;
_unused_ int rlen;
buffer = alloca(len + 9);
memcpy(buffer, "MESSAGE=", 8);
rlen = vsnprintf(buffer + 8, len + 1, format, ap);

View File

@ -2093,10 +2093,13 @@ static int wait_for_change(sd_journal *j, int poll_fd) {
return log_error_errno(errno, "Couldn't wait for journal event: %m");
}
if (pollfds[1].revents & (POLLHUP|POLLERR)) /* STDOUT has been closed? */
if (pollfds[1].revents & (POLLHUP|POLLERR|POLLNVAL)) /* STDOUT has been closed? */
return log_debug_errno(SYNTHETIC_ERRNO(ECANCELED),
"Standard output has been closed.");
if (pollfds[0].revents & POLLNVAL)
return log_debug_errno(SYNTHETIC_ERRNO(EBADF), "Change fd closed?");
r = sd_journal_process(j);
if (r < 0)
return log_error_errno(r, "Failed to process journal events: %m");

View File

@ -1275,6 +1275,8 @@ int bus_socket_process_opening(sd_bus *b) {
r = poll(&p, 1, 0);
if (r < 0)
return -errno;
if (p.revents & POLLNVAL)
return -EBADF;
if (!(p.revents & (POLLOUT|POLLERR|POLLHUP)))
return 0;

View File

@ -3121,8 +3121,15 @@ static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec) {
r = ppoll(p, n, m == USEC_INFINITY ? NULL : timespec_store(&ts, m), NULL);
if (r < 0)
return -errno;
if (r == 0)
return 0;
return r > 0 ? 1 : 0;
if (p[0].revents & POLLNVAL)
return -EBADF;
if (n >= 2 && (p[1].revents & POLLNVAL))
return -EBADF;
return 1;
}
_public_ int sd_bus_wait(sd_bus *bus, uint64_t timeout_usec) {

View File

@ -577,6 +577,8 @@ _public_ int sd_notify_barrier(int unset_environment, uint64_t timeout) {
return -errno;
if (r == 0)
return -ETIMEDOUT;
if (pfd.revents & POLLNVAL)
return -EBADF;
return 1;
}

View File

@ -462,7 +462,6 @@ static usec_t calc_elapse(uint64_t usec) {
}
static int rtnl_poll(sd_netlink *rtnl, bool need_more, uint64_t timeout_usec) {
struct pollfd p[1] = {};
struct timespec ts;
usec_t m = USEC_INFINITY;
int r, e;
@ -495,14 +494,21 @@ static int rtnl_poll(sd_netlink *rtnl, bool need_more, uint64_t timeout_usec) {
if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
m = timeout_usec;
p[0].fd = rtnl->fd;
p[0].events = e;
struct pollfd p = {
.fd = rtnl->fd,
.events = e,
};
r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
r = ppoll(&p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
if (r < 0)
return -errno;
if (r == 0)
return 0;
return r > 0 ? 1 : 0;
if (p.revents & POLLNVAL)
return -EBADF;
return 1;
}
int sd_netlink_wait(sd_netlink *nl, uint64_t timeout_usec) {

View File

@ -216,8 +216,11 @@ static int udev_monitor_receive_sd_device(struct udev_monitor *udev_monitor, sd_
continue;
return -errno;
} else if (r == 0)
}
if (r == 0)
return -EAGAIN;
if (pfd.revents & POLLNVAL)
return -EBADF;
/* receive next message */
break;

View File

@ -78,7 +78,7 @@ static int user_mkdir_runtime_path(
r = mount("tmpfs", runtime_path, "tmpfs", MS_NODEV|MS_NOSUID, options);
if (r < 0) {
if (!IN_SET(errno, EPERM, EACCES)) {
if (!ERRNO_IS_PRIVILEGE(errno)) {
r = log_error_errno(errno, "Failed to mount per-user tmpfs directory %s: %m", runtime_path);
goto fail;
}

View File

@ -898,7 +898,7 @@ static int mount_inaccessible(const char *dest, CustomMount *m) {
return m->graceful ? 0 : r;
}
r = mode_to_inaccessible_node("/run/systemd", st.st_mode, &source);
r = mode_to_inaccessible_node(NULL, st.st_mode, &source);
if (r < 0)
return m->graceful ? 0 : r;

View File

@ -3482,7 +3482,7 @@ static int outer_child(
(void) dev_setup(directory, arg_uid_shift, arg_uid_shift);
p = prefix_roota(directory, "/run/systemd");
p = prefix_roota(directory, "/run");
(void) make_inaccessible_nodes(p, arg_uid_shift, arg_uid_shift);
r = setup_pts(directory);

View File

@ -305,6 +305,12 @@ int ask_password_plymouth(
goto finish;
}
if (pollfd[POLL_SOCKET].revents & POLLNVAL ||
(notify >= 0 && pollfd[POLL_INOTIFY].revents & POLLNVAL)) {
r = -EBADF;
goto finish;
}
if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0)
(void) flush_fd(notify);
@ -541,6 +547,12 @@ int ask_password_tty(
goto finish;
}
if ((pollfd[POLL_TTY].revents & POLLNVAL) ||
(notify >= 0 && (pollfd[POLL_INOTIFY].revents & POLLNVAL))) {
r = -EBADF;
goto finish;
}
if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0 && keyname) {
(void) flush_fd(notify);
@ -888,6 +900,13 @@ int ask_password_agent(
goto finish;
}
if (pollfd[FD_SOCKET].revents & POLLNVAL ||
pollfd[FD_SIGNAL].revents & POLLNVAL ||
(notify >= 0 && pollfd[FD_INOTIFY].revents & POLLNVAL)) {
r = -EBADF;
goto finish;
}
if (pollfd[FD_SIGNAL].revents & POLLIN) {
r = -EINTR;
goto finish;

View File

@ -218,10 +218,14 @@ static bool barrier_read(Barrier *b, int64_t comp) {
uint64_t buf;
int r;
r = poll(pfd, 2, -1);
if (r < 0 && IN_SET(errno, EAGAIN, EINTR))
continue;
else if (r < 0)
r = poll(pfd, ELEMENTSOF(pfd), -1);
if (r < 0) {
if (IN_SET(errno, EAGAIN, EINTR))
continue;
goto error;
}
if (pfd[0].revents & POLLNVAL ||
pfd[1].revents & POLLNVAL)
goto error;
if (pfd[1].revents) {

View File

@ -56,31 +56,38 @@ int dev_setup(const char *prefix, uid_t uid, gid_t gid) {
return 0;
}
int make_inaccessible_nodes(const char *root, uid_t uid, gid_t gid) {
int make_inaccessible_nodes(
const char *runtime_dir,
uid_t uid,
gid_t gid) {
static const struct {
const char *name;
mode_t mode;
} table[] = {
{ "", S_IFDIR | 0755 },
{ "/inaccessible", S_IFDIR | 0000 },
{ "/inaccessible/reg", S_IFREG | 0000 },
{ "/inaccessible/dir", S_IFDIR | 0000 },
{ "/inaccessible/fifo", S_IFIFO | 0000 },
{ "/inaccessible/sock", S_IFSOCK | 0000 },
{ "/systemd", S_IFDIR | 0755 },
{ "/systemd/inaccessible", S_IFDIR | 0000 },
{ "/systemd/inaccessible/reg", S_IFREG | 0000 },
{ "/systemd/inaccessible/dir", S_IFDIR | 0000 },
{ "/systemd/inaccessible/fifo", S_IFIFO | 0000 },
{ "/systemd/inaccessible/sock", S_IFSOCK | 0000 },
/* The following two are likely to fail if we lack the privs for it (for example in an userns
* environment, if CAP_SYS_MKNOD is missing, or if a device node policy prohibit major/minor of 0
* device nodes to be created). But that's entirely fine. Consumers of these files should carry
* fallback to use a different node then, for example <root>/inaccessible/sock, which is close
* enough in behaviour and semantics for most uses. */
{ "/inaccessible/chr", S_IFCHR | 0000 },
{ "/inaccessible/blk", S_IFBLK | 0000 },
{ "/systemd/inaccessible/chr", S_IFCHR | 0000 },
{ "/systemd/inaccessible/blk", S_IFBLK | 0000 },
};
_cleanup_umask_ mode_t u;
size_t i;
int r;
if (!runtime_dir)
runtime_dir = "/run";
u = umask(0000);
/* Set up inaccessible (and empty) file nodes of all types. This are used to as mount sources for over-mounting
@ -91,7 +98,7 @@ int make_inaccessible_nodes(const char *root, uid_t uid, gid_t gid) {
for (i = 0; i < ELEMENTSOF(table); i++) {
_cleanup_free_ char *path = NULL;
path = path_join(root, table[i].name);
path = path_join(runtime_dir, table[i].name);
if (!path)
return log_oom();

View File

@ -397,71 +397,73 @@ int repeat_unmount(const char *path, int flags) {
}
}
int mode_to_inaccessible_node(const char *runtime_dir, mode_t mode, char **dest) {
/* This function maps a node type to a corresponding inaccessible file node. These nodes are created during
* early boot by PID 1. In some cases we lacked the privs to create the character and block devices (maybe
* because we run in an userns environment, or miss CAP_SYS_MKNOD, or run with a devices policy that excludes
* device nodes with major and minor of 0), but that's fine, in that case we use an AF_UNIX file node instead,
* which is not the same, but close enough for most uses. And most importantly, the kernel allows bind mounts
* from socket nodes to any non-directory file nodes, and that's the most important thing that matters. */
int mode_to_inaccessible_node(
const char *runtime_dir,
mode_t mode,
char **ret) {
/* This function maps a node type to a corresponding inaccessible file node. These nodes are created
* during early boot by PID 1. In some cases we lacked the privs to create the character and block
* devices (maybe because we run in an userns environment, or miss CAP_SYS_MKNOD, or run with a
* devices policy that excludes device nodes with major and minor of 0), but that's fine, in that
* case we use an AF_UNIX file node instead, which is not the same, but close enough for most
* uses. And most importantly, the kernel allows bind mounts from socket nodes to any non-directory
* file nodes, and that's the most important thing that matters.
*
* Note that the runtime directory argument shall be the top-level runtime directory, i.e. /run/ if
* we operate in system context and $XDG_RUNTIME_DIR if we operate in user context. */
_cleanup_free_ char *d = NULL;
const char *node = NULL;
char *tmp;
bool fallback = false;
assert(dest);
assert(ret);
if (!runtime_dir)
runtime_dir = "/run";
switch(mode & S_IFMT) {
case S_IFREG:
node = "/inaccessible/reg";
node = "/systemd/inaccessible/reg";
break;
case S_IFDIR:
node = "/inaccessible/dir";
node = "/systemd/inaccessible/dir";
break;
case S_IFCHR:
d = path_join(runtime_dir, "/inaccessible/chr");
if (!d)
return log_oom();
if (access(d, F_OK) == 0) {
*dest = TAKE_PTR(d);
return 0;
}
node = "/inaccessible/sock";
node = "/systemd/inaccessible/chr";
fallback = true;
break;
case S_IFBLK:
d = path_join(runtime_dir, "/inaccessible/blk");
if (!d)
return log_oom();
if (access(d, F_OK) == 0) {
*dest = TAKE_PTR(d);
return 0;
}
node = "/inaccessible/sock";
node = "/systemd/inaccessible/blk";
fallback = true;
break;
case S_IFIFO:
node = "/inaccessible/fifo";
node = "/systemd/inaccessible/fifo";
break;
case S_IFSOCK:
node = "/inaccessible/sock";
node = "/systemd/inaccessible/sock";
break;
}
if (!node)
return -EINVAL;
tmp = path_join(runtime_dir, node);
if (!tmp)
return log_oom();
d = path_join(runtime_dir, node);
if (!d)
return -ENOMEM;
*dest = tmp;
if (fallback && access(d, F_OK) < 0) {
free(d);
d = path_join(runtime_dir, "/systemd/inaccessible/sock");
if (!d)
return -ENOMEM;
}
*ret = TAKE_PTR(d);
return 0;
}

View File

@ -131,7 +131,8 @@ int pager_open(PagerFlags flags) {
if (flags & PAGER_JUMP_TO_END)
less_opts = strjoina(less_opts, " +G");
r = safe_fork("(pager)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pager_pid);
/* We set SIGINT as PR_DEATHSIG signal here, to match the "K" parameter we set in $LESS, which enables SIGINT behaviour. */
r = safe_fork("(pager)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGINT|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pager_pid);
if (r < 0)
return r;
if (r == 0) {

View File

@ -334,9 +334,10 @@ static int write_to_terminal(const char *tty, const char *message) {
k = poll(&pollfd, 1, (end - t) / USEC_PER_MSEC);
if (k < 0)
return -errno;
if (k == 0)
return -ETIME;
if (pollfd.revents & POLLNVAL)
return -EBADF;
n = write(fd, p, left);
if (n < 0) {

View File

@ -1048,10 +1048,14 @@ int varlink_wait(Varlink *v, usec_t timeout) {
NULL);
if (r < 0)
return -errno;
if (r == 0)
return 0;
if (pfd.revents & POLLNVAL)
return -EBADF;
handle_revents(v, pfd.revents);
return r > 0 ? 1 : 0;
return 1;
}
int varlink_get_fd(Varlink *v) {
@ -1139,9 +1143,14 @@ int varlink_flush(Varlink *v) {
.events = POLLOUT,
};
if (poll(&pfd, 1, -1) < 0)
r = poll(&pfd, 1, -1);
if (r < 0)
return -errno;
assert(r > 0);
if (pfd.revents & POLLNVAL)
return -EBADF;
handle_revents(v, pfd.revents);
}

View File

@ -271,6 +271,9 @@ static int execute_s2h(const SleepConfig *sleep_config) {
tfd = safe_close(tfd);
if (FLAGS_SET(fds.revents, POLLNVAL))
return log_error_errno(SYNTHETIC_ERRNO(EBADF), "Invalid timer fd to sleep on?");
if (!FLAGS_SET(fds.revents, POLLIN)) /* We woke up before the alarm time, we are done. */
return 0;

View File

@ -238,17 +238,19 @@ static int run(int argc, char *argv[]) {
ts = timespec_store(&_ts, t);
}
{
struct pollfd p[3] = {
{.fd = fd, .events = events_a },
{.fd = STDIN_FILENO, .events = events_b & POLLIN },
{.fd = STDOUT_FILENO, .events = events_b & POLLOUT },
};
struct pollfd p[3] = {
{ .fd = fd, .events = events_a },
{ .fd = STDIN_FILENO, .events = events_b & POLLIN },
{ .fd = STDOUT_FILENO, .events = events_b & POLLOUT },
};
r = ppoll(p, ELEMENTSOF(p), ts, NULL);
}
r = ppoll(p, ELEMENTSOF(p), ts, NULL);
if (r < 0)
return log_error_errno(errno, "ppoll() failed: %m");
if (p[0].revents & POLLNVAL ||
p[1].revents & POLLNVAL ||
p[2].revents & POLLNVAL)
return log_error_errno(SYNTHETIC_ERRNO(EBADF), "Invalid file descriptor to poll on?");
}
return 0;

View File

@ -20,7 +20,6 @@ int main(int argc, char *argv[]) {
f = prefix_roota(p, "/run");
assert_se(mkdir(f, 0755) >= 0);
f = prefix_roota(p, "/run/systemd");
assert_se(make_inaccessible_nodes(f, 1, 1) >= 0);
f = prefix_roota(p, "/run/systemd/inaccessible/reg");

View File

@ -395,6 +395,10 @@ static int process_and_watch_password_files(bool watch) {
return -errno;
}
if (pollfd[FD_SIGNAL].revents & POLLNVAL ||
pollfd[FD_INOTIFY].revents & POLLNVAL)
return -EBADF;
if (pollfd[FD_INOTIFY].revents != 0)
(void) flush_fd(notify);

View File

@ -202,7 +202,12 @@ int settle_main(int argc, char *argv[], void *userdata) {
return -ETIMEDOUT;
/* wake up when queue becomes empty */
if (poll(&pfd, 1, MSEC_PER_SEC) > 0 && pfd.revents & POLLIN) {
r = poll(&pfd, 1, MSEC_PER_SEC);
if (r < 0)
return -errno;
if (pfd.revents & POLLNVAL)
return -EBADF;
if (r > 0 && pfd.revents & POLLIN) {
r = udev_queue_flush(queue);
if (r < 0)
return log_error_errno(r, "Failed to flush queue: %m");

View File

@ -1841,12 +1841,13 @@ int run_udevd(int argc, char *argv[]) {
return r;
if (arg_children_max == 0) {
unsigned long cpu_limit, mem_limit;
unsigned long cpu_count = 1;
cpu_set_t cpu_set;
unsigned long cpu_limit, mem_limit, cpu_count = 1;
if (sched_getaffinity(0, sizeof(cpu_set), &cpu_set) == 0)
cpu_count = CPU_COUNT(&cpu_set);
r = cpus_in_affinity_mask();
if (r < 0)
log_warning_errno(r, "Failed to determine number of local CPUs, ignoring: %m");
else
cpu_count = r;
cpu_limit = cpu_count * 2 + 16;
mem_limit = MAX(physical_memory() / (128UL*1024*1024), 10U);
@ -1858,10 +1859,6 @@ int run_udevd(int argc, char *argv[]) {
}
/* set umask before creating any file/directory */
r = chdir("/");
if (r < 0)
return log_error_errno(errno, "Failed to change dir to '/': %m");
umask(022);
r = mac_selinux_init();
@ -1872,8 +1869,6 @@ int run_udevd(int argc, char *argv[]) {
if (r < 0 && r != -EEXIST)
return log_error_errno(r, "Failed to create /run/udev: %m");
dev_setup(NULL, UID_INVALID, GID_INVALID);
if (getppid() == 1 && sd_booted() > 0) {
/* Get our own cgroup, we regularly kill everything udev has left behind.
* We only do this on systemd systems, and only if we are directly spawned
@ -1916,10 +1911,6 @@ int run_udevd(int argc, char *argv[]) {
/* child */
(void) setsid();
r = set_oom_score_adjust(-1000);
if (r < 0)
log_debug_errno(r, "Failed to adjust OOM score, ignoring: %m");
}
return main_loop(manager);

View File

@ -757,6 +757,8 @@ static int run(int argc, char *argv[]) {
if (poll(&pfd, 1, 0) < 0)
return log_error_errno(errno, "Failed to test for POLLIN on listening socket: %m");
if (FLAGS_SET(pfd.revents, POLLNVAL))
return log_error_errno(SYNTHETIC_ERRNO(EBADF), "Listening socket dead?");
if (FLAGS_SET(pfd.revents, POLLIN)) {
pid_t parent;

View File

@ -29,10 +29,34 @@ ADDITIONAL_DEPS=(dnf-plugins-core
openssl-devel
p11-kit-devel)
function info() {
info() {
echo -e "\033[33;1m$1\033[0m"
}
error() {
echo >&2 -e "\033[31;1m$1\033[0m"
}
success() {
echo >&2 -e "\033[32;1m$1\033[0m"
}
# Simple wrapper which retries given command up to five times
_retry() {
local EC=1
for i in {1..5}; do
if "$@"; then
EC=0
break
fi
sleep $((i * 5))
done
return $EC
}
set -e
source "$(dirname $0)/travis_wait.bash"
@ -52,11 +76,11 @@ for phase in "${PHASES[@]}"; do
# running following dnf commands during the initializing/starting
# (early/late bootup) phase, which caused nasty race conditions
$DOCKER_EXEC bash -c 'systemctl is-system-running --wait || :'
$DOCKER_EXEC dnf makecache
_retry $DOCKER_EXEC dnf makecache
# Install necessary build/test requirements
$DOCKER_EXEC dnf -y --exclude selinux-policy\* upgrade
$DOCKER_EXEC dnf -y install "${ADDITIONAL_DEPS[@]}"
$DOCKER_EXEC dnf -y builddep systemd
_retry $DOCKER_EXEC dnf -y --exclude selinux-policy\* upgrade
_retry $DOCKER_EXEC dnf -y install "${ADDITIONAL_DEPS[@]}"
_retry $DOCKER_EXEC dnf -y builddep systemd
;;
RUN)
info "Run phase"
@ -86,13 +110,53 @@ for phase in "${PHASES[@]}"; do
-t $CONT_NAME \
meson test --timeout-multiplier=3 -C ./build/ --print-errorlogs
;;
RUN_BUILD_CHECK_GCC|RUN_BUILD_CHECK_CLANG)
ARGS=(
"--optimization=0"
"--optimization=2"
"--optimization=3"
"--optimization=s"
"-Db_lto=true"
"-Db_ndebug=true"
)
if [[ "$phase" = "RUN_BUILD_CHECK_CLANG" ]]; then
ENV_VARS="-e CC=clang -e CXX=clang++"
$DOCKER_EXEC clang --version
else
$DOCKER_EXEC gcc --version
fi
for args in "${ARGS[@]}"; do
SECONDS=0
info "Checking build with $args"
# Redirect meson/ninja logs into separate files, otherwise we
# would trip over Travis' log size limit
if ! docker exec $ENV_VARS -it $CONT_NAME meson --werror $args build &> meson.log; then
cat meson.log
error "meson failed with $args"
exit 1
fi
if ! $DOCKER_EXEC ninja -v -C build &> ninja.log; then
cat ninja.log
error "ninja failed with $args"
exit 1
fi
$DOCKER_EXEC rm -fr build
rm -f meson.log ninja.log
success "Build with $args passed in $SECONDS seconds"
done
;;
CLEANUP)
info "Cleanup phase"
docker stop $CONT_NAME
docker rm -f $CONT_NAME
;;
*)
echo >&2 "Unknown phase '$phase'"
error "Unknown phase '$phase'"
exit 1
esac
done