diff options
author | Thomas Haller <thaller@redhat.com> | 2019-04-04 05:40:44 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2019-04-04 09:39:16 +0200 |
commit | b6032223988616c7d5c6c5715521aff1c5a81e40 (patch) | |
tree | 82f821c11542897b303f7e3b13e4aa7c02d1a4a1 | |
parent | 8372c0e9c0e6a035be1e6e046ceb8015e6f96782 (diff) | |
download | NetworkManager-b6032223988616c7d5c6c5715521aff1c5a81e40.tar.gz |
systemd: update code from upstream (2019-04-04)
This is a direct dump from systemd git.
======
SYSTEMD_DIR=../systemd
COMMIT=6e79d2b5a414f49c05392cf5f52072c5f081442e
(
cd "$SYSTEMD_DIR"
git checkout "$COMMIT"
git reset --hard
git clean -fdx
)
git ls-files -z :/src/systemd/src/ \
:/shared/systemd/src/ \
:/shared/nm-utils/unaligned.h | \
xargs -0 rm -f
nm_copy_sd_shared() {
mkdir -p "./shared/systemd/$(dirname "$1")"
cp "$SYSTEMD_DIR/$1" "./shared/systemd/$1"
}
nm_copy_sd_core() {
mkdir -p "./src/systemd/$(dirname "$1")"
cp "$SYSTEMD_DIR/$1" "./src/systemd/$1"
}
nm_copy_sd_nmutils() {
mkdir -p "./shared/nm-utils/"
cp "$SYSTEMD_DIR/$1" "./shared/nm-utils/${1##*/}"
}
nm_copy_sd_core "src/libsystemd-network/arp-util.c"
nm_copy_sd_core "src/libsystemd-network/arp-util.h"
nm_copy_sd_core "src/libsystemd-network/dhcp-identifier.c"
nm_copy_sd_core "src/libsystemd-network/dhcp-identifier.h"
nm_copy_sd_core "src/libsystemd-network/dhcp-internal.h"
nm_copy_sd_core "src/libsystemd-network/dhcp-lease-internal.h"
nm_copy_sd_core "src/libsystemd-network/dhcp-network.c"
nm_copy_sd_core "src/libsystemd-network/dhcp-option.c"
nm_copy_sd_core "src/libsystemd-network/dhcp-packet.c"
nm_copy_sd_core "src/libsystemd-network/dhcp-protocol.h"
nm_copy_sd_core "src/libsystemd-network/dhcp6-internal.h"
nm_copy_sd_core "src/libsystemd-network/dhcp6-lease-internal.h"
nm_copy_sd_core "src/libsystemd-network/dhcp6-network.c"
nm_copy_sd_core "src/libsystemd-network/dhcp6-option.c"
nm_copy_sd_core "src/libsystemd-network/dhcp6-protocol.h"
nm_copy_sd_core "src/libsystemd-network/lldp-internal.h"
nm_copy_sd_core "src/libsystemd-network/lldp-neighbor.c"
nm_copy_sd_core "src/libsystemd-network/lldp-neighbor.h"
nm_copy_sd_core "src/libsystemd-network/lldp-network.c"
nm_copy_sd_core "src/libsystemd-network/lldp-network.h"
nm_copy_sd_core "src/libsystemd-network/network-internal.c"
nm_copy_sd_core "src/libsystemd-network/network-internal.h"
nm_copy_sd_core "src/libsystemd-network/sd-dhcp-client.c"
nm_copy_sd_core "src/libsystemd-network/sd-dhcp-lease.c"
nm_copy_sd_core "src/libsystemd-network/sd-dhcp6-client.c"
nm_copy_sd_core "src/libsystemd-network/sd-dhcp6-lease.c"
nm_copy_sd_core "src/libsystemd-network/sd-ipv4acd.c"
nm_copy_sd_core "src/libsystemd-network/sd-ipv4ll.c"
nm_copy_sd_core "src/libsystemd-network/sd-lldp.c"
nm_copy_sd_core "src/libsystemd/sd-event/event-source.h"
nm_copy_sd_core "src/libsystemd/sd-event/event-util.c"
nm_copy_sd_core "src/libsystemd/sd-event/event-util.h"
nm_copy_sd_core "src/libsystemd/sd-event/sd-event.c"
nm_copy_sd_core "src/libsystemd/sd-id128/id128-util.c"
nm_copy_sd_core "src/libsystemd/sd-id128/id128-util.h"
nm_copy_sd_core "src/libsystemd/sd-id128/sd-id128.c"
nm_copy_sd_core "src/shared/dns-domain.c"
nm_copy_sd_core "src/shared/dns-domain.h"
nm_copy_sd_core "src/systemd/_sd-common.h"
nm_copy_sd_core "src/systemd/sd-dhcp-client.h"
nm_copy_sd_core "src/systemd/sd-dhcp-lease.h"
nm_copy_sd_core "src/systemd/sd-dhcp6-client.h"
nm_copy_sd_core "src/systemd/sd-dhcp6-lease.h"
nm_copy_sd_core "src/systemd/sd-event.h"
nm_copy_sd_core "src/systemd/sd-id128.h"
nm_copy_sd_core "src/systemd/sd-ipv4acd.h"
nm_copy_sd_core "src/systemd/sd-ipv4ll.h"
nm_copy_sd_core "src/systemd/sd-lldp.h"
nm_copy_sd_core "src/systemd/sd-ndisc.h"
nm_copy_sd_nmutils "src/basic/unaligned.h"
nm_copy_sd_shared "src/basic/alloc-util.c"
nm_copy_sd_shared "src/basic/alloc-util.h"
nm_copy_sd_shared "src/basic/async.h"
nm_copy_sd_shared "src/basic/env-file.c"
nm_copy_sd_shared "src/basic/env-file.h"
nm_copy_sd_shared "src/basic/env-util.c"
nm_copy_sd_shared "src/basic/env-util.h"
nm_copy_sd_shared "src/basic/errno-util.h"
nm_copy_sd_shared "src/basic/escape.c"
nm_copy_sd_shared "src/basic/escape.h"
nm_copy_sd_shared "src/basic/ether-addr-util.c"
nm_copy_sd_shared "src/basic/ether-addr-util.h"
nm_copy_sd_shared "src/basic/extract-word.c"
nm_copy_sd_shared "src/basic/extract-word.h"
nm_copy_sd_shared "src/basic/fd-util.c"
nm_copy_sd_shared "src/basic/fd-util.h"
nm_copy_sd_shared "src/basic/fileio.c"
nm_copy_sd_shared "src/basic/fileio.h"
nm_copy_sd_shared "src/basic/fs-util.c"
nm_copy_sd_shared "src/basic/fs-util.h"
nm_copy_sd_shared "src/basic/hash-funcs.c"
nm_copy_sd_shared "src/basic/hash-funcs.h"
nm_copy_sd_shared "src/basic/hashmap.c"
nm_copy_sd_shared "src/basic/hashmap.h"
nm_copy_sd_shared "src/basic/hexdecoct.c"
nm_copy_sd_shared "src/basic/hexdecoct.h"
nm_copy_sd_shared "src/basic/hostname-util.c"
nm_copy_sd_shared "src/basic/hostname-util.h"
nm_copy_sd_shared "src/basic/in-addr-util.c"
nm_copy_sd_shared "src/basic/in-addr-util.h"
nm_copy_sd_shared "src/basic/io-util.c"
nm_copy_sd_shared "src/basic/io-util.h"
nm_copy_sd_shared "src/basic/list.h"
nm_copy_sd_shared "src/basic/log.h"
nm_copy_sd_shared "src/basic/macro.h"
nm_copy_sd_shared "src/basic/memory-util.c"
nm_copy_sd_shared "src/basic/memory-util.h"
nm_copy_sd_shared "src/basic/mempool.c"
nm_copy_sd_shared "src/basic/mempool.h"
nm_copy_sd_shared "src/basic/missing_fcntl.h"
nm_copy_sd_shared "src/basic/missing_socket.h"
nm_copy_sd_shared "src/basic/missing_stat.h"
nm_copy_sd_shared "src/basic/missing_type.h"
nm_copy_sd_shared "src/basic/parse-util.c"
nm_copy_sd_shared "src/basic/parse-util.h"
nm_copy_sd_shared "src/basic/path-util.c"
nm_copy_sd_shared "src/basic/path-util.h"
nm_copy_sd_shared "src/basic/prioq.c"
nm_copy_sd_shared "src/basic/prioq.h"
nm_copy_sd_shared "src/basic/process-util.c"
nm_copy_sd_shared "src/basic/process-util.h"
nm_copy_sd_shared "src/basic/random-util.c"
nm_copy_sd_shared "src/basic/random-util.h"
nm_copy_sd_shared "src/basic/set.h"
nm_copy_sd_shared "src/basic/signal-util.h"
nm_copy_sd_shared "src/basic/siphash24.h"
nm_copy_sd_shared "src/basic/socket-util.c"
nm_copy_sd_shared "src/basic/socket-util.h"
nm_copy_sd_shared "src/basic/sort-util.h"
nm_copy_sd_shared "src/basic/sparse-endian.h"
nm_copy_sd_shared "src/basic/stat-util.c"
nm_copy_sd_shared "src/basic/stat-util.h"
nm_copy_sd_shared "src/basic/stdio-util.h"
nm_copy_sd_shared "src/basic/string-table.c"
nm_copy_sd_shared "src/basic/string-table.h"
nm_copy_sd_shared "src/basic/string-util.c"
nm_copy_sd_shared "src/basic/string-util.h"
nm_copy_sd_shared "src/basic/strv.c"
nm_copy_sd_shared "src/basic/strv.h"
nm_copy_sd_shared "src/basic/time-util.c"
nm_copy_sd_shared "src/basic/time-util.h"
nm_copy_sd_shared "src/basic/tmpfile-util.c"
nm_copy_sd_shared "src/basic/tmpfile-util.h"
nm_copy_sd_shared "src/basic/umask-util.h"
nm_copy_sd_shared "src/basic/utf8.c"
nm_copy_sd_shared "src/basic/utf8.h"
nm_copy_sd_shared "src/basic/util.c"
nm_copy_sd_shared "src/basic/util.h"
60 files changed, 1031 insertions, 978 deletions
diff --git a/shared/systemd/src/basic/alloc-util.c b/shared/systemd/src/basic/alloc-util.c index ab7a42c4e2..1e4ee722f2 100644 --- a/shared/systemd/src/basic/alloc-util.c +++ b/shared/systemd/src/basic/alloc-util.c @@ -1,11 +1,12 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ +#include <malloc.h> #include <stdint.h> #include <string.h> #include "alloc-util.h" #include "macro.h" -#include "util.h" +#include "memory-util.h" void* memdup(const void *p, size_t l) { void *ret; @@ -27,6 +28,9 @@ void* memdup_suffix0(const void *p, size_t l) { /* The same as memdup() but place a safety NUL byte after the allocated memory */ + if (_unlikely_(l == SIZE_MAX)) /* prevent overflow */ + return NULL; + ret = malloc(l + 1); if (!ret) return NULL; @@ -45,19 +49,23 @@ void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) { if (*allocated >= need) return *p; - newalloc = MAX(need * 2, 64u / size); - a = newalloc * size; + if (_unlikely_(need > SIZE_MAX/2)) /* Overflow check */ + return NULL; - /* check for overflows */ - if (a < size * need) + newalloc = need * 2; + if (size_multiply_overflow(newalloc, size)) return NULL; + a = newalloc * size; + if (a < 64) /* Allocate at least 64 bytes */ + a = 64; + q = realloc(*p, a); if (!q) return NULL; *p = q; - *allocated = newalloc; + *allocated = _unlikely_(size == 0) ? newalloc : malloc_usable_size(q) / size; return q; } diff --git a/shared/systemd/src/basic/alloc-util.h b/shared/systemd/src/basic/alloc-util.h index 893a1238ff..9b20be4773 100644 --- a/shared/systemd/src/basic/alloc-util.h +++ b/shared/systemd/src/basic/alloc-util.h @@ -8,6 +8,10 @@ #include "macro.h" +#if HAS_FEATURE_MEMORY_SANITIZER +# include <sanitizer/msan_interface.h> +#endif + typedef void (*free_func_t)(void *p); /* If for some reason more than 4M are allocated on the stack, let's abort immediately. It's better than @@ -152,11 +156,17 @@ void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size); (void*)memset(_new_, 0, _xsize_); \ }) -/* Takes inspiration from Rusts's Option::take() method: reads and returns a pointer, but at the same time resets it to - * NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */ +/* Takes inspiration from Rust's Option::take() method: reads and returns a pointer, but at the same time + * resets it to NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */ #define TAKE_PTR(ptr) \ ({ \ typeof(ptr) _ptr_ = (ptr); \ (ptr) = NULL; \ _ptr_; \ }) + +#if HAS_FEATURE_MEMORY_SANITIZER +# define msan_unpoison(r, s) __msan_unpoison(r, s) +#else +# define msan_unpoison(r, s) +#endif diff --git a/shared/systemd/src/basic/env-file.c b/shared/systemd/src/basic/env-file.c index 7f10f9ad39..a1f1308a54 100644 --- a/shared/systemd/src/basic/env-file.c +++ b/shared/systemd/src/basic/env-file.c @@ -559,6 +559,6 @@ int write_env_file(const char *fname, char **l) { r = -errno; } - unlink(p); + (void) unlink(p); return r; } diff --git a/shared/systemd/src/basic/errno-util.h b/shared/systemd/src/basic/errno-util.h new file mode 100644 index 0000000000..615b6a806a --- /dev/null +++ b/shared/systemd/src/basic/errno-util.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include "macro.h" + +static inline void _reset_errno_(int *saved_errno) { + if (*saved_errno < 0) /* Invalidated by UNPROTECT_ERRNO? */ + return; + + errno = *saved_errno; +} + +#define PROTECT_ERRNO \ + _cleanup_(_reset_errno_) _unused_ int _saved_errno_ = errno + +#define UNPROTECT_ERRNO \ + do { \ + errno = _saved_errno_; \ + _saved_errno_ = -1; \ + } while (false) + +static inline int negative_errno(void) { + /* This helper should be used to shut up gcc if you know 'errno' is + * negative. Instead of "return -errno;", use "return negative_errno();" + * It will suppress bogus gcc warnings in case it assumes 'errno' might + * be 0 and thus the caller's error-handling might not be triggered. */ + assert_return(errno > 0, -EINVAL); + return -errno; +} + +/* Hint #1: ENETUNREACH happens if we try to connect to "non-existing" special IP addresses, such as ::5. + * + * Hint #2: The kernel sends e.g., EHOSTUNREACH or ENONET to userspace in some ICMP error cases. See the + * icmp_err_convert[] in net/ipv4/icmp.c in the kernel sources */ +#define ERRNO_IS_DISCONNECT(r) \ + IN_SET(abs(r), \ + ENOTCONN, ECONNRESET, ECONNREFUSED, ECONNABORTED, EPIPE, \ + ENETUNREACH, EHOSTUNREACH, ENOPROTOOPT, EHOSTDOWN, \ + ENONET, ESHUTDOWN) + +/* Resource exhaustion, could be our fault or general system trouble */ +#define ERRNO_IS_RESOURCE(r) \ + IN_SET(abs(r), ENOMEM, EMFILE, ENFILE) diff --git a/shared/systemd/src/basic/fd-util.c b/shared/systemd/src/basic/fd-util.c index 3e6ef5a06a..b3b840145f 100644 --- a/shared/systemd/src/basic/fd-util.c +++ b/shared/systemd/src/basic/fd-util.c @@ -25,6 +25,10 @@ #include "util.h" #include "tmpfile-util.h" +/* The maximum number of iterations in the loop to close descriptors in the fallback case + * when /proc/self/fd/ is inaccessible. */ +#define MAX_FD_LOOP_LIMIT (1024*1024) + int close_nointr(int fd) { assert(fd >= 0); @@ -228,6 +232,13 @@ int close_all_fds(const int except[], size_t n_except) { if (max_fd < 0) return max_fd; + /* Refuse to do the loop over more too many elements. It's better to fail immediately than to + * spin the CPU for a long time. */ + if (max_fd > MAX_FD_LOOP_LIMIT) + return log_debug_errno(SYNTHETIC_ERRNO(EPERM), + "/proc/self/fd is inaccessible. Refusing to loop over %d potential fds.", + max_fd); + for (fd = 3; fd >= 0; fd = fd < max_fd ? fd + 1 : -1) { int q; diff --git a/shared/systemd/src/basic/fd-util.h b/shared/systemd/src/basic/fd-util.h index 4085a244d2..e490753caf 100644 --- a/shared/systemd/src/basic/fd-util.h +++ b/shared/systemd/src/basic/fd-util.h @@ -77,18 +77,6 @@ int acquire_data_fd(const void *data, size_t size, unsigned flags); int fd_duplicate_data_fd(int fd); -/* Hint: ENETUNREACH happens if we try to connect to "non-existing" special IP addresses, such as ::5 */ -/* The kernel sends e.g., EHOSTUNREACH or ENONET to userspace in some ICMP error cases. - * See the icmp_err_convert[] in net/ipv4/icmp.c in the kernel sources */ -#define ERRNO_IS_DISCONNECT(r) \ - IN_SET(r, \ - ENOTCONN, ECONNRESET, ECONNREFUSED, ECONNABORTED, EPIPE, \ - ENETUNREACH, EHOSTUNREACH, ENOPROTOOPT, EHOSTDOWN, ENONET) - -/* Resource exhaustion, could be our fault or general system trouble */ -#define ERRNO_IS_RESOURCE(r) \ - IN_SET(r, ENOMEM, EMFILE, ENFILE) - int fd_move_above_stdio(int fd); int rearrange_stdio(int original_input_fd, int original_output_fd, int original_error_fd); diff --git a/shared/systemd/src/basic/fileio.c b/shared/systemd/src/basic/fileio.c index e18b842999..91e0c9ec8b 100644 --- a/shared/systemd/src/basic/fileio.c +++ b/shared/systemd/src/basic/fileio.c @@ -212,7 +212,6 @@ int write_string_filef( int read_one_line_file(const char *fn, char **line) { _cleanup_fclose_ FILE *f = NULL; - int r; assert(fn); assert(line); @@ -223,8 +222,7 @@ int read_one_line_file(const char *fn, char **line) { (void) __fsetlocking(f, FSETLOCKING_BYCALLER); - r = read_line(f, LONG_LINE_MAX, line); - return r < 0 ? r : 0; + return read_line(f, LONG_LINE_MAX, line); } int verify_file(const char *fn, const char *blob, bool accept_extra_nl) { diff --git a/shared/systemd/src/basic/fs-util.c b/shared/systemd/src/basic/fs-util.c index f25bf2cbbc..d1c06cf12a 100644 --- a/shared/systemd/src/basic/fs-util.c +++ b/shared/systemd/src/basic/fs-util.c @@ -6,6 +6,7 @@ #include <stdlib.h> #include <string.h> #include <sys/stat.h> +#include <linux/falloc.h> #include <linux/magic.h> #include <time.h> #include <unistd.h> @@ -214,64 +215,109 @@ 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) { char fd_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1]; _cleanup_close_ int fd = -1; + bool st_valid = false; + struct stat st; + int r; + assert(path); - /* Under the assumption that we are running privileged we first change the access mode and only then hand out - * ownership to avoid a window where access is too open. */ + /* Under the assumption that we are running privileged we first change the access mode and only then + * hand out ownership to avoid a window where access is too open. */ - fd = open(path, O_PATH|O_CLOEXEC|O_NOFOLLOW); /* Let's acquire an O_PATH fd, as precaution to change mode/owner - * on the same file */ + fd = open(path, O_PATH|O_CLOEXEC|O_NOFOLLOW); /* Let's acquire an O_PATH fd, as precaution to change + * mode/owner on the same file */ if (fd < 0) return -errno; xsprintf(fd_path, "/proc/self/fd/%i", fd); if (mode != MODE_INVALID) { - if ((mode & S_IFMT) != 0) { - struct stat st; if (stat(fd_path, &st) < 0) return -errno; if ((mode & S_IFMT) != (st.st_mode & S_IFMT)) return -EINVAL; + + st_valid = true; } - if (chmod(fd_path, mode & 07777) < 0) - return -errno; + if (chmod(fd_path, mode & 07777) < 0) { + r = -errno; + + if (!st_valid && stat(fd_path, &st) < 0) + return -errno; + + if ((mode & 07777) != (st.st_mode & 07777)) + return r; + + st_valid = true; + } } - if (uid != UID_INVALID || gid != GID_INVALID) - if (chown(fd_path, uid, gid) < 0) - return -errno; + if (uid != UID_INVALID || gid != GID_INVALID) { + if (chown(fd_path, uid, gid) < 0) { + r = -errno; + + if (!st_valid && stat(fd_path, &st) < 0) + return -errno; + + if (uid != UID_INVALID && st.st_uid != uid) + return r; + if (gid != GID_INVALID && st.st_gid != gid) + return r; + } + } return 0; } int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid) { + bool st_valid = false; + struct stat st; + int r; + /* Under the assumption that we are running privileged we first change the access mode and only then hand out * ownership to avoid a window where access is too open. */ if (mode != MODE_INVALID) { - if ((mode & S_IFMT) != 0) { - struct stat st; if (fstat(fd, &st) < 0) return -errno; if ((mode & S_IFMT) != (st.st_mode & S_IFMT)) return -EINVAL; + + st_valid = true; } - if (fchmod(fd, mode & 0777) < 0) - return -errno; + if (fchmod(fd, mode & 07777) < 0) { + r = -errno; + + if (!st_valid && fstat(fd, &st) < 0) + return -errno; + + if ((mode & 07777) != (st.st_mode & 07777)) + return r; + + st_valid = true; + } } if (uid != UID_INVALID || gid != GID_INVALID) - if (fchown(fd, uid, gid) < 0) - return -errno; + if (fchown(fd, uid, gid) < 0) { + r = -errno; + + if (!st_valid && fstat(fd, &st) < 0) + return -errno; + + if (uid != UID_INVALID && st.st_uid != uid) + return r; + if (gid != GID_INVALID && st.st_gid != gid) + return r; + } return 0; } @@ -307,6 +353,10 @@ int fd_warn_permissions(const char *path, int fd) { if (fstat(fd, &st) < 0) return -errno; + /* Don't complain if we are reading something that is not a file, for example /dev/null */ + if (!S_ISREG(st.st_mode)) + return 0; + if (st.st_mode & 0111) log_warning("Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway.", path); @@ -925,6 +975,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, if (fstat(child, &st) < 0) return -errno; if ((flags & CHASE_SAFE) && + (empty_or_root(root) || (size_t)(todo - buffer) > strlen(root)) && unsafe_transition(&previous_stat, &st)) return log_unsafe_transition(fd, child, path, flags); @@ -1329,6 +1380,21 @@ int fsync_path_at(int at_fd, const char *path) { return 0; } +int syncfs_path(int atfd, const char *path) { + _cleanup_close_ int fd = -1; + + assert(path); + + fd = openat(atfd, path, O_CLOEXEC|O_RDONLY|O_NONBLOCK); + if (fd < 0) + return -errno; + + if (syncfs(fd) < 0) + return -errno; + + return 0; +} + int open_parent(const char *path, int flags, mode_t mode) { _cleanup_free_ char *parent = NULL; int fd; @@ -1345,9 +1411,9 @@ int open_parent(const char *path, int flags, mode_t mode) { /* Let's insist on O_DIRECTORY since the parent of a file or directory is a directory. Except if we open an * O_TMPFILE file, because in that case we are actually create a regular file below the parent directory. */ - if ((flags & O_PATH) == O_PATH) + if (FLAGS_SET(flags, O_PATH)) flags |= O_DIRECTORY; - else if ((flags & O_TMPFILE) != O_TMPFILE) + else if (!FLAGS_SET(flags, O_TMPFILE)) flags |= O_DIRECTORY|O_RDONLY; fd = open(parent, flags, mode); diff --git a/shared/systemd/src/basic/fs-util.h b/shared/systemd/src/basic/fs-util.h index 7ad030be5d..b9651205e6 100644 --- a/shared/systemd/src/basic/fs-util.h +++ b/shared/systemd/src/basic/fs-util.h @@ -10,8 +10,8 @@ #include <sys/types.h> #include <unistd.h> +#include "errno-util.h" #include "time-util.h" -#include "util.h" int unlink_noerrno(const char *path); @@ -108,4 +108,6 @@ int unlinkat_deallocate(int fd, const char *name, int flags); int fsync_directory_of_file(int fd); int fsync_path_at(int at_fd, const char *path); +int syncfs_path(int atfd, const char *path); + int open_parent(const char *path, int flags, mode_t mode); diff --git a/shared/systemd/src/basic/hashmap.c b/shared/systemd/src/basic/hashmap.c index f2e33d2265..c7bd7323a1 100644 --- a/shared/systemd/src/basic/hashmap.c +++ b/shared/systemd/src/basic/hashmap.c @@ -9,6 +9,7 @@ #include "fileio.h" #include "hashmap.h" #include "macro.h" +#include "memory-util.h" #include "mempool.h" #include "process-util.h" #include "random-util.h" @@ -16,7 +17,6 @@ #include "siphash24.h" #include "string-util.h" #include "strv.h" -#include "util.h" #if ENABLE_DEBUG_HASHMAP #include <pthread.h> @@ -888,7 +888,8 @@ void internal_hashmap_clear(HashmapBase *h, free_func_t default_free_key, free_f * themselves from our hash table a second time, the entry is already gone. */ while (internal_hashmap_size(h) > 0) { - void *v, *k; + void *k = NULL; + void *v; v = internal_hashmap_first_key_and_value(h, true, &k); @@ -1515,8 +1516,11 @@ void *internal_hashmap_first_key_and_value(HashmapBase *h, bool remove, void **r unsigned idx; idx = find_first_entry(h); - if (idx == IDX_NIL) + if (idx == IDX_NIL) { + if (ret_key) + *ret_key = NULL; return NULL; + } e = bucket_at(h, idx); key = (void*) e->key; @@ -1532,7 +1536,6 @@ void *internal_hashmap_first_key_and_value(HashmapBase *h, bool remove, void **r } unsigned internal_hashmap_size(HashmapBase *h) { - if (!h) return 0; @@ -1540,7 +1543,6 @@ unsigned internal_hashmap_size(HashmapBase *h) { } unsigned internal_hashmap_buckets(HashmapBase *h) { - if (!h) return 0; @@ -1900,8 +1902,7 @@ IteratedCache *iterated_cache_free(IteratedCache *cache) { if (cache) { free(cache->keys.ptr); free(cache->values.ptr); - free(cache); } - return NULL; + return mfree(cache); } diff --git a/shared/systemd/src/basic/hashmap.h b/shared/systemd/src/basic/hashmap.h index e16a9f9e30..41c8adb16b 100644 --- a/shared/systemd/src/basic/hashmap.h +++ b/shared/systemd/src/basic/hashmap.h @@ -412,9 +412,11 @@ static inline char **ordered_hashmap_get_strv(OrderedHashmap *h) { DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free); DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free); +DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free_key); DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free_free); DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free); DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free); +DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free_key); DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free_free); #define _cleanup_hashmap_free_ _cleanup_(hashmap_freep) diff --git a/shared/systemd/src/basic/hexdecoct.c b/shared/systemd/src/basic/hexdecoct.c index c0f96409fd..a5660a0ff3 100644 --- a/shared/systemd/src/basic/hexdecoct.c +++ b/shared/systemd/src/basic/hexdecoct.c @@ -8,8 +8,8 @@ #include "alloc-util.h" #include "hexdecoct.h" #include "macro.h" +#include "memory-util.h" #include "string-util.h" -#include "util.h" char octchar(int x) { return '0' + (x & 7); @@ -601,10 +601,11 @@ static int base64_append_width( lines = DIV_ROUND_UP(len, width); slen = strlen_ptr(sep); - if (lines > (SSIZE_MAX - plen - 1 - slen) / (indent + width + 1)) + if (plen >= SSIZE_MAX - 1 - slen || + lines > (SSIZE_MAX - plen - 1 - slen) / (indent + width + 1)) return -ENOMEM; - t = realloc(*prefix, plen + 1 + slen + (indent + width + 1) * lines); + t = realloc(*prefix, (ssize_t) plen + 1 + slen + (indent + width + 1) * lines); if (!t) return -ENOMEM; @@ -639,7 +640,7 @@ int base64_append( return base64_append_width(prefix, plen, "\n", indent, p, l, width - indent - 1); else /* leave plen on the left, keep last column free */ - return base64_append_width(prefix, plen, NULL, plen, p, l, width - plen - 1); + return base64_append_width(prefix, plen, " ", plen, p, l, width - plen - 1); } static int unbase64_next(const char **p, size_t *l) { diff --git a/shared/systemd/src/basic/in-addr-util.c b/shared/systemd/src/basic/in-addr-util.c index 2bffe473ca..1d5c6412b5 100644 --- a/shared/systemd/src/basic/in-addr-util.c +++ b/shared/systemd/src/basic/in-addr-util.c @@ -5,12 +5,15 @@ #include <errno.h> #include <net/if.h> #include <stdint.h> +#include <stdio.h> #include <stdlib.h> #include "alloc-util.h" #include "in-addr-util.h" #include "macro.h" #include "parse-util.h" +#include "random-util.h" +#include "strxcpyx.h" #include "util.h" bool in4_addr_is_null(const struct in_addr *a) { @@ -68,6 +71,14 @@ bool in4_addr_is_localhost(const struct in_addr *a) { return (be32toh(a->s_addr) & UINT32_C(0xFF000000)) == UINT32_C(127) << 24; } +bool in4_addr_is_non_local(const struct in_addr *a) { + /* Whether the address is not null and not localhost. + * + * As such, it is suitable to configure as DNS/NTP server from DHCP. */ + return !in4_addr_is_null(a) && + !in4_addr_is_localhost(a); +} + int in_addr_is_localhost(int family, const union in_addr_union *u) { assert(u); @@ -207,8 +218,85 @@ int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen) return -EAFNOSUPPORT; } +int in_addr_random_prefix( + int family, + union in_addr_union *u, + unsigned prefixlen_fixed_part, + unsigned prefixlen) { + + assert(u); + + /* Random network part of an address by one. */ + + if (prefixlen <= 0) + return 0; + + if (family == AF_INET) { + uint32_t c, n; + + if (prefixlen_fixed_part > 32) + prefixlen_fixed_part = 32; + if (prefixlen > 32) + prefixlen = 32; + if (prefixlen_fixed_part >= prefixlen) + return -EINVAL; + + c = be32toh(u->in.s_addr); + c &= ((UINT32_C(1) << prefixlen_fixed_part) - 1) << (32 - prefixlen_fixed_part); + + random_bytes(&n, sizeof(n)); + n &= ((UINT32_C(1) << (prefixlen - prefixlen_fixed_part)) - 1) << (32 - prefixlen); + + u->in.s_addr = htobe32(n | c); + return 1; + } + + if (family == AF_INET6) { + struct in6_addr n; + unsigned i, j; + + if (prefixlen_fixed_part > 128) + prefixlen_fixed_part = 128; + if (prefixlen > 128) + prefixlen = 128; + if (prefixlen_fixed_part >= prefixlen) + return -EINVAL; + + random_bytes(&n, sizeof(n)); + + for (i = 0; i < 16; i++) { + uint8_t mask_fixed_part = 0, mask = 0; + + if (i < (prefixlen_fixed_part + 7) / 8) { + if (i < prefixlen_fixed_part / 8) + mask_fixed_part = 0xffu; + else { + j = prefixlen_fixed_part % 8; + mask_fixed_part = ((UINT8_C(1) << (j + 1)) - 1) << (8 - j); + } + } + + if (i < (prefixlen + 7) / 8) { + if (i < prefixlen / 8) + mask = 0xffu ^ mask_fixed_part; + else { + j = prefixlen % 8; + mask = (((UINT8_C(1) << (j + 1)) - 1) << (8 - j)) ^ mask_fixed_part; + } + } + + u->in6.s6_addr[i] &= mask_fixed_part; + u->in6.s6_addr[i] |= n.s6_addr[i] & mask; + } + + return 1; + } + + return -EAFNOSUPPORT; +} + int in_addr_to_string(int family, const union in_addr_union *u, char **ret) { - char *x; + _cleanup_free_ char *x = NULL; size_t l; assert(u); @@ -226,18 +314,50 @@ int in_addr_to_string(int family, const union in_addr_union *u, char **ret) { return -ENOMEM; errno = 0; - if (!inet_ntop(family, u, x, l)) { - free(x); + if (!inet_ntop(family, u, x, l)) return errno > 0 ? -errno : -EINVAL; - } - *ret = x; + *ret = TAKE_PTR(x); + return 0; +} + +int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned prefixlen, char **ret) { + _cleanup_free_ char *x = NULL; + char *p; + size_t l; + + assert(u); + assert(ret); + + if (family == AF_INET) + l = INET_ADDRSTRLEN + 3; + else if (family == AF_INET6) + l = INET6_ADDRSTRLEN + 4; + else + return -EAFNOSUPPORT; + + if (prefixlen > FAMILY_ADDRESS_SIZE(family) * 8) + return -EINVAL; + + x = new(char, l); + if (!x) + return -ENOMEM; + + errno = 0; + if (!inet_ntop(family, u, x, l)) + return errno > 0 ? -errno : -EINVAL; + + p = x + strlen(x); + l -= strlen(x); + (void) strpcpyf(&p, l, "/%u", prefixlen); + + *ret = TAKE_PTR(x); return 0; } int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret) { + _cleanup_free_ char *x = NULL; size_t l; - char *x; int r; assert(u); @@ -263,14 +383,12 @@ int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifin return -ENOMEM; errno = 0; - if (!inet_ntop(family, u, x, l)) { - free(x); + if (!inet_ntop(family, u, x, l)) return errno > 0 ? -errno : -EINVAL; - } sprintf(strchr(x, 0), "%%%i", ifindex); - *ret = x; + *ret = TAKE_PTR(x); return 0; fallback: diff --git a/shared/systemd/src/basic/in-addr-util.h b/shared/systemd/src/basic/in-addr-util.h index 3069790519..a6a685b918 100644 --- a/shared/systemd/src/basic/in-addr-util.h +++ b/shared/systemd/src/basic/in-addr-util.h @@ -30,10 +30,14 @@ int in_addr_is_link_local(int family, const union in_addr_union *u); bool in4_addr_is_localhost(const struct in_addr *a); int in_addr_is_localhost(int family, const union in_addr_union *u); +bool in4_addr_is_non_local(const struct in_addr *a); + int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b); int in_addr_prefix_intersect(int family, const union in_addr_union *a, unsigned aprefixlen, const union in_addr_union *b, unsigned bprefixlen); int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen); +int in_addr_random_prefix(int family, union in_addr_union *u, unsigned prefixlen_fixed_part, unsigned prefixlen); int in_addr_to_string(int family, const union in_addr_union *u, char **ret); +int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned prefixlen, char **ret); int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret); int in_addr_from_string(int family, const char *s, union in_addr_union *ret); int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret); diff --git a/shared/systemd/src/basic/log.h b/shared/systemd/src/basic/log.h index 17438d7ff7..aa3d5b75f1 100644 --- a/shared/systemd/src/basic/log.h +++ b/shared/systemd/src/basic/log.h @@ -115,6 +115,19 @@ int log_internalv_realm( log_internalv_realm(LOG_REALM_PLUS_LEVEL(LOG_REALM, (level)), __VA_ARGS__) /* Realm is fixed to LOG_REALM_SYSTEMD for those */ +int log_object_internalv( + int level, + int error, + const char *file, + int line, + const char *func, + const char *object_field, + const char *object, + const char *extra_field, + const char *extra, + const char *format, + va_list ap) _printf_(10,0); + int log_object_internal( int level, int error, @@ -308,7 +321,7 @@ int log_syntax_invalid_utf8_internal( int _level = (level), _e = (error); \ (log_get_max_level() >= LOG_PRI(_level)) \ ? log_syntax_internal(unit, _level, config_file, config_line, _e, __FILE__, __LINE__, __func__, __VA_ARGS__) \ - : -abs(_e); \ + : -ERRNO_VALUE(_e); \ }) #define log_syntax_invalid_utf8(unit, level, config_file, config_line, rvalue) \ diff --git a/shared/systemd/src/basic/memory-util.c b/shared/systemd/src/basic/memory-util.c new file mode 100644 index 0000000000..5f327ef0d7 --- /dev/null +++ b/shared/systemd/src/basic/memory-util.c @@ -0,0 +1,57 @@ +#include <unistd.h> + +#include "memory-util.h" + +size_t page_size(void) { + static thread_local size_t pgsz = 0; + long r; + + if (_likely_(pgsz > 0)) + return pgsz; + + r = sysconf(_SC_PAGESIZE); + assert(r > 0); + + pgsz = (size_t) r; + return pgsz; +} + +bool memeqzero(const void *data, size_t length) { + /* Does the buffer consist entirely of NULs? + * Copied from https://github.com/systemd/casync/, copied in turn from + * https://github.com/rustyrussell/ccan/blob/master/ccan/mem/mem.c#L92, + * which is licensed CC-0. + */ + + const uint8_t *p = data; + size_t i; + + /* Check first 16 bytes manually */ + for (i = 0; i < 16; i++, length--) { + if (length == 0) + return true; + if (p[i]) + return false; + } + + /* Now we know first 16 bytes are NUL, memcmp with self. */ + return memcmp(data, p + i, length) == 0; +} + +#if !HAVE_EXPLICIT_BZERO +/* + * The pointer to memset() is volatile so that compiler must de-reference the pointer and can't assume that + * it points to any function in particular (such as memset(), which it then might further "optimize"). This + * approach is inspired by openssl's crypto/mem_clr.c. + */ +typedef void *(*memset_t)(void *,int,size_t); + +static volatile memset_t memset_func = memset; + +void* explicit_bzero_safe(void *p, size_t l) { + if (l > 0) + memset_func(p, '\0', l); + + return p; +} +#endif diff --git a/shared/systemd/src/basic/memory-util.h b/shared/systemd/src/basic/memory-util.h new file mode 100644 index 0000000000..915c24a5dd --- /dev/null +++ b/shared/systemd/src/basic/memory-util.h @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include <inttypes.h> +#include <stdbool.h> +#include <string.h> +#include <sys/types.h> + +#include "macro.h" + +size_t page_size(void) _pure_; +#define PAGE_ALIGN(l) ALIGN_TO((l), page_size()) + +/* Normal memcpy requires src to be nonnull. We do nothing if n is 0. */ +static inline void memcpy_safe(void *dst, const void *src, size_t n) { + if (n == 0) + return; + assert(src); + memcpy(dst, src, n); +} + +/* Normal memcmp requires s1 and s2 to be nonnull. We do nothing if n is 0. */ +static inline int memcmp_safe(const void *s1, const void *s2, size_t n) { + if (n == 0) + return 0; + assert(s1); + assert(s2); + return memcmp(s1, s2, n); +} + +/* Compare s1 (length n1) with s2 (length n2) in lexicographic order. */ +static inline int memcmp_nn(const void *s1, size_t n1, const void *s2, size_t n2) { + return memcmp_safe(s1, s2, MIN(n1, n2)) + ?: CMP(n1, n2); +} + +#define memzero(x,l) \ + ({ \ + size_t _l_ = (l); \ + void *_x_ = (x); \ + _l_ == 0 ? _x_ : memset(_x_, 0, _l_); \ + }) + +#define zero(x) (memzero(&(x), sizeof(x))) + +bool memeqzero(const void *data, size_t length); + +#define eqzero(x) memeqzero(x, sizeof(x)) + +static inline void *mempset(void *s, int c, size_t n) { + memset(s, c, n); + return (uint8_t*)s + n; +} + +/* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */ +static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) { + + if (needlelen <= 0) + return (void*) haystack; + + if (haystacklen < needlelen) + return NULL; + + assert(haystack); + assert(needle); + + return memmem(haystack, haystacklen, needle, needlelen); +} + +#if HAVE_EXPLICIT_BZERO +static inline void* explicit_bzero_safe(void *p, size_t l) { + if (l > 0) + explicit_bzero(p, l); + + return p; +} +#else +void *explicit_bzero_safe(void *p, size_t l); +#endif + +/* Use with _cleanup_ to erase a single 'char' when leaving scope */ +static inline void erase_char(char *p) { + explicit_bzero_safe(p, sizeof(char)); +} diff --git a/shared/systemd/src/basic/mempool.c b/shared/systemd/src/basic/mempool.c index 159c963377..22df42105b 100644 --- a/shared/systemd/src/basic/mempool.c +++ b/shared/systemd/src/basic/mempool.c @@ -5,6 +5,7 @@ #include "env-util.h" #include "macro.h" +#include "memory-util.h" #include "mempool.h" #include "process-util.h" #include "util.h" diff --git a/shared/systemd/src/basic/missing_socket.h b/shared/systemd/src/basic/missing_socket.h new file mode 100644 index 0000000000..276be366c3 --- /dev/null +++ b/shared/systemd/src/basic/missing_socket.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include <sys/socket.h> + +#if HAVE_LINUX_VM_SOCKETS_H +#include <linux/vm_sockets.h> +#else +#define VMADDR_CID_ANY -1U +struct sockaddr_vm { + unsigned short svm_family; + unsigned short svm_reserved1; + unsigned int svm_port; + unsigned int svm_cid; + unsigned char svm_zero[sizeof(struct sockaddr) - + sizeof(unsigned short) - + sizeof(unsigned short) - + sizeof(unsigned int) - + sizeof(unsigned int)]; +}; +#endif /* !HAVE_LINUX_VM_SOCKETS_H */ + +#ifndef AF_VSOCK +#define AF_VSOCK 40 +#endif + +#ifndef SO_REUSEPORT +#define SO_REUSEPORT 15 +#endif + +#ifndef SO_PEERGROUPS +#define SO_PEERGROUPS 59 +#endif + +#ifndef SO_BINDTOIFINDEX +#define SO_BINDTOIFINDEX 62 +#endif + +#ifndef SOL_NETLINK +#define SOL_NETLINK 270 +#endif + +#ifndef SOL_ALG +#define SOL_ALG 279 +#endif + +/* Not exposed yet. Defined in include/linux/socket.h. */ +#ifndef SOL_SCTP +#define SOL_SCTP 132 +#endif + +/* Not exposed yet. Defined in include/linux/socket.h */ +#ifndef SCM_SECURITY +#define SCM_SECURITY 0x03 +#endif + +/* netinet/in.h */ +#ifndef IP_FREEBIND +#define IP_FREEBIND 15 +#endif + +#ifndef IP_TRANSPARENT +#define IP_TRANSPARENT 19 +#endif diff --git a/shared/systemd/src/basic/missing_stat.h b/shared/systemd/src/basic/missing_stat.h new file mode 100644 index 0000000000..5116206a2e --- /dev/null +++ b/shared/systemd/src/basic/missing_stat.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include <linux/types.h> +#include <sys/stat.h> + +#if WANT_LINUX_STAT_H +#include <linux/stat.h> +#endif + +/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ +#if !HAVE_STRUCT_STATX +struct statx_timestamp { + __s64 tv_sec; + __u32 tv_nsec; + __s32 __reserved; +}; +struct statx { + __u32 stx_mask; + __u32 stx_blksize; + __u64 stx_attributes; + __u32 stx_nlink; + __u32 stx_uid; + __u32 stx_gid; + __u16 stx_mode; + __u16 __spare0[1]; + __u64 stx_ino; + __u64 stx_size; + __u64 stx_blocks; + __u64 stx_attributes_mask; + struct statx_timestamp stx_atime; + struct statx_timestamp stx_btime; + struct statx_timestamp stx_ctime; + struct statx_timestamp stx_mtime; + __u32 stx_rdev_major; + __u32 stx_rdev_minor; + __u32 stx_dev_major; + __u32 stx_dev_minor; + __u64 __spare2[14]; +}; +#endif + +/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ +#ifndef STATX_BTIME +#define STATX_BTIME 0x00000800U +#endif + +/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ +#ifndef AT_STATX_DONT_SYNC +#define AT_STATX_DONT_SYNC 0x4000 +#endif diff --git a/shared/systemd/src/basic/path-util.c b/shared/systemd/src/basic/path-util.c index 221517303e..55cb140d87 100644 --- a/shared/systemd/src/basic/path-util.c +++ b/shared/systemd/src/basic/path-util.c @@ -21,6 +21,7 @@ #include "log.h" #include "macro.h" #include "missing.h" +#include "nulstr-util.h" #include "parse-util.h" #include "path-util.h" #include "stat-util.h" @@ -1103,48 +1104,40 @@ int path_simplify_and_warn( unsigned line, const char *lvalue) { - bool absolute, fatal = flag & PATH_CHECK_FATAL; + bool fatal = flag & PATH_CHECK_FATAL; assert(!FLAGS_SET(flag, PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE)); - if (!utf8_is_valid(path)) { - log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, path); - return -EINVAL; - } + if (!utf8_is_valid(path)) + return log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, path); if (flag & (PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE)) { + bool absolute; + absolute = path_is_absolute(path); - if (!absolute && (flag & PATH_CHECK_ABSOLUTE)) { - log_syntax(unit, LOG_ERR, filename, line, 0, - "%s= path is not absolute%s: %s", - lvalue, fatal ? "" : ", ignoring", path); - return -EINVAL; - } + if (!absolute && (flag & PATH_CHECK_ABSOLUTE)) + return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL), + "%s= path is not absolute%s: %s", + lvalue, fatal ? "" : ", ignoring", path); - if (absolute && (flag & PATH_CHECK_RELATIVE)) { - log_syntax(unit, LOG_ERR, filename, line, 0, - "%s= path is absolute%s: %s", - lvalue, fatal ? "" : ", ignoring", path); - return -EINVAL; - } + if (absolute && (flag & PATH_CHECK_RELATIVE)) + return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL), + "%s= path is absolute%s: %s", + lvalue, fatal ? "" : ", ignoring", path); } path_simplify(path, true); - if (!path_is_normalized(path)) { - log_syntax(unit, LOG_ERR, filename, line, 0, - "%s= path is not normalized%s: %s", - lvalue, fatal ? "" : ", ignoring", path); - return -EINVAL; - } + if (!path_is_valid(path)) + return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL), + "%s= path has invalid length (%zu bytes)%s.", + lvalue, strlen(path), fatal ? "" : ", ignoring"); - if (!path_is_valid(path)) { - log_syntax(unit, LOG_ERR, filename, line, 0, - "%s= path has invalid length (%zu bytes)%s.", - lvalue, strlen(path), fatal ? "" : ", ignoring"); - return -EINVAL; - } + if (!path_is_normalized(path)) + return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL), + "%s= path is not normalized%s: %s", + lvalue, fatal ? "" : ", ignoring", path); return 0; } diff --git a/shared/systemd/src/basic/process-util.c b/shared/systemd/src/basic/process-util.c index 78ce43b944..f773eeaffd 100644 --- a/shared/systemd/src/basic/process-util.c +++ b/shared/systemd/src/basic/process-util.c @@ -32,7 +32,9 @@ #include "ioprio.h" #include "log.h" #include "macro.h" +#include "memory-util.h" #include "missing.h" +#include "namespace-util.h" #include "process-util.h" #include "raw-clone.h" #include "rlimit-util.h" @@ -42,7 +44,6 @@ #include "string-util.h" #include "terminal-util.h" #include "user-util.h" -#include "util.h" int get_process_state(pid_t pid) { const char *p; @@ -933,6 +934,20 @@ int getenv_for_pid(pid_t pid, const char *field, char **ret) { return 0; } +int pid_is_my_child(pid_t pid) { + pid_t ppid; + int r; + + if (pid <= 1) + return false; + + r = get_process_ppid(pid, &ppid); + if (r < 0) + return r; + + return ppid == getpid_cached(); +} + bool pid_is_unwaited(pid_t pid) { /* Checks whether a PID is still valid at all, including a zombie */ @@ -1000,7 +1015,7 @@ _noreturn_ void freeze(void) { log_close(); /* Make sure nobody waits for us on a socket anymore */ - close_all_fds(NULL, 0); + (void) close_all_fds(NULL, 0); sync(); @@ -1534,6 +1549,40 @@ int set_oom_score_adjust(int value) { WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_DISABLE_BUFFER); } +int cpus_in_affinity_mask(void) { + size_t n = 16; + int r; + + for (;;) { + cpu_set_t *c; + + c = CPU_ALLOC(n); + if (!c) + return -ENOMEM; + + if (sched_getaffinity(0, CPU_ALLOC_SIZE(n), c) >= 0) { + int k; + + k = CPU_COUNT_S(CPU_ALLOC_SIZE(n), c); + CPU_FREE(c); + + if (k <= 0) + return -EINVAL; + + return k; + } + + r = -errno; + CPU_FREE(c); + + if (r != -EINVAL) + return r; + if (n > SIZE_MAX/2) + return -ENOMEM; + n *= 2; + } +} + static const char *const ioprio_class_table[] = { [IOPRIO_CLASS_NONE] = "none", [IOPRIO_CLASS_RT] = "realtime", diff --git a/shared/systemd/src/basic/process-util.h b/shared/systemd/src/basic/process-util.h index c85ea30ecc..7e1d65a7bf 100644 --- a/shared/systemd/src/basic/process-util.h +++ b/shared/systemd/src/basic/process-util.h @@ -12,6 +12,7 @@ #include <sys/resource.h> #include <sys/types.h> +#include "alloc-util.h" #include "format-util.h" #include "ioprio.h" #include "macro.h" @@ -68,6 +69,7 @@ int getenv_for_pid(pid_t pid, const char *field, char **_value); bool pid_is_alive(pid_t pid); bool pid_is_unwaited(pid_t pid); +int pid_is_my_child(pid_t pid); int pid_from_same_root_fs(pid_t pid); bool is_main_thread(void); @@ -192,3 +194,5 @@ assert_cc(TASKS_MAX <= (unsigned long) PID_T_MAX) (pid) = 0; \ _pid_; \ }) + +int cpus_in_affinity_mask(void); diff --git a/shared/systemd/src/basic/random-util.c b/shared/systemd/src/basic/random-util.c index f7decf60b6..ca25fd2420 100644 --- a/shared/systemd/src/basic/random-util.c +++ b/shared/systemd/src/basic/random-util.c @@ -23,16 +23,13 @@ # include <linux/random.h> #endif +#include "alloc-util.h" #include "fd-util.h" #include "io-util.h" #include "missing.h" #include "random-util.h" #include "time-util.h" -#if HAS_FEATURE_MEMORY_SANITIZER -#include <sanitizer/msan_interface.h> -#endif - int rdrand(unsigned long *ret) { #if defined(__i386__) || defined(__x86_64__) @@ -58,11 +55,7 @@ int rdrand(unsigned long *ret) { "setc %1" : "=r" (*ret), "=qm" (err)); - -#if HAS_FEATURE_MEMORY_SANITIZER - __msan_unpoison(&err, sizeof(err)); -#endif - + msan_unpoison(&err, sizeof(err)); if (!err) return -EAGAIN; diff --git a/shared/systemd/src/basic/refcnt.h b/shared/systemd/src/basic/refcnt.h deleted file mode 100644 index 40f9a84a22..0000000000 --- a/shared/systemd/src/basic/refcnt.h +++ /dev/null @@ -1,54 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -#pragma once - -/* A type-safe atomic refcounter. - * - * DO NOT USE THIS UNLESS YOU ACTUALLY CARE ABOUT THREAD SAFETY! */ - -typedef struct { - volatile unsigned _value; -} RefCount; - -#define REFCNT_GET(r) ((r)._value) -#define REFCNT_INC(r) (__sync_add_and_fetch(&(r)._value, 1)) -#define REFCNT_DEC(r) (__sync_sub_and_fetch(&(r)._value, 1)) - -#define REFCNT_INIT ((RefCount) { ._value = 1 }) - -#define _DEFINE_ATOMIC_REF_FUNC(type, name, scope) \ - scope type *name##_ref(type *p) { \ - if (!p) \ - return NULL; \ - \ - assert_se(REFCNT_INC(p->n_ref) >= 2); \ - return p; \ - } - -#define _DEFINE_ATOMIC_UNREF_FUNC(type, name, free_func, scope) \ - scope type *name##_unref(type *p) { \ - if (!p) \ - return NULL; \ - \ - if (REFCNT_DEC(p->n_ref) > 0) \ - return NULL; \ - \ - return free_func(p); \ - } - -#define DEFINE_ATOMIC_REF_FUNC(type, name) \ - _DEFINE_ATOMIC_REF_FUNC(type, name,) -#define DEFINE_PUBLIC_ATOMIC_REF_FUNC(type, name) \ - _DEFINE_ATOMIC_REF_FUNC(type, name, _public_) - -#define DEFINE_ATOMIC_UNREF_FUNC(type, name, free_func) \ - _DEFINE_ATOMIC_UNREF_FUNC(type, name, free_func,) -#define DEFINE_PUBLIC_ATOMIC_UNREF_FUNC(type, name, free_func) \ - _DEFINE_ATOMIC_UNREF_FUNC(type, name, free_func, _public_) - -#define DEFINE_ATOMIC_REF_UNREF_FUNC(type, name, free_func) \ - DEFINE_ATOMIC_REF_FUNC(type, name); \ - DEFINE_ATOMIC_UNREF_FUNC(type, name, free_func); - -#define DEFINE_PUBLIC_ATOMIC_REF_UNREF_FUNC(type, name, free_func) \ - DEFINE_PUBLIC_ATOMIC_REF_FUNC(type, name); \ - DEFINE_PUBLIC_ATOMIC_UNREF_FUNC(type, name, free_func); diff --git a/shared/systemd/src/basic/socket-util.c b/shared/systemd/src/basic/socket-util.c index 91bf801cdf..3d929f5418 100644 --- a/shared/systemd/src/basic/socket-util.c +++ b/shared/systemd/src/basic/socket-util.c @@ -21,6 +21,7 @@ #include "format-util.h" #include "log.h" #include "macro.h" +#include "memory-util.h" #include "missing.h" #include "parse-util.h" #include "path-util.h" @@ -31,7 +32,6 @@ #include "strv.h" #include "user-util.h" #include "utf8.h" -#include "util.h" #if ENABLE_IDN # define IDN_FLAGS NI_IDN @@ -235,23 +235,32 @@ int socket_address_parse_and_warn(SocketAddress *a, const char *s) { } int socket_address_parse_netlink(SocketAddress *a, const char *s) { - int family; + _cleanup_free_ char *word = NULL; unsigned group = 0; - _cleanup_free_ char *sfamily = NULL; + int family, r; + assert(a); assert(s); zero(*a); a->type = SOCK_RAW; - errno = 0; - if (sscanf(s, "%ms %u", &sfamily, &group) < 1) - return errno > 0 ? -errno : -EINVAL; + r = extract_first_word(&s, &word, NULL, 0); + if (r < 0) + return r; + if (r == 0) + return -EINVAL; - family = netlink_family_from_string(sfamily); + family = netlink_family_from_string(word); if (family < 0) return -EINVAL; + if (!isempty(s)) { + r = safe_atou(s, &group); + if (r < 0) + return r; + } + a->sockaddr.nl.nl_family = AF_NETLINK; a->sockaddr.nl.nl_groups = group; @@ -1345,3 +1354,39 @@ int sockaddr_un_set_path(struct sockaddr_un *ret, const char *path) { return (int) (offsetof(struct sockaddr_un, sun_path) + l + 1); /* include trailing NUL in size */ } } + +int socket_bind_to_ifname(int fd, const char *ifname) { + assert(fd >= 0); + + /* Call with NULL to drop binding */ + + if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen_ptr(ifname)) < 0) + return -errno; + + return 0; +} + +int socket_bind_to_ifindex(int fd, int ifindex) { + char ifname[IFNAMSIZ] = ""; + + assert(fd >= 0); + + if (ifindex <= 0) { + /* Drop binding */ + if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, NULL, 0) < 0) + return -errno; + + return 0; + } + + if (setsockopt(fd, SOL_SOCKET, SO_BINDTOIFINDEX, &ifindex, sizeof(ifindex)) >= 0) + return 0; + if (errno != ENOPROTOOPT) + return -errno; + + /* Fall back to SO_BINDTODEVICE on kernels < 5.0 which didn't have SO_BINDTOIFINDEX */ + if (!if_indextoname(ifindex, ifname)) + return -errno; + + return socket_bind_to_ifname(fd, ifname); +} diff --git a/shared/systemd/src/basic/socket-util.h b/shared/systemd/src/basic/socket-util.h index 574d2b73f5..6920fd99ba 100644 --- a/shared/systemd/src/basic/socket-util.h +++ b/shared/systemd/src/basic/socket-util.h @@ -198,3 +198,6 @@ static inline int setsockopt_int(int fd, int level, int optname, int value) { return 0; } + +int socket_bind_to_ifname(int fd, const char *ifname); +int socket_bind_to_ifindex(int fd, int ifindex); diff --git a/shared/systemd/src/basic/sort-util.h b/shared/systemd/src/basic/sort-util.h new file mode 100644 index 0000000000..e029f8646e --- /dev/null +++ b/shared/systemd/src/basic/sort-util.h @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include <stdlib.h> + +#include "macro.h" + +void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, + __compar_d_fn_t compar, void *arg); + +#define typesafe_bsearch_r(k, b, n, func, userdata) \ + ({ \ + const typeof(b[0]) *_k = k; \ + int (*_func_)(const typeof(b[0])*, const typeof(b[0])*, typeof(userdata)) = func; \ + xbsearch_r((const void*) _k, (b), (n), sizeof((b)[0]), (__compar_d_fn_t) _func_, userdata); \ + }) + +/** + * Normal bsearch requires base to be nonnull. Here were require + * that only if nmemb > 0. + */ +static inline void* bsearch_safe(const void *key, const void *base, + size_t nmemb, size_t size, __compar_fn_t compar) { + if (nmemb <= 0) + return NULL; + + assert(base); + return bsearch(key, base, nmemb, size, compar); +} + +#define typesafe_bsearch(k, b, n, func) \ + ({ \ + const typeof(b[0]) *_k = k; \ + int (*_func_)(const typeof(b[0])*, const typeof(b[0])*) = func; \ + bsearch_safe((const void*) _k, (b), (n), sizeof((b)[0]), (__compar_fn_t) _func_); \ + }) + +/** + * Normal qsort requires base to be nonnull. Here were require + * that only if nmemb > 0. + */ +static inline void qsort_safe(void *base, size_t nmemb, size_t size, __compar_fn_t compar) { + if (nmemb <= 1) + return; + + assert(base); + qsort(base, nmemb, size, compar); +} + +/* A wrapper around the above, but that adds typesafety: the element size is automatically derived from the type and so + * is the prototype for the comparison function */ +#define typesafe_qsort(p, n, func) \ + ({ \ + int (*_func_)(const typeof(p[0])*, const typeof(p[0])*) = func; \ + qsort_safe((p), (n), sizeof((p)[0]), (__compar_fn_t) _func_); \ + }) + +static inline void qsort_r_safe(void *base, size_t nmemb, size_t size, __compar_d_fn_t compar, void *userdata) { + if (nmemb <= 1) + return; + + assert(base); + qsort_r(base, nmemb, size, compar, userdata); +} + +#define typesafe_qsort_r(p, n, func, userdata) \ + ({ \ + int (*_func_)(const typeof(p[0])*, const typeof(p[0])*, typeof(userdata)) = func; \ + qsort_r_safe((p), (n), sizeof((p)[0]), (__compar_d_fn_t) _func_, userdata); \ + }) diff --git a/shared/systemd/src/basic/stat-util.c b/shared/systemd/src/basic/stat-util.c index ea2bbc368b..2cd722c106 100644 --- a/shared/systemd/src/basic/stat-util.c +++ b/shared/systemd/src/basic/stat-util.c @@ -223,52 +223,6 @@ int fd_is_network_fs(int fd) { return is_network_fs(&s); } -int fd_is_network_ns(int fd) { - struct statfs s; - int r; - - /* Checks whether the specified file descriptor refers to a network namespace. On old kernels there's no nice - * way to detect that, hence on those we'll return a recognizable error (EUCLEAN), so that callers can handle - * this somewhat nicely. - * - * This function returns > 0 if the fd definitely refers to a network namespace, 0 if it definitely does not - * refer to a network namespace, -EUCLEAN if we can't determine, and other negative error codes on error. */ - - if (fstatfs(fd, &s) < 0) - return -errno; - - if (!is_fs_type(&s, NSFS_MAGIC)) { - /* On really old kernels, there was no "nsfs", and network namespace sockets belonged to procfs - * instead. Handle that in a somewhat smart way. */ - - if (is_fs_type(&s, PROC_SUPER_MAGIC)) { - struct statfs t; - - /* OK, so it is procfs. Let's see if our own network namespace is procfs, too. If so, then the - * passed fd might refer to a network namespace, but we can't know for sure. In that case, - * return a recognizable error. */ - - if (statfs("/proc/self/ns/net", &t) < 0) - return -errno; - - if (s.f_type == t.f_type) - return -EUCLEAN; /* It's possible, we simply don't know */ - } - - return 0; /* No! */ - } - - r = ioctl(fd, NS_GET_NSTYPE); - if (r < 0) { - if (errno == ENOTTY) /* Old kernels didn't know this ioctl, let's also return a recognizable error in that case */ - return -EUCLEAN; - - return -errno; - } - - return r == CLONE_NEWNET; -} - int path_is_temporary_fs(const char *path) { _cleanup_close_ int fd = -1; diff --git a/shared/systemd/src/basic/stat-util.h b/shared/systemd/src/basic/stat-util.h index 74fb7251b3..7824af3500 100644 --- a/shared/systemd/src/basic/stat-util.h +++ b/shared/systemd/src/basic/stat-util.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once +#include <fcntl.h> #include <stdbool.h> #include <stddef.h> #include <sys/stat.h> @@ -50,8 +51,6 @@ bool is_network_fs(const struct statfs *s) _pure_; int fd_is_temporary_fs(int fd); int fd_is_network_fs(int fd); -int fd_is_network_ns(int fd); - int path_is_temporary_fs(const char *path); /* Because statfs.t_type can be int on some architectures, we have to cast diff --git a/shared/systemd/src/basic/stdio-util.h b/shared/systemd/src/basic/stdio-util.h index dc67b6e761..c3b9448d4f 100644 --- a/shared/systemd/src/basic/stdio-util.h +++ b/shared/systemd/src/basic/stdio-util.h @@ -7,7 +7,7 @@ #include <sys/types.h> #include "macro.h" -#include "util.h" +#include "memory-util.h" #define snprintf_ok(buf, len, fmt, ...) \ ((size_t) snprintf(buf, len, fmt, __VA_ARGS__) < (len)) diff --git a/shared/systemd/src/basic/string-table.h b/shared/systemd/src/basic/string-table.h index 228c12ad00..42fe4f4315 100644 --- a/shared/systemd/src/basic/string-table.h +++ b/shared/systemd/src/basic/string-table.h @@ -59,13 +59,13 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k #define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,scope) \ scope type name##_from_string(const char *s) { \ - type i; \ unsigned u = 0; \ + type i; \ if (!s) \ return (type) -1; \ - for (i = 0; i < (type) ELEMENTSOF(name##_table); i++) \ - if (streq_ptr(name##_table[i], s)) \ - return i; \ + i = (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \ + if (i >= 0) \ + return i; \ if (safe_atou(s, &u) >= 0 && u <= max) \ return (type) u; \ return (type) -1; \ diff --git a/shared/systemd/src/basic/string-util.c b/shared/systemd/src/basic/string-util.c index 93917bc0f0..5001a2be3a 100644 --- a/shared/systemd/src/basic/string-util.c +++ b/shared/systemd/src/basic/string-util.c @@ -10,14 +10,15 @@ #include "alloc-util.h" #include "escape.h" +#include "fileio.h" #include "gunicode.h" #include "locale-util.h" #include "macro.h" +#include "memory-util.h" #include "string-util.h" #include "terminal-util.h" #include "utf8.h" #include "util.h" -#include "fileio.h" int strcmp_ptr(const char *a, const char *b) { @@ -675,19 +676,6 @@ char *cellescape(char *buf, size_t len, const char *s) { return buf; } -bool nulstr_contains(const char *nulstr, const char *needle) { - const char *i; - - if (!nulstr) - return false; - - NULSTR_FOREACH(i, nulstr) - if (streq(i, needle)) - return true; - - return false; -} - char* strshorten(char *s, size_t l) { assert(s); @@ -1048,25 +1036,6 @@ int free_and_strndup(char **p, const char *s, size_t l) { return 1; } -#if !HAVE_EXPLICIT_BZERO -/* - * Pointer to memset is volatile so that compiler must de-reference - * the pointer and can't assume that it points to any function in - * particular (such as memset, which it then might further "optimize") - * This approach is inspired by openssl's crypto/mem_clr.c. - */ -typedef void *(*memset_t)(void *,int,size_t); - -static volatile memset_t memset_func = memset; - -void* explicit_bzero_safe(void *p, size_t l) { - if (l > 0) - memset_func(p, '\0', l); - - return p; -} -#endif - char* string_erase(char *x) { if (!x) return NULL; diff --git a/shared/systemd/src/basic/string-util.h b/shared/systemd/src/basic/string-util.h index 38070abb22..9cf11198b1 100644 --- a/shared/systemd/src/basic/string-util.h +++ b/shared/systemd/src/basic/string-util.h @@ -165,8 +165,6 @@ char *cellescape(char *buf, size_t len, const char *s); /* This limit is arbitrary, enough to give some idea what the string contains */ #define CELLESCAPE_DEFAULT_LENGTH 64 -bool nulstr_contains(const char *nulstr, const char *needle); - char* strshorten(char *s, size_t l); char *strreplace(const char *text, const char *old_string, const char *new_string); @@ -182,33 +180,12 @@ char *strrep(const char *s, unsigned n); int split_pair(const char *s, const char *sep, char **l, char **r); int free_and_strdup(char **p, const char *s); -int free_and_strndup(char **p, const char *s, size_t l); - -/* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */ -static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) { - - if (needlelen <= 0) - return (void*) haystack; - - if (haystacklen < needlelen) - return NULL; - - assert(haystack); - assert(needle); - - return memmem(haystack, haystacklen, needle, needlelen); -} - -#if HAVE_EXPLICIT_BZERO -static inline void* explicit_bzero_safe(void *p, size_t l) { - if (l > 0) - explicit_bzero(p, l); - - return p; +static inline int free_and_strdup_warn(char **p, const char *s) { + if (free_and_strdup(p, s) < 0) + return log_oom(); + return 0; } -#else -void *explicit_bzero_safe(void *p, size_t l); -#endif +int free_and_strndup(char **p, const char *s, size_t l); char *string_erase(char *x); diff --git a/shared/systemd/src/basic/strv.c b/shared/systemd/src/basic/strv.c index 3a62f25ded..21c106149b 100644 --- a/shared/systemd/src/basic/strv.c +++ b/shared/systemd/src/basic/strv.c @@ -11,9 +11,10 @@ #include "escape.h" #include "extract-word.h" #include "fileio.h" +#include "nulstr-util.h" +#include "sort-util.h" #include "string-util.h" #include "strv.h" -#include "util.h" char *strv_find(char **l, const char *name) { char **i; diff --git a/shared/systemd/src/basic/strv.h b/shared/systemd/src/basic/strv.h index 392cab65be..aa5f95ab72 100644 --- a/shared/systemd/src/basic/strv.h +++ b/shared/systemd/src/basic/strv.h @@ -5,12 +5,12 @@ #include <stdarg.h> #include <stdbool.h> #include <stddef.h> +#include <stdio.h> #include "alloc-util.h" #include "extract-word.h" #include "macro.h" #include "string-util.h" -#include "util.h" char *strv_find(char **l, const char *name) _pure_; char *strv_find_prefix(char **l, const char *name) _pure_; diff --git a/shared/systemd/src/basic/time-util.c b/shared/systemd/src/basic/time-util.c index 62cdc305f9..daf952baa1 100644 --- a/shared/systemd/src/basic/time-util.c +++ b/shared/systemd/src/basic/time-util.c @@ -1031,6 +1031,15 @@ int parse_sec_fix_0(const char *t, usec_t *ret) { return r; } +int parse_sec_def_infinity(const char *t, usec_t *ret) { + t += strspn(t, WHITESPACE); + if (isempty(t)) { + *ret = USEC_INFINITY; + return 0; + } + return parse_sec(t, ret); +} + static const char* extract_nsec_multiplier(const char *p, nsec_t *multiplier) { static const struct { const char *suffix; @@ -1205,7 +1214,7 @@ int get_timezones(char ***ret) { n_allocated = 2; n_zones = 1; - f = fopen("/usr/share/zoneinfo/zone.tab", "re"); + f = fopen("/usr/share/zoneinfo/zone1970.tab", "re"); if (f) { for (;;) { _cleanup_free_ char *line = NULL; diff --git a/shared/systemd/src/basic/time-util.h b/shared/systemd/src/basic/time-util.h index 5316305062..a238f6914d 100644 --- a/shared/systemd/src/basic/time-util.h +++ b/shared/systemd/src/basic/time-util.h @@ -112,6 +112,7 @@ int parse_timestamp(const char *t, usec_t *usec); int parse_sec(const char *t, usec_t *usec); int parse_sec_fix_0(const char *t, usec_t *usec); +int parse_sec_def_infinity(const char *t, usec_t *usec); int parse_time(const char *t, usec_t *usec, usec_t default_unit); int parse_nsec(const char *t, nsec_t *nsec); diff --git a/shared/systemd/src/basic/utf8.c b/shared/systemd/src/basic/utf8.c index e0d1949dc7..090c69d140 100644 --- a/shared/systemd/src/basic/utf8.c +++ b/shared/systemd/src/basic/utf8.c @@ -61,12 +61,7 @@ static bool unichar_is_control(char32_t ch) { } /* count of characters used to encode one unicode char */ -static size_t utf8_encoded_expected_len(const char *str) { - uint8_t c; - - assert(str); - - c = (uint8_t) str[0]; +static size_t utf8_encoded_expected_len(uint8_t c) { if (c < 0x80) return 1; if ((c & 0xe0) == 0xc0) @@ -90,7 +85,7 @@ int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar) { assert(str); - len = utf8_encoded_expected_len(str); + len = utf8_encoded_expected_len(str[0]); switch (len) { case 1: @@ -133,14 +128,14 @@ bool utf8_is_printable_newline(const char* str, size_t length, bool newline) { assert(str); - for (p = str; length;) { + for (p = str; length > 0;) { int encoded_len, r; char32_t val; - encoded_len = utf8_encoded_valid_unichar(p); - if (encoded_len < 0 || - (size_t) encoded_len > length) + encoded_len = utf8_encoded_valid_unichar(p, length); + if (encoded_len < 0) return false; + assert(encoded_len > 0 && (size_t) encoded_len <= length); r = utf8_encoded_to_unichar(p, &val); if (r < 0 || @@ -164,7 +159,7 @@ char *utf8_is_valid(const char *str) { while (*p) { int len; - len = utf8_encoded_valid_unichar(p); + len = utf8_encoded_valid_unichar(p, (size_t) -1); if (len < 0) return NULL; @@ -186,7 +181,7 @@ char *utf8_escape_invalid(const char *str) { while (*str) { int len; - len = utf8_encoded_valid_unichar(str); + len = utf8_encoded_valid_unichar(str, (size_t) -1); if (len > 0) { s = mempcpy(s, str, len); str += len; @@ -213,7 +208,7 @@ char *utf8_escape_non_printable(const char *str) { while (*str) { int len; - len = utf8_encoded_valid_unichar(str); + len = utf8_encoded_valid_unichar(str, (size_t) -1); if (len > 0) { if (utf8_is_printable(str, len)) { s = mempcpy(s, str, len); @@ -405,7 +400,7 @@ char16_t *utf8_to_utf16(const char *s, size_t length) { char32_t unichar; size_t e; - e = utf8_encoded_expected_len(s + i); + e = utf8_encoded_expected_len(s[i]); if (e <= 1) /* Invalid and single byte characters are copied as they are */ goto copy; @@ -457,17 +452,24 @@ static int utf8_unichar_to_encoded_len(char32_t unichar) { } /* validate one encoded unicode char and return its length */ -int utf8_encoded_valid_unichar(const char *str) { +int utf8_encoded_valid_unichar(const char *str, size_t length /* bytes */) { char32_t unichar; size_t len, i; int r; assert(str); + assert(length > 0); - len = utf8_encoded_expected_len(str); + /* We read until NUL, at most length bytes. (size_t) -1 may be used to disable the length check. */ + + len = utf8_encoded_expected_len(str[0]); if (len == 0) return -EINVAL; + /* Do we have a truncated multi-byte character? */ + if (len > length) + return -EINVAL; + /* ascii is valid */ if (len == 1) return 1; @@ -500,7 +502,7 @@ size_t utf8_n_codepoints(const char *str) { while (*str != 0) { int k; - k = utf8_encoded_valid_unichar(str); + k = utf8_encoded_valid_unichar(str, (size_t) -1); if (k < 0) return (size_t) -1; diff --git a/shared/systemd/src/basic/utf8.h b/shared/systemd/src/basic/utf8.h index 628456936e..6df70921db 100644 --- a/shared/systemd/src/basic/utf8.h +++ b/shared/systemd/src/basic/utf8.h @@ -32,7 +32,7 @@ char16_t *utf8_to_utf16(const char *s, size_t length); size_t char16_strlen(const char16_t *s); /* returns the number of 16bit words in the string (not bytes!) */ -int utf8_encoded_valid_unichar(const char *str); +int utf8_encoded_valid_unichar(const char *str, size_t length); int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar); static inline bool utf16_is_surrogate(char16_t c) { diff --git a/shared/systemd/src/basic/util.c b/shared/systemd/src/basic/util.c index e577c93e60..93d610bc98 100644 --- a/shared/systemd/src/basic/util.c +++ b/shared/systemd/src/basic/util.c @@ -19,7 +19,6 @@ #include "alloc-util.h" #include "btrfs-util.h" #include "build.h" -#include "cgroup-util.h" #include "def.h" #include "device-nodes.h" #include "dirent-util.h" @@ -52,33 +51,6 @@ int saved_argc = 0; char **saved_argv = NULL; static int saved_in_initrd = -1; -size_t page_size(void) { - static thread_local size_t pgsz = 0; - long r; - - if (_likely_(pgsz > 0)) - return pgsz; - - r = sysconf(_SC_PAGESIZE); - assert(r > 0); - - pgsz = (size_t) r; - return pgsz; -} - -bool plymouth_running(void) { - return access("/run/plymouth/pid", F_OK) >= 0; -} - -bool display_is_local(const char *display) { - assert(display); - - return - display[0] == ':' && - display[1] >= '0' && - display[1] <= '9'; -} - bool kexec_loaded(void) { _cleanup_free_ char *s = NULL; @@ -141,53 +113,6 @@ void in_initrd_force(bool value) { saved_in_initrd = value; } -/* hey glibc, APIs with callbacks without a user pointer are so useless */ -void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, - __compar_d_fn_t compar, void *arg) { - size_t l, u, idx; - const void *p; - int comparison; - - assert(!size_multiply_overflow(nmemb, size)); - - l = 0; - u = nmemb; - while (l < u) { - idx = (l + u) / 2; - p = (const uint8_t*) base + idx * size; - comparison = compar(key, p, arg); - if (comparison < 0) - u = idx; - else if (comparison > 0) - l = idx + 1; - else - return (void *)p; - } - return NULL; -} - -bool memeqzero(const void *data, size_t length) { - /* Does the buffer consist entirely of NULs? - * Copied from https://github.com/systemd/casync/, copied in turn from - * https://github.com/rustyrussell/ccan/blob/master/ccan/mem/mem.c#L92, - * which is licensed CC-0. - */ - - const uint8_t *p = data; - size_t i; - - /* Check first 16 bytes manually */ - for (i = 0; i < 16; i++, length--) { - if (length == 0) - return true; - if (p[i]) - return false; - } - - /* Now we know first 16 bytes are NUL, memcmp with self. */ - return memcmp(data, p + i, length) == 0; -} - int on_ac_power(void) { bool found_offline = false, found_online = false; _cleanup_closedir_ DIR *d = NULL; @@ -294,268 +219,6 @@ int container_get_leader(const char *machine, pid_t *pid) { return 0; } -int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd) { - _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, netnsfd = -1, usernsfd = -1; - int rfd = -1; - - assert(pid >= 0); - - if (mntns_fd) { - const char *mntns; - - mntns = procfs_file_alloca(pid, "ns/mnt"); - mntnsfd = open(mntns, O_RDONLY|O_NOCTTY|O_CLOEXEC); - if (mntnsfd < 0) - return -errno; - } - - if (pidns_fd) { - const char *pidns; - - pidns = procfs_file_alloca(pid, "ns/pid"); - pidnsfd = open(pidns, O_RDONLY|O_NOCTTY|O_CLOEXEC); - if (pidnsfd < 0) - return -errno; - } - - if (netns_fd) { - const char *netns; - - netns = procfs_file_alloca(pid, "ns/net"); - netnsfd = open(netns, O_RDONLY|O_NOCTTY|O_CLOEXEC); - if (netnsfd < 0) - return -errno; - } - - if (userns_fd) { - const char *userns; - - userns = procfs_file_alloca(pid, "ns/user"); - usernsfd = open(userns, O_RDONLY|O_NOCTTY|O_CLOEXEC); - if (usernsfd < 0 && errno != ENOENT) - return -errno; - } - - if (root_fd) { - const char *root; - - root = procfs_file_alloca(pid, "root"); - rfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY); - if (rfd < 0) - return -errno; - } - - if (pidns_fd) - *pidns_fd = pidnsfd; - - if (mntns_fd) - *mntns_fd = mntnsfd; - - if (netns_fd) - *netns_fd = netnsfd; - - if (userns_fd) - *userns_fd = usernsfd; - - if (root_fd) - *root_fd = rfd; - - pidnsfd = mntnsfd = netnsfd = usernsfd = -1; - - return 0; -} - -int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) { - if (userns_fd >= 0) { - /* Can't setns to your own userns, since then you could - * escalate from non-root to root in your own namespace, so - * check if namespaces equal before attempting to enter. */ - _cleanup_free_ char *userns_fd_path = NULL; - int r; - if (asprintf(&userns_fd_path, "/proc/self/fd/%d", userns_fd) < 0) - return -ENOMEM; - - r = files_same(userns_fd_path, "/proc/self/ns/user", 0); - if (r < 0) - return r; - if (r) - userns_fd = -1; - } - - if (pidns_fd >= 0) - if (setns(pidns_fd, CLONE_NEWPID) < 0) - return -errno; - - if (mntns_fd >= 0) - if (setns(mntns_fd, CLONE_NEWNS) < 0) - return -errno; - - if (netns_fd >= 0) - if (setns(netns_fd, CLONE_NEWNET) < 0) - return -errno; - - if (userns_fd >= 0) - if (setns(userns_fd, CLONE_NEWUSER) < 0) - return -errno; - - if (root_fd >= 0) { - if (fchdir(root_fd) < 0) - return -errno; - - if (chroot(".") < 0) - return -errno; - } - - return reset_uid_gid(); -} - -uint64_t physical_memory(void) { - _cleanup_free_ char *root = NULL, *value = NULL; - uint64_t mem, lim; - size_t ps; - long sc; - int r; - - /* We return this as uint64_t in case we are running as 32bit process on a 64bit kernel with huge amounts of - * memory. - * - * In order to support containers nicely that have a configured memory limit we'll take the minimum of the - * physically reported amount of memory and the limit configured for the root cgroup, if there is any. */ - - sc = sysconf(_SC_PHYS_PAGES); - assert(sc > 0); - - ps = page_size(); - mem = (uint64_t) sc * (uint64_t) ps; - - r = cg_get_root_path(&root); - if (r < 0) { - log_debug_errno(r, "Failed to determine root cgroup, ignoring cgroup memory limit: %m"); - return mem; - } - - r = cg_all_unified(); - if (r < 0) { - log_debug_errno(r, "Failed to determine root unified mode, ignoring cgroup memory limit: %m"); - return mem; - } - if (r > 0) { - r = cg_get_attribute("memory", root, "memory.max", &value); - if (r < 0) { - log_debug_errno(r, "Failed to read memory.max cgroup attribute, ignoring cgroup memory limit: %m"); - return mem; - } - - if (streq(value, "max")) - return mem; - } else { - r = cg_get_attribute("memory", root, "memory.limit_in_bytes", &value); - if (r < 0) { - log_debug_errno(r, "Failed to read memory.limit_in_bytes cgroup attribute, ignoring cgroup memory limit: %m"); - return mem; - } - } - - r = safe_atou64(value, &lim); - if (r < 0) { - log_debug_errno(r, "Failed to parse cgroup memory limit '%s', ignoring: %m", value); - return mem; - } - if (lim == UINT64_MAX) - return mem; - - /* Make sure the limit is a multiple of our own page size */ - lim /= ps; - lim *= ps; - - return MIN(mem, lim); -} - -uint64_t physical_memory_scale(uint64_t v, uint64_t max) { - uint64_t p, m, ps, r; - - assert(max > 0); - - /* Returns the physical memory size, multiplied by v divided by max. Returns UINT64_MAX on overflow. On success - * the result is a multiple of the page size (rounds down). */ - - ps = page_size(); - assert(ps > 0); - - p = physical_memory() / ps; - assert(p > 0); - - m = p * v; - if (m / p != v) - return UINT64_MAX; - - m /= max; - - r = m * ps; - if (r / ps != m) - return UINT64_MAX; - - return r; -} - -uint64_t system_tasks_max(void) { - - uint64_t a = TASKS_MAX, b = TASKS_MAX; - _cleanup_free_ char *root = NULL; - int r; - - /* Determine the maximum number of tasks that may run on this system. We check three sources to determine this - * limit: - * - * a) the maximum tasks value the kernel allows on this architecture - * b) the cgroups pids_max attribute for the system - * c) the kernel's configured maximum PID value - * - * And then pick the smallest of the three */ - - r = procfs_tasks_get_limit(&a); - if (r < 0) - log_debug_errno(r, "Failed to read maximum number of tasks from /proc, ignoring: %m"); - - r = cg_get_root_path(&root); - if (r < 0) - log_debug_errno(r, "Failed to determine cgroup root path, ignoring: %m"); - else { - _cleanup_free_ char *value = NULL; - - r = cg_get_attribute("pids", root, "pids.max", &value); - if (r < 0) - log_debug_errno(r, "Failed to read pids.max attribute of cgroup root, ignoring: %m"); - else if (!streq(value, "max")) { - r = safe_atou64(value, &b); - if (r < 0) - log_debug_errno(r, "Failed to parse pids.max attribute of cgroup root, ignoring: %m"); - } - } - - return MIN3(TASKS_MAX, - a <= 0 ? TASKS_MAX : a, - b <= 0 ? TASKS_MAX : b); -} - -uint64_t system_tasks_max_scale(uint64_t v, uint64_t max) { - uint64_t t, m; - - assert(max > 0); - - /* Multiply the system's task value by the fraction v/max. Hence, if max==100 this calculates percentages - * relative to the system's maximum number of tasks. Returns UINT64_MAX on overflow. */ - - t = system_tasks_max(); - assert(t > 0); - - m = t * v; - if (m / t != v) /* overflow? */ - return UINT64_MAX; - - return m / max; -} - int version(void) { puts("systemd " STRINGIFY(PROJECT_VERSION) " (" GIT_VERSION ")\n" SYSTEMD_FEATURES); diff --git a/shared/systemd/src/basic/util.h b/shared/systemd/src/basic/util.h index f009d37d4c..25e6ab8112 100644 --- a/shared/systemd/src/basic/util.h +++ b/shared/systemd/src/basic/util.h @@ -1,34 +1,9 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -#include <alloca.h> -#include <errno.h> -#include <fcntl.h> -#include <inttypes.h> -#include <limits.h> -#include <locale.h> -#include <stdarg.h> -#include <stdbool.h> -#include <stddef.h> #include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/inotify.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <sys/statfs.h> -#include <sys/sysmacros.h> -#include <sys/types.h> -#include <time.h> -#include <unistd.h> - -#include "format-util.h" -#include "macro.h" -#include "time-util.h" -size_t page_size(void) _pure_; -#define PAGE_ALIGN(l) ALIGN_TO((l), page_size()) +#include "macro.h" static inline const char* yes_no(bool b) { return b ? "yes" : "no"; @@ -46,19 +21,14 @@ static inline const char* enable_disable(bool b) { return b ? "enable" : "disable"; } -bool plymouth_running(void); - -bool display_is_local(const char *display) _pure_; - -#define NULSTR_FOREACH(i, l) \ - for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1) - -#define NULSTR_FOREACH_PAIR(i, j, l) \ - for ((i) = (l), (j) = strchr((i), 0)+1; (i) && *(i); (i) = strchr((j), 0)+1, (j) = *(i) ? strchr((i), 0)+1 : (i)) - extern int saved_argc; extern char **saved_argv; +static inline void save_argc_argv(int argc, char **argv) { + saved_argc = argc; + saved_argv = argv; +} + bool kexec_loaded(void); int prot_from_flags(int flags) _const_; @@ -66,129 +36,8 @@ int prot_from_flags(int flags) _const_; bool in_initrd(void); void in_initrd_force(bool value); -void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, - __compar_d_fn_t compar, void *arg); - -#define typesafe_bsearch_r(k, b, n, func, userdata) \ - ({ \ - const typeof(b[0]) *_k = k; \ - int (*_func_)(const typeof(b[0])*, const typeof(b[0])*, typeof(userdata)) = func; \ - xbsearch_r((const void*) _k, (b), (n), sizeof((b)[0]), (__compar_d_fn_t) _func_, userdata); \ - }) - -/** - * Normal bsearch requires base to be nonnull. Here were require - * that only if nmemb > 0. - */ -static inline void* bsearch_safe(const void *key, const void *base, - size_t nmemb, size_t size, __compar_fn_t compar) { - if (nmemb <= 0) - return NULL; - - assert(base); - return bsearch(key, base, nmemb, size, compar); -} - -#define typesafe_bsearch(k, b, n, func) \ - ({ \ - const typeof(b[0]) *_k = k; \ - int (*_func_)(const typeof(b[0])*, const typeof(b[0])*) = func; \ - bsearch_safe((const void*) _k, (b), (n), sizeof((b)[0]), (__compar_fn_t) _func_); \ - }) - -/** - * Normal qsort requires base to be nonnull. Here were require - * that only if nmemb > 0. - */ -static inline void qsort_safe(void *base, size_t nmemb, size_t size, __compar_fn_t compar) { - if (nmemb <= 1) - return; - - assert(base); - qsort(base, nmemb, size, compar); -} - -/* A wrapper around the above, but that adds typesafety: the element size is automatically derived from the type and so - * is the prototype for the comparison function */ -#define typesafe_qsort(p, n, func) \ - ({ \ - int (*_func_)(const typeof(p[0])*, const typeof(p[0])*) = func; \ - qsort_safe((p), (n), sizeof((p)[0]), (__compar_fn_t) _func_); \ - }) - -static inline void qsort_r_safe(void *base, size_t nmemb, size_t size, __compar_d_fn_t compar, void *userdata) { - if (nmemb <= 1) - return; - - assert(base); - qsort_r(base, nmemb, size, compar, userdata); -} - -#define typesafe_qsort_r(p, n, func, userdata) \ - ({ \ - int (*_func_)(const typeof(p[0])*, const typeof(p[0])*, typeof(userdata)) = func; \ - qsort_r_safe((p), (n), sizeof((p)[0]), (__compar_d_fn_t) _func_, userdata); \ - }) - -/* Normal memcpy requires src to be nonnull. We do nothing if n is 0. */ -static inline void memcpy_safe(void *dst, const void *src, size_t n) { - if (n == 0) - return; - assert(src); - memcpy(dst, src, n); -} - -/* Normal memcmp requires s1 and s2 to be nonnull. We do nothing if n is 0. */ -static inline int memcmp_safe(const void *s1, const void *s2, size_t n) { - if (n == 0) - return 0; - assert(s1); - assert(s2); - return memcmp(s1, s2, n); -} - -/* Compare s1 (length n1) with s2 (length n2) in lexicographic order. */ -static inline int memcmp_nn(const void *s1, size_t n1, const void *s2, size_t n2) { - return memcmp_safe(s1, s2, MIN(n1, n2)) - ?: CMP(n1, n2); -} - int on_ac_power(void); -#define memzero(x,l) \ - ({ \ - size_t _l_ = (l); \ - void *_x_ = (x); \ - _l_ == 0 ? _x_ : memset(_x_, 0, _l_); \ - }) - -#define zero(x) (memzero(&(x), sizeof(x))) - -bool memeqzero(const void *data, size_t length); - -#define eqzero(x) memeqzero(x, sizeof(x)) - -static inline void *mempset(void *s, int c, size_t n) { - memset(s, c, n); - return (uint8_t*)s + n; -} - -static inline void _reset_errno_(int *saved_errno) { - errno = *saved_errno; -} - -#define PROTECT_ERRNO \ - _cleanup_(_reset_errno_) _unused_ int _saved_errno_ = errno - -static inline int negative_errno(void) { - /* This helper should be used to shut up gcc if you know 'errno' is - * negative. Instead of "return -errno;", use "return negative_errno();" - * It will suppress bogus gcc warnings in case it assumes 'errno' might - * be 0 and thus the caller's error-handling might not be triggered. */ - assert_return(errno > 0, -EINVAL); - return -errno; -} - static inline unsigned u64log2(uint64_t n) { #if __SIZEOF_LONG_LONG__ == 8 return (n > 1) ? (unsigned) __builtin_clzll(n) ^ 63U : 0; @@ -228,15 +77,6 @@ static inline unsigned log2u_round_up(unsigned x) { int container_get_leader(const char *machine, pid_t *pid); -int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd); -int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd); - -uint64_t physical_memory(void); -uint64_t physical_memory_scale(uint64_t v, uint64_t max); - -uint64_t system_tasks_max(void); -uint64_t system_tasks_max_scale(uint64_t v, uint64_t max); - int version(void); int str_verscmp(const char *s1, const char *s2); diff --git a/src/systemd/src/libsystemd-network/dhcp-identifier.c b/src/systemd/src/libsystemd-network/dhcp-identifier.c index 04bf64cce5..0c1ff34e5d 100644 --- a/src/systemd/src/libsystemd-network/dhcp-identifier.c +++ b/src/systemd/src/libsystemd-network/dhcp-identifier.c @@ -12,6 +12,7 @@ #include "siphash24.h" #include "sparse-endian.h" #include "stdio-util.h" +#include "udev-util.h" #include "virt.h" #define SYSTEMD_PEN 43793 @@ -182,6 +183,13 @@ int dhcp_identifier_set_iaid( /* not yet ready */ return -EBUSY; + r = device_is_renaming(device); + if (r < 0) + return r; + if (r > 0) + /* device is under renaming */ + return -EBUSY; + name = net_get_name(device); } } diff --git a/src/systemd/src/libsystemd-network/dhcp-lease-internal.h b/src/systemd/src/libsystemd-network/dhcp-lease-internal.h index 9d245a9059..122042ab58 100644 --- a/src/systemd/src/libsystemd-network/dhcp-lease-internal.h +++ b/src/systemd/src/libsystemd-network/dhcp-lease-internal.h @@ -41,7 +41,6 @@ struct sd_dhcp_lease { /* each 0 if unset */ be32_t address; be32_t server_address; - be32_t router; be32_t next_server; bool have_subnet_mask; @@ -50,6 +49,9 @@ struct sd_dhcp_lease { bool have_broadcast; be32_t broadcast; + struct in_addr *router; + size_t router_size; + struct in_addr *dns; size_t dns_size; diff --git a/src/systemd/src/libsystemd-network/dhcp-network.c b/src/systemd/src/libsystemd-network/dhcp-network.c index 0e5b4147a9..94c10ed14c 100644 --- a/src/systemd/src/libsystemd-network/dhcp-network.c +++ b/src/systemd/src/libsystemd-network/dhcp-network.c @@ -50,12 +50,16 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link, BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.htype)), /* A <- DHCP header type */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, arp_type, 1, 0), /* header type == arp_type ? */ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.hlen)), /* A <- MAC address length */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, dhcp_hlen, 1, 0), /* address length == dhcp_hlen ? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.xid)), /* A <- client identifier */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, xid, 1, 0), /* client identifier == xid ? */ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ + BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.hlen)), /* A <- MAC address length */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, dhcp_hlen, 1, 0), /* address length == dhcp_hlen ? */ + BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ + + /* We only support MAC address length to be either 0 or 6 (ETH_ALEN). Optionally + * compare chaddr for ETH_ALEN bytes. */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETH_ALEN, 0, 12), /* A (the MAC address length) == ETH_ALEN ? */ BPF_STMT(BPF_LD + BPF_IMM, unaligned_read_be32(ð_mac->ether_addr_octet[0])), /* A <- 4 bytes of client's MAC */ BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */ BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr)), /* A <- 4 bytes of MAC from dhcp.chaddr */ @@ -68,6 +72,7 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link, BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0), /* A == 0 ? */ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ + BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.magic)), /* A <- DHCP magic cookie */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP_MAGIC_COOKIE, 1, 0), /* cookie == DHCP magic cookie ? */ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ @@ -148,7 +153,6 @@ int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port) { .in.sin_addr.s_addr = address, }; _cleanup_close_ int s = -1; - char ifname[IF_NAMESIZE] = ""; int r; s = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); @@ -164,12 +168,9 @@ int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port) { return r; if (ifindex > 0) { - if (if_indextoname(ifindex, ifname) == 0) - return -errno; - - r = setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname)); + r = socket_bind_to_ifindex(s, ifindex); if (r < 0) - return -errno; + return r; } if (address == INADDR_ANY) { diff --git a/src/systemd/src/libsystemd-network/dhcp-option.c b/src/systemd/src/libsystemd-network/dhcp-option.c index ad3f92546d..a68de4ff98 100644 --- a/src/systemd/src/libsystemd-network/dhcp-option.c +++ b/src/systemd/src/libsystemd-network/dhcp-option.c @@ -9,10 +9,10 @@ #include <string.h> #include "alloc-util.h" -#include "utf8.h" -#include "strv.h" - #include "dhcp-internal.h" +#include "memory-util.h" +#include "strv.h" +#include "utf8.h" static int option_append(uint8_t options[], size_t size, size_t *offset, uint8_t code, size_t optlen, const void *optval) { diff --git a/src/systemd/src/libsystemd-network/dhcp6-option.c b/src/systemd/src/libsystemd-network/dhcp6-option.c index a2aac9a793..017402c53b 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-option.c +++ b/src/systemd/src/libsystemd-network/dhcp6-option.c @@ -14,10 +14,10 @@ #include "dhcp6-lease-internal.h" #include "dhcp6-protocol.h" #include "dns-domain.h" +#include "memory-util.h" #include "sparse-endian.h" #include "strv.h" #include "unaligned.h" -#include "util.h" typedef struct DHCP6StatusOption { struct DHCP6Option option; diff --git a/src/systemd/src/libsystemd-network/lldp-neighbor.c b/src/systemd/src/libsystemd-network/lldp-neighbor.c index f6db62594d..9bae4a3c6e 100644 --- a/src/systemd/src/libsystemd-network/lldp-neighbor.c +++ b/src/systemd/src/libsystemd-network/lldp-neighbor.c @@ -7,9 +7,9 @@ #include "in-addr-util.h" #include "lldp-internal.h" #include "lldp-neighbor.h" +#include "memory-util.h" #include "missing.h" #include "unaligned.h" -#include "util.h" static void lldp_neighbor_id_hash_func(const LLDPNeighborID *id, struct siphash *state) { siphash24_compress(id->chassis_id, id->chassis_id_size, state); diff --git a/src/systemd/src/libsystemd-network/network-internal.c b/src/systemd/src/libsystemd-network/network-internal.c index 0348e7fa9d..2154cf7eac 100644 --- a/src/systemd/src/libsystemd-network/network-internal.c +++ b/src/systemd/src/libsystemd-network/network-internal.c @@ -10,6 +10,7 @@ #include "alloc-util.h" #include "condition.h" #include "conf-parser.h" +#include "device-util.h" #include "dhcp-lease-internal.h" #include "ether-addr-util.h" #include "hexdecoct.h" @@ -40,31 +41,35 @@ const char *net_get_name(sd_device *device) { int net_get_unique_predictable_data(sd_device *device, uint64_t *result) { size_t l, sz = 0; - const char *name = NULL; + const char *name; int r; uint8_t *v; assert(device); + /* net_get_name() will return one of the device names based on stable information about the + * device. If this is not available, we fall back to using the device name. */ name = net_get_name(device); if (!name) - return -ENOENT; + (void) sd_device_get_sysname(device, &name); + if (!name) + return log_device_debug_errno(device, SYNTHETIC_ERRNO(ENODATA), + "No stable identifying information found"); + log_device_debug(device, "Using \"%s\" as stable identifying information", name); l = strlen(name); sz = sizeof(sd_id128_t) + l; v = newa(uint8_t, sz); - /* fetch some persistent data unique to this machine */ + /* Fetch some persistent data unique to this machine */ r = sd_id128_get_machine((sd_id128_t*) v); if (r < 0) return r; memcpy(v + sizeof(sd_id128_t), name, l); - /* Let's hash the machine ID plus the device name. We - * use a fixed, but originally randomly created hash - * key here. */ + /* Let's hash the machine ID plus the device name. We use + * a fixed, but originally randomly created hash key here. */ *result = htole64(siphash24(v, sz, HASH_KEY.bytes)); - return 0; } @@ -95,33 +100,12 @@ bool net_match_config(Set *match_mac, char * const *match_drivers, char * const *match_types, char * const *match_names, - Condition *match_host, - Condition *match_virt, - Condition *match_kernel_cmdline, - Condition *match_kernel_version, - Condition *match_arch, const struct ether_addr *dev_mac, const char *dev_path, - const char *dev_parent_driver, const char *dev_driver, const char *dev_type, const char *dev_name) { - if (match_host && condition_test(match_host) <= 0) - return false; - - if (match_virt && condition_test(match_virt) <= 0) - return false; - - if (match_kernel_cmdline && condition_test(match_kernel_cmdline) <= 0) - return false; - - if (match_kernel_version && condition_test(match_kernel_version) <= 0) - return false; - - if (match_arch && condition_test(match_arch) <= 0) - return false; - if (match_mac && (!dev_mac || !set_contains(match_mac, dev_mac))) return false; @@ -152,32 +136,31 @@ int config_parse_net_condition(const char *unit, void *userdata) { ConditionType cond = ltype; - Condition **ret = data; + Condition **list = data, *c; bool negate; - Condition *c; - _cleanup_free_ char *s = NULL; assert(filename); assert(lvalue); assert(rvalue); assert(data); + if (isempty(rvalue)) { + *list = condition_free_list_type(*list, cond); + return 0; + } + negate = rvalue[0] == '!'; if (negate) rvalue++; - s = strdup(rvalue); - if (!s) - return log_oom(); - - c = condition_new(cond, s, false, negate); + c = condition_new(cond, rvalue, false, negate); if (!c) return log_oom(); - if (*ret) - condition_free(*ret); + /* Drop previous assignment. */ + *list = condition_free_list_type(*list, cond); - *ret = c; + LIST_PREPEND(conditions, *list, c); return 0; } @@ -409,16 +392,33 @@ int config_parse_bridge_port_priority( return 0; } -void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) { - unsigned i; +size_t serialize_in_addrs(FILE *f, + const struct in_addr *addresses, + size_t size, + bool with_leading_space, + bool (*predicate)(const struct in_addr *addr)) { + size_t count; + size_t i; assert(f); assert(addresses); - assert(size); - for (i = 0; i < size; i++) - fprintf(f, "%s%s", inet_ntoa(addresses[i]), - (i < (size - 1)) ? " ": ""); + count = 0; + + for (i = 0; i < size; i++) { + char sbuf[INET_ADDRSTRLEN]; + + if (predicate && !predicate(&addresses[i])) + continue; + if (with_leading_space) + fputc(' ', f); + else + with_leading_space = true; + fputs(inet_ntop(AF_INET, &addresses[i], sbuf, sizeof(sbuf)), f); + count++; + } + + return count; } int deserialize_in_addrs(struct in_addr **ret, const char *string) { @@ -452,7 +452,7 @@ int deserialize_in_addrs(struct in_addr **ret, const char *string) { size++; } - *ret = TAKE_PTR(addresses); + *ret = size > 0 ? TAKE_PTR(addresses) : NULL; return size; } @@ -521,6 +521,7 @@ void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, siz fprintf(f, "%s=", key); for (i = 0; i < size; i++) { + char sbuf[INET_ADDRSTRLEN]; struct in_addr dest, gw; uint8_t length; @@ -528,8 +529,8 @@ void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, siz assert_se(sd_dhcp_route_get_gateway(routes[i], &gw) >= 0); assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &length) >= 0); - fprintf(f, "%s/%" PRIu8, inet_ntoa(dest), length); - fprintf(f, ",%s%s", inet_ntoa(gw), (i < (size - 1)) ? " ": ""); + fprintf(f, "%s/%" PRIu8, inet_ntop(AF_INET, &dest, sbuf, sizeof(sbuf)), length); + fprintf(f, ",%s%s", inet_ntop(AF_INET, &gw, sbuf, sizeof(sbuf)), (i < (size - 1)) ? " ": ""); } fputs("\n", f); diff --git a/src/systemd/src/libsystemd-network/network-internal.h b/src/systemd/src/libsystemd-network/network-internal.h index 0c8da848c1..62f5a4a76c 100644 --- a/src/systemd/src/libsystemd-network/network-internal.h +++ b/src/systemd/src/libsystemd-network/network-internal.h @@ -6,9 +6,10 @@ #include "sd-device.h" #include "sd-dhcp-lease.h" -#include "condition.h" #include "conf-parser.h" +#include "def.h" #include "set.h" +#include "strv.h" #define LINK_BRIDGE_PORT_PRIORITY_INVALID 128 #define LINK_BRIDGE_PORT_PRIORITY_MAX 63 @@ -18,14 +19,8 @@ bool net_match_config(Set *match_mac, char * const *match_driver, char * const *match_type, char * const *match_name, - Condition *match_host, - Condition *match_virt, - Condition *match_kernel_cmdline, - Condition *match_kernel_version, - Condition *match_arch, const struct ether_addr *dev_mac, const char *dev_path, - const char *dev_parent_driver, const char *dev_driver, const char *dev_type, const char *dev_name); @@ -40,7 +35,11 @@ CONFIG_PARSER_PROTOTYPE(config_parse_bridge_port_priority); int net_get_unique_predictable_data(sd_device *device, uint64_t *result); const char *net_get_name(sd_device *device); -void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size); +size_t serialize_in_addrs(FILE *f, + const struct in_addr *addresses, + size_t size, + bool with_leading_space, + bool (*predicate)(const struct in_addr *addr)); int deserialize_in_addrs(struct in_addr **addresses, const char *string); void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, size_t size); @@ -54,3 +53,5 @@ int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t /* It is not necessary to add deserialize_dhcp_option(). Use unhexmem() instead. */ int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size); + +#define NETWORK_DIRS ((const char* const*) CONF_PATHS_STRV("systemd/network")) diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-client.c b/src/systemd/src/libsystemd-network/sd-dhcp-client.c index 35fc88ef91..97e1dd3702 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp-client.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp-client.c @@ -24,10 +24,10 @@ #include "event-util.h" #include "hostname-util.h" #include "io-util.h" +#include "memory-util.h" #include "random-util.h" #include "string-util.h" #include "strv.h" -#include "util.h" #define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */ #define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN) @@ -1676,8 +1676,7 @@ static int client_receive_message_udp( sd_dhcp_client *client = userdata; _cleanup_free_ DHCPMessage *message = NULL; - const struct ether_addr zero_mac = {}; - const struct ether_addr *expected_chaddr = NULL; + const uint8_t *expected_chaddr = NULL; uint8_t expected_hlen = 0; ssize_t len, buflen; @@ -1685,6 +1684,12 @@ static int client_receive_message_udp( assert(client); buflen = next_datagram_size_fd(fd); + if (buflen == -ENETDOWN) { + /* the link is down. Don't return an error or the I/O event + source will be disconnected and we won't be able to receive + packets again when the link comes back. */ + return 0; + } if (buflen < 0) return buflen; @@ -1694,7 +1699,8 @@ static int client_receive_message_udp( len = recv(fd, message, buflen, 0); if (len < 0) { - if (IN_SET(errno, EAGAIN, EINTR)) + /* see comment above for why we shouldn't error out on ENETDOWN. */ + if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN)) return 0; return log_dhcp_client_errno(client, errno, @@ -1722,11 +1728,7 @@ static int client_receive_message_udp( if (client->arp_type == ARPHRD_ETHER) { expected_hlen = ETH_ALEN; - expected_chaddr = (const struct ether_addr *) &client->mac_addr; - } else { - /* Non-Ethernet links expect zero chaddr */ - expected_hlen = 0; - expected_chaddr = &zero_mac; + expected_chaddr = &client->mac_addr[0]; } if (message->hlen != expected_hlen) { @@ -1734,7 +1736,7 @@ static int client_receive_message_udp( return 0; } - if (memcmp(&message->chaddr[0], expected_chaddr, ETH_ALEN)) { + if (expected_hlen > 0 && memcmp(&message->chaddr[0], expected_chaddr, expected_hlen)) { log_dhcp_client(client, "Received chaddr does not match expected: ignoring"); return 0; } @@ -1776,6 +1778,8 @@ static int client_receive_message_raw( assert(client); buflen = next_datagram_size_fd(fd); + if (buflen == -ENETDOWN) + return 0; if (buflen < 0) return buflen; @@ -1787,7 +1791,7 @@ static int client_receive_message_raw( len = recvmsg(fd, &msg, 0); if (len < 0) { - if (IN_SET(errno, EAGAIN, EINTR)) + if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN)) return 0; return log_dhcp_client_errno(client, errno, diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c index 13badbf0bf..a16314a9d3 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c @@ -9,6 +9,9 @@ #include <stdio_ext.h> #include <stdlib.h> #include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> #include "sd-dhcp-lease.h" @@ -151,15 +154,15 @@ int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path) { return 0; } -int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr) { +int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, const struct in_addr **addr) { assert_return(lease, -EINVAL); assert_return(addr, -EINVAL); - if (lease->router == 0) + if (lease->router_size <= 0) return -ENODATA; - addr->s_addr = lease->router; - return 0; + *addr = lease->router; + return (int) lease->router_size; } int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) { @@ -261,6 +264,7 @@ static sd_dhcp_lease *dhcp_lease_free(sd_dhcp_lease *lease) { } free(lease->root_path); + free(lease->router); free(lease->timezone); free(lease->hostname); free(lease->domainname); @@ -370,23 +374,6 @@ static int lease_parse_domain(const uint8_t *option, size_t len, char **ret) { return 0; } -static void filter_bogus_addresses(struct in_addr *addresses, size_t *n) { - size_t i, j; - - /* Silently filter DNS/NTP servers supplied to us that do not make outside of the local scope. */ - - for (i = 0, j = 0; i < *n; i ++) { - - if (in4_addr_is_null(addresses+i) || - in4_addr_is_localhost(addresses+i)) - continue; - - addresses[j++] = addresses[i]; - } - - *n = j; -} - static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *n_ret) { assert(option); assert(ret); @@ -408,8 +395,6 @@ static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_add if (!addresses) return -ENOMEM; - filter_bogus_addresses(addresses, &n_addresses); - free(*ret); *ret = addresses; *n_ret = n_addresses; @@ -554,11 +539,9 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void break; case SD_DHCP_OPTION_ROUTER: - if (len >= 4) { - r = lease_parse_be32(option, 4, &lease->router); - if (r < 0) - log_debug_errno(r, "Failed to parse router address, ignoring: %m"); - } + r = lease_parse_in_addrs(option, len, &lease->router, &lease->router_size); + if (r < 0) + log_debug_errno(r, "Failed to parse router addresses, ignoring: %m"); break; case SD_DHCP_OPTION_DOMAIN_NAME_SERVER: @@ -820,7 +803,6 @@ int dhcp_lease_new(sd_dhcp_lease **ret) { if (!lease) return -ENOMEM; - lease->router = INADDR_ANY; lease->n_ref = 1; *ret = lease; @@ -835,6 +817,7 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { const struct in_addr *addresses; const void *client_id, *data; size_t client_id_len, data_len; + char sbuf[INET_ADDRSTRLEN]; const char *string; uint16_t mtu; _cleanup_free_ sd_dhcp_route **routes = NULL; @@ -857,27 +840,30 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { r = sd_dhcp_lease_get_address(lease, &address); if (r >= 0) - fprintf(f, "ADDRESS=%s\n", inet_ntoa(address)); + fprintf(f, "ADDRESS=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf))); r = sd_dhcp_lease_get_netmask(lease, &address); if (r >= 0) - fprintf(f, "NETMASK=%s\n", inet_ntoa(address)); + fprintf(f, "NETMASK=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf))); - r = sd_dhcp_lease_get_router(lease, &address); - if (r >= 0) - fprintf(f, "ROUTER=%s\n", inet_ntoa(address)); + r = sd_dhcp_lease_get_router(lease, &addresses); + if (r > 0) { + fputs("ROUTER=", f); + serialize_in_addrs(f, addresses, r, false, NULL); + fputc('\n', f); + } r = sd_dhcp_lease_get_server_identifier(lease, &address); if (r >= 0) - fprintf(f, "SERVER_ADDRESS=%s\n", inet_ntoa(address)); + fprintf(f, "SERVER_ADDRESS=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf))); r = sd_dhcp_lease_get_next_server(lease, &address); if (r >= 0) - fprintf(f, "NEXT_SERVER=%s\n", inet_ntoa(address)); + fprintf(f, "NEXT_SERVER=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf))); r = sd_dhcp_lease_get_broadcast(lease, &address); if (r >= 0) - fprintf(f, "BROADCAST=%s\n", inet_ntoa(address)); + fprintf(f, "BROADCAST=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf))); r = sd_dhcp_lease_get_mtu(lease, &mtu); if (r >= 0) @@ -898,15 +884,15 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { r = sd_dhcp_lease_get_dns(lease, &addresses); if (r > 0) { fputs("DNS=", f); - serialize_in_addrs(f, addresses, r); - fputs("\n", f); + serialize_in_addrs(f, addresses, r, false, NULL); + fputc('\n', f); } r = sd_dhcp_lease_get_ntp(lease, &addresses); if (r > 0) { fputs("NTP=", f); - serialize_in_addrs(f, addresses, r); - fputs("\n", f); + serialize_in_addrs(f, addresses, r, false, NULL); + fputc('\n', f); } r = sd_dhcp_lease_get_domainname(lease, &string); @@ -917,7 +903,7 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { if (r > 0) { fputs("DOMAIN_SEARCH_LIST=", f); fputstrv(f, search_domains, NULL, NULL); - fputs("\n", f); + fputc('\n', f); } r = sd_dhcp_lease_get_hostname(lease, &string); @@ -1080,9 +1066,11 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { } if (router) { - r = inet_pton(AF_INET, router, &lease->router); - if (r <= 0) - log_debug("Failed to parse router %s, ignoring.", router); + r = deserialize_in_addrs(&lease->router, router); + if (r < 0) + log_debug_errno(r, "Failed to deserialize router addresses %s, ignoring: %m", router); + else + lease->router_size = r; } if (netmask) { diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c index 593ffd1b64..68b41dfb6c 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c @@ -1112,6 +1112,12 @@ static int client_receive_message( assert(client->event); buflen = next_datagram_size_fd(fd); + if (buflen == -ENETDOWN) { + /* the link is down. Don't return an error or the I/O event + source will be disconnected and we won't be able to receive + packets again when the link comes back. */ + return 0; + } if (buflen < 0) return buflen; @@ -1121,7 +1127,8 @@ static int client_receive_message( len = recv(fd, message, buflen, 0); if (len < 0) { - if (IN_SET(errno, EAGAIN, EINTR)) + /* see comment above for why we shouldn't error out on ENETDOWN. */ + if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN)) return 0; return log_dhcp6_client_errno(client, errno, "Could not receive message from UDP socket: %m"); diff --git a/src/systemd/src/libsystemd-network/sd-ipv4acd.c b/src/systemd/src/libsystemd-network/sd-ipv4acd.c index 59359aec79..c8e34497fd 100644 --- a/src/systemd/src/libsystemd-network/sd-ipv4acd.c +++ b/src/systemd/src/libsystemd-network/sd-ipv4acd.c @@ -21,7 +21,7 @@ #include "random-util.h" #include "siphash24.h" #include "string-util.h" -#include "util.h" +#include "time-util.h" /* Constants from the RFC */ #define PROBE_WAIT_USEC (1U * USEC_PER_SEC) diff --git a/src/systemd/src/libsystemd-network/sd-ipv4ll.c b/src/systemd/src/libsystemd-network/sd-ipv4ll.c index e451dff744..a59a952326 100644 --- a/src/systemd/src/libsystemd-network/sd-ipv4ll.c +++ b/src/systemd/src/libsystemd-network/sd-ipv4ll.c @@ -218,28 +218,21 @@ static int ipv4ll_pick_address(sd_ipv4ll *ll) { return sd_ipv4ll_set_address(ll, &(struct in_addr) { addr }); } -int sd_ipv4ll_restart(sd_ipv4ll *ll) { - ll->address = 0; - - return sd_ipv4ll_start(ll); -} - #define MAC_HASH_KEY SD_ID128_MAKE(df,04,22,98,3f,ad,14,52,f9,87,2e,d1,9c,70,e2,f2) -int sd_ipv4ll_start(sd_ipv4ll *ll) { +static int ipv4ll_start_internal(sd_ipv4ll *ll, bool reset_generation) { int r; bool picked_address = false; assert_return(ll, -EINVAL); assert_return(!ether_addr_is_null(&ll->mac), -EINVAL); - assert_return(sd_ipv4ll_is_running(ll) == 0, -EBUSY); /* If no random seed is set, generate some from the MAC address */ if (!ll->seed_set) ll->seed.value = htole64(siphash24(ll->mac.ether_addr_octet, ETH_ALEN, MAC_HASH_KEY.bytes)); - /* Restart the generation counter. */ - ll->seed.generation = 0; + if (reset_generation) + ll->seed.generation = 0; if (ll->address == 0) { r = ipv4ll_pick_address(ll); @@ -263,6 +256,19 @@ int sd_ipv4ll_start(sd_ipv4ll *ll) { return 0; } +int sd_ipv4ll_start(sd_ipv4ll *ll) { + assert_return(ll, -EINVAL); + assert_return(sd_ipv4ll_is_running(ll) == 0, -EBUSY); + + return ipv4ll_start_internal(ll, true); +} + +int sd_ipv4ll_restart(sd_ipv4ll *ll) { + ll->address = 0; + + return ipv4ll_start_internal(ll, false); +} + static void ipv4ll_client_notify(sd_ipv4ll *ll, int event) { assert(ll); @@ -298,11 +304,7 @@ void ipv4ll_on_acd(sd_ipv4acd *acd, int event, void *userdata) { ll->claimed_address = 0; } else { - r = ipv4ll_pick_address(ll); - if (r < 0) - goto error; - - r = sd_ipv4acd_start(ll->acd); + r = sd_ipv4ll_restart(ll); if (r < 0) goto error; } diff --git a/src/systemd/src/libsystemd-network/sd-lldp.c b/src/systemd/src/libsystemd-network/sd-lldp.c index 969fc71051..1f28c5731f 100644 --- a/src/systemd/src/libsystemd-network/sd-lldp.c +++ b/src/systemd/src/libsystemd-network/sd-lldp.c @@ -13,7 +13,9 @@ #include "lldp-internal.h" #include "lldp-neighbor.h" #include "lldp-network.h" +#include "memory-util.h" #include "socket-util.h" +#include "sort-util.h" #include "string-table.h" #define LLDP_DEFAULT_NEIGHBORS_MAX 128U diff --git a/src/systemd/src/libsystemd/sd-event/sd-event.c b/src/systemd/src/libsystemd/sd-event/sd-event.c index 04ba7e2574..1987f279eb 100644 --- a/src/systemd/src/libsystemd/sd-event/sd-event.c +++ b/src/systemd/src/libsystemd/sd-event/sd-event.c @@ -15,6 +15,7 @@ #include "hashmap.h" #include "list.h" #include "macro.h" +#include "memory-util.h" #include "missing.h" #include "prioq.h" #include "process-util.h" @@ -23,7 +24,6 @@ #include "string-table.h" #include "string-util.h" #include "time-util.h" -#include "util.h" #define DEFAULT_ACCURACY_USEC (250 * USEC_PER_MSEC) @@ -3116,7 +3116,7 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) { timeout = 0; m = epoll_wait(e->epoll_fd, ev_queue, ev_queue_max, - timeout == (uint64_t) -1 ? -1 : (int) ((timeout + USEC_PER_MSEC - 1) / USEC_PER_MSEC)); + timeout == (uint64_t) -1 ? -1 : (int) DIV_ROUND_UP(timeout, USEC_PER_MSEC)); if (m < 0) { if (errno == EINTR) { e->state = SD_EVENT_PENDING; diff --git a/src/systemd/src/libsystemd/sd-id128/sd-id128.c b/src/systemd/src/libsystemd/sd-id128/sd-id128.c index e72af1593c..e5f82b8863 100644 --- a/src/systemd/src/libsystemd/sd-id128/sd-id128.c +++ b/src/systemd/src/libsystemd/sd-id128/sd-id128.c @@ -117,7 +117,6 @@ _public_ int sd_id128_get_boot(sd_id128_t *ret) { } static int get_invocation_from_keyring(sd_id128_t *ret) { - _cleanup_free_ char *description = NULL; char *d, *p, *g, *u, *e; unsigned long perms; @@ -136,7 +135,7 @@ static int get_invocation_from_keyring(sd_id128_t *ret) { if (key == -1) { /* Keyring support not available? No invocation key stored? */ if (IN_SET(errno, ENOSYS, ENOKEY)) - return 0; + return -ENXIO; return -errno; } @@ -212,7 +211,19 @@ static int get_invocation_from_keyring(sd_id128_t *ret) { if (c != sizeof(sd_id128_t)) return -EIO; - return 1; + return 0; +} + +static int get_invocation_from_environment(sd_id128_t *ret) { + const char *e; + + assert(ret); + + e = secure_getenv("INVOCATION_ID"); + if (!e) + return -ENXIO; + + return sd_id128_from_string(e, ret); } _public_ int sd_id128_get_invocation(sd_id128_t *ret) { @@ -222,31 +233,17 @@ _public_ int sd_id128_get_invocation(sd_id128_t *ret) { assert_return(ret, -EINVAL); if (sd_id128_is_null(saved_invocation_id)) { + /* We first check the environment. The environment variable is primarily relevant for user + * services, and sufficiently safe as long as no privilege boundary is involved. */ + r = get_invocation_from_environment(&saved_invocation_id); + if (r < 0 && r != -ENXIO) + return r; - /* We first try to read the invocation ID from the kernel keyring. This has the benefit that it is not - * fakeable by unprivileged code. If the information is not available in the keyring, we use - * $INVOCATION_ID but ignore the data if our process was called by less privileged code - * (i.e. secure_getenv() instead of getenv()). - * - * The kernel keyring is only relevant for system services (as for user services we don't store the - * invocation ID in the keyring, as there'd be no trust benefit in that). The environment variable is - * primarily relevant for user services, and sufficiently safe as no privilege boundary is involved. */ - + /* The kernel keyring is relevant for system services (as for user services we don't store + * the invocation ID in the keyring, as there'd be no trust benefit in that). */ r = get_invocation_from_keyring(&saved_invocation_id); if (r < 0) return r; - - if (r == 0) { - const char *e; - - e = secure_getenv("INVOCATION_ID"); - if (!e) - return -ENXIO; - - r = sd_id128_from_string(e, &saved_invocation_id); - if (r < 0) - return r; - } } *ret = saved_invocation_id; diff --git a/src/systemd/src/systemd/sd-dhcp-lease.h b/src/systemd/src/systemd/sd-dhcp-lease.h index 4875f10555..d299c79121 100644 --- a/src/systemd/src/systemd/sd-dhcp-lease.h +++ b/src/systemd/src/systemd/sd-dhcp-lease.h @@ -39,7 +39,7 @@ int sd_dhcp_lease_get_t1(sd_dhcp_lease *lease, uint32_t *t1); int sd_dhcp_lease_get_t2(sd_dhcp_lease *lease, uint32_t *t2); int sd_dhcp_lease_get_broadcast(sd_dhcp_lease *lease, struct in_addr *addr); int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr); -int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr); +int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, const struct in_addr **addr); int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr); int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr); int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr); diff --git a/src/systemd/src/systemd/sd-event.h b/src/systemd/src/systemd/sd-event.h index 787a12f241..7bb8609376 100644 --- a/src/systemd/src/systemd/sd-event.h +++ b/src/systemd/src/systemd/sd-event.h @@ -71,7 +71,7 @@ typedef int (*sd_event_handler_t)(sd_event_source *s, void *userdata); typedef int (*sd_event_io_handler_t)(sd_event_source *s, int fd, uint32_t revents, void *userdata); typedef int (*sd_event_time_handler_t)(sd_event_source *s, uint64_t usec, void *userdata); typedef int (*sd_event_signal_handler_t)(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata); -#if defined _GNU_SOURCE || _POSIX_C_SOURCE >= 199309L +#if defined _GNU_SOURCE || (defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 199309L) typedef int (*sd_event_child_handler_t)(sd_event_source *s, const siginfo_t *si, void *userdata); #else typedef void* sd_event_child_handler_t; |