summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/basic/architecture.c2
-rw-r--r--src/basic/cgroup-util.h5
-rw-r--r--src/basic/fd-util.c4
-rw-r--r--src/basic/fs-util.c8
-rw-r--r--src/basic/missing_syscall.h19
-rw-r--r--src/basic/missing_syscall_def.h102
-rw-r--r--src/basic/missing_syscalls.py3
-rw-r--r--src/basic/string-util.c12
-rw-r--r--src/basic/string-util.h5
-rw-r--r--src/basic/strv.h12
-rw-r--r--src/basic/user-util.c2
-rw-r--r--src/basic/virt.c13
-rw-r--r--src/core/dbus-cgroup.c2
-rw-r--r--src/core/dbus-execute.c4
-rw-r--r--src/core/execute.c12
-rw-r--r--src/core/kmod-setup.c36
-rw-r--r--src/core/load-fragment.c2
-rw-r--r--src/core/service.c3
-rw-r--r--src/libsystemd/sd-bus/bus-socket.c22
-rw-r--r--src/libsystemd/sd-bus/sd-bus.c18
-rw-r--r--src/libsystemd/sd-bus/test-bus-watch-bind.c9
-rw-r--r--src/libsystemd/sd-id128/id128-util.c2
-rw-r--r--src/login/user-runtime-dir.c2
-rw-r--r--src/machine/machinectl.c2
-rw-r--r--src/network/wait-online/manager.c4
-rw-r--r--src/nspawn/nspawn.c6
-rw-r--r--src/portable/portablectl.c2
-rw-r--r--src/resolve/resolved-dns-dnssec.c21
-rw-r--r--src/resolve/resolved-dns-dnssec.h9
-rw-r--r--src/resolve/resolved-dns-transaction.c19
-rw-r--r--src/shared/base-filesystem.c2
-rw-r--r--src/shared/bus-unit-util.c6
-rw-r--r--src/shared/conf-parser.c2
-rw-r--r--src/shared/efi-loader.c11
-rwxr-xr-xsrc/shared/generate-syscall-list.py9
-rw-r--r--src/shared/keyring-util.c21
-rw-r--r--src/shared/loop-util.c2
-rw-r--r--src/shared/machine-id-setup.c2
-rw-r--r--src/shared/seccomp-util.c25
-rw-r--r--src/shared/utmp-wtmp.c1
-rw-r--r--src/systemd/sd-gpt.h2
-rw-r--r--src/sysusers/sysusers.c8
-rw-r--r--src/test/test-calendarspec.c9
-rw-r--r--src/test/test-date.c3
-rw-r--r--src/test/test-execute.c2
-rw-r--r--src/test/test-fs-util.c38
-rw-r--r--src/test/test-namespace.c2
-rw-r--r--src/test/test-nss-hosts.c6
-rw-r--r--src/test/test-seccomp.c28
-rw-r--r--src/test/test-time-util.c3
-rw-r--r--src/timesync/timesyncd-manager.c35
-rw-r--r--src/timesync/timesyncd-manager.h1
-rw-r--r--src/tmpfiles/tmpfiles.c8
53 files changed, 423 insertions, 165 deletions
diff --git a/src/basic/architecture.c b/src/basic/architecture.c
index 773ee3c..488367c 100644
--- a/src/basic/architecture.c
+++ b/src/basic/architecture.c
@@ -70,7 +70,7 @@ Architecture uname_architecture(void) {
{ "parisc64", ARCHITECTURE_PARISC64 },
{ "parisc", ARCHITECTURE_PARISC },
-#elif defined(__loongarch64)
+#elif defined(__loongarch_lp64)
{ "loongarch64", ARCHITECTURE_LOONGARCH64 },
#elif defined(__m68k__)
diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h
index df6d5b7..1904e84 100644
--- a/src/basic/cgroup-util.h
+++ b/src/basic/cgroup-util.h
@@ -66,10 +66,13 @@ typedef enum CGroupMask {
/* All real cgroup v2 controllers */
CGROUP_MASK_V2 = CGROUP_MASK_CPU|CGROUP_MASK_CPUSET|CGROUP_MASK_IO|CGROUP_MASK_MEMORY|CGROUP_MASK_PIDS,
+ /* All controllers we want to delegate in case of Delegate=yes. Which are prety much the v2 controllers only, as delegation on v1 is not safe, and bpf stuff isn't a real controller */
+ CGROUP_MASK_DELEGATE = CGROUP_MASK_V2,
+
/* All cgroup v2 BPF pseudo-controllers */
CGROUP_MASK_BPF = CGROUP_MASK_BPF_FIREWALL|CGROUP_MASK_BPF_DEVICES|CGROUP_MASK_BPF_FOREIGN|CGROUP_MASK_BPF_SOCKET_BIND|CGROUP_MASK_BPF_RESTRICT_NETWORK_INTERFACES,
- _CGROUP_MASK_ALL = CGROUP_CONTROLLER_TO_MASK(_CGROUP_CONTROLLER_MAX) - 1
+ _CGROUP_MASK_ALL = CGROUP_CONTROLLER_TO_MASK(_CGROUP_CONTROLLER_MAX) - 1,
} CGroupMask;
static inline CGroupMask CGROUP_MASK_EXTEND_JOINED(CGroupMask mask) {
diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c
index 66bb756..ad7bd63 100644
--- a/src/basic/fd-util.c
+++ b/src/basic/fd-util.c
@@ -284,7 +284,7 @@ static int close_all_fds_special_case(const int except[], size_t n_except) {
case 0:
/* Close everything. Yay! */
- if (close_range(3, -1, 0) >= 0)
+ if (close_range(3, INT_MAX, 0) >= 0)
return 1;
if (ERRNO_IS_NOT_SUPPORTED(errno) || ERRNO_IS_PRIVILEGE(errno)) {
@@ -395,7 +395,7 @@ int close_all_fds(const int except[], size_t n_except) {
if (sorted[n_sorted-1] >= INT_MAX) /* Dont let the addition below overflow */
return 0;
- if (close_range(sorted[n_sorted-1] + 1, -1, 0) >= 0)
+ if (close_range(sorted[n_sorted-1] + 1, INT_MAX, 0) >= 0)
return 0;
if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c
index 6b757bd..d71c07c 100644
--- a/src/basic/fs-util.c
+++ b/src/basic/fs-util.c
@@ -118,7 +118,11 @@ int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char
int readlinkat_malloc(int fd, const char *p, char **ret) {
size_t l = PATH_MAX;
- assert(p);
+ assert(fd >= 0 || fd == AT_FDCWD);
+
+ if (fd < 0 && isempty(p))
+ return -EISDIR; /* In this case, the fd points to the current working directory, and is
+ * definitely not a symlink. Let's return earlier. */
for (;;) {
_cleanup_free_ char *c = NULL;
@@ -128,7 +132,7 @@ int readlinkat_malloc(int fd, const char *p, char **ret) {
if (!c)
return -ENOMEM;
- n = readlinkat(fd, p, c, l);
+ n = readlinkat(fd, strempty(p), c, l);
if (n < 0)
return -errno;
diff --git a/src/basic/missing_syscall.h b/src/basic/missing_syscall.h
index d54e59f..47c5177 100644
--- a/src/basic/missing_syscall.h
+++ b/src/basic/missing_syscall.h
@@ -383,23 +383,14 @@ static inline int missing_execveat(int dirfd, const char *pathname,
/* ======================================================================= */
#if !HAVE_CLOSE_RANGE
-static inline int missing_close_range(int first_fd, int end_fd, unsigned flags) {
+static inline int missing_close_range(unsigned first_fd, unsigned end_fd, unsigned flags) {
# ifdef __NR_close_range
/* Kernel-side the syscall expects fds as unsigned integers (just like close() actually), while
- * userspace exclusively uses signed integers for fds. We don't know just yet how glibc is going to
- * wrap this syscall, but let's assume it's going to be similar to what they do for close(),
- * i.e. make the same unsigned → signed type change from the raw kernel syscall compared to the
- * userspace wrapper. There's only one caveat for this: unlike for close() there's the special
- * UINT_MAX fd value for the 'end_fd' argument. Let's safely map that to -1 here. And let's refuse
- * any other negative values. */
- if ((first_fd < 0) || (end_fd < 0 && end_fd != -1)) {
- errno = -EBADF;
- return -1;
- }
-
+ * userspace exclusively uses signed integers for fds. glibc chose to expose it 1:1 however, hence we
+ * do so here too, even if we end up passing signed fds to it most of the time. */
return syscall(__NR_close_range,
- (unsigned) first_fd,
- end_fd == -1 ? UINT_MAX : (unsigned) end_fd, /* Of course, the compiler should figure out that this is the identity mapping IRL */
+ first_fd,
+ end_fd,
flags);
# else
errno = ENOSYS;
diff --git a/src/basic/missing_syscall_def.h b/src/basic/missing_syscall_def.h
index 67cae70..8906f40 100644
--- a/src/basic/missing_syscall_def.h
+++ b/src/basic/missing_syscall_def.h
@@ -14,7 +14,7 @@
# elif defined(__arm__)
# elif defined(__i386__)
# elif defined(__ia64__)
-# elif defined(__loongarch64)
+# elif defined(__loongarch_lp64)
# elif defined(__m68k__)
# elif defined(_MIPS_SIM)
# if _MIPS_SIM == _MIPS_SIM_ABI32
@@ -55,7 +55,7 @@
# define systemd_NR_bpf 357
# elif defined(__ia64__)
# define systemd_NR_bpf 1341
-# elif defined(__loongarch64)
+# elif defined(__loongarch_lp64)
# define systemd_NR_bpf 280
# elif defined(__m68k__)
# define systemd_NR_bpf 354
@@ -123,7 +123,7 @@ assert_cc(__NR_bpf == systemd_NR_bpf);
# define systemd_NR_close_range 436
# elif defined(__ia64__)
# define systemd_NR_close_range 1460
-# elif defined(__loongarch64)
+# elif defined(__loongarch_lp64)
# define systemd_NR_close_range 436
# elif defined(__m68k__)
# define systemd_NR_close_range 436
@@ -191,7 +191,7 @@ assert_cc(__NR_close_range == systemd_NR_close_range);
# define systemd_NR_copy_file_range 377
# elif defined(__ia64__)
# define systemd_NR_copy_file_range 1347
-# elif defined(__loongarch64)
+# elif defined(__loongarch_lp64)
# define systemd_NR_copy_file_range 285
# elif defined(__m68k__)
# define systemd_NR_copy_file_range 376
@@ -314,6 +314,74 @@ assert_cc(__NR_epoll_pwait2 == systemd_NR_epoll_pwait2);
# endif
#endif
+#ifndef __IGNORE_fchmodat2
+# if defined(__aarch64__)
+# define systemd_NR_fchmodat2 452
+# elif defined(__alpha__)
+# define systemd_NR_fchmodat2 562
+# elif defined(__arc__) || defined(__tilegx__)
+# define systemd_NR_fchmodat2 452
+# elif defined(__arm__)
+# define systemd_NR_fchmodat2 452
+# elif defined(__i386__)
+# define systemd_NR_fchmodat2 452
+# elif defined(__ia64__)
+# define systemd_NR_fchmodat2 1476
+# elif defined(__loongarch_lp64)
+# define systemd_NR_fchmodat2 452
+# elif defined(__m68k__)
+# define systemd_NR_fchmodat2 452
+# elif defined(_MIPS_SIM)
+# if _MIPS_SIM == _MIPS_SIM_ABI32
+# define systemd_NR_fchmodat2 4452
+# elif _MIPS_SIM == _MIPS_SIM_NABI32
+# define systemd_NR_fchmodat2 6452
+# elif _MIPS_SIM == _MIPS_SIM_ABI64
+# define systemd_NR_fchmodat2 5452
+# else
+# error "Unknown MIPS ABI"
+# endif
+# elif defined(__hppa__)
+# define systemd_NR_fchmodat2 452
+# elif defined(__powerpc__)
+# define systemd_NR_fchmodat2 452
+# elif defined(__riscv)
+# if __riscv_xlen == 32
+# define systemd_NR_fchmodat2 452
+# elif __riscv_xlen == 64
+# define systemd_NR_fchmodat2 452
+# else
+# error "Unknown RISC-V ABI"
+# endif
+# elif defined(__s390__)
+# define systemd_NR_fchmodat2 452
+# elif defined(__sparc__)
+# define systemd_NR_fchmodat2 452
+# elif defined(__x86_64__)
+# if defined(__ILP32__)
+# define systemd_NR_fchmodat2 (452 | /* __X32_SYSCALL_BIT */ 0x40000000)
+# else
+# define systemd_NR_fchmodat2 452
+# endif
+# elif !defined(missing_arch_template)
+# warning "fchmodat2() syscall number is unknown for your architecture"
+# endif
+
+/* may be an (invalid) negative number due to libseccomp, see PR 13319 */
+# if defined __NR_fchmodat2 && __NR_fchmodat2 >= 0
+# if defined systemd_NR_fchmodat2
+assert_cc(__NR_fchmodat2 == systemd_NR_fchmodat2);
+# endif
+# else
+# if defined __NR_fchmodat2
+# undef __NR_fchmodat2
+# endif
+# if defined systemd_NR_fchmodat2 && systemd_NR_fchmodat2 >= 0
+# define __NR_fchmodat2 systemd_NR_fchmodat2
+# endif
+# endif
+#endif
+
#ifndef __IGNORE_getrandom
# if defined(__aarch64__)
# define systemd_NR_getrandom 278
@@ -327,7 +395,7 @@ assert_cc(__NR_epoll_pwait2 == systemd_NR_epoll_pwait2);
# define systemd_NR_getrandom 355
# elif defined(__ia64__)
# define systemd_NR_getrandom 1339
-# elif defined(__loongarch64)
+# elif defined(__loongarch_lp64)
# define systemd_NR_getrandom 278
# elif defined(__m68k__)
# define systemd_NR_getrandom 352
@@ -395,7 +463,7 @@ assert_cc(__NR_getrandom == systemd_NR_getrandom);
# define systemd_NR_memfd_create 356
# elif defined(__ia64__)
# define systemd_NR_memfd_create 1340
-# elif defined(__loongarch64)
+# elif defined(__loongarch_lp64)
# define systemd_NR_memfd_create 279
# elif defined(__m68k__)
# define systemd_NR_memfd_create 353
@@ -463,7 +531,7 @@ assert_cc(__NR_memfd_create == systemd_NR_memfd_create);
# define systemd_NR_mount_setattr 442
# elif defined(__ia64__)
# define systemd_NR_mount_setattr 1466
-# elif defined(__loongarch64)
+# elif defined(__loongarch_lp64)
# define systemd_NR_mount_setattr 442
# elif defined(__m68k__)
# define systemd_NR_mount_setattr 442
@@ -531,7 +599,7 @@ assert_cc(__NR_mount_setattr == systemd_NR_mount_setattr);
# define systemd_NR_move_mount 429
# elif defined(__ia64__)
# define systemd_NR_move_mount 1453
-# elif defined(__loongarch64)
+# elif defined(__loongarch_lp64)
# define systemd_NR_move_mount 429
# elif defined(__m68k__)
# define systemd_NR_move_mount 429
@@ -599,7 +667,7 @@ assert_cc(__NR_move_mount == systemd_NR_move_mount);
# define systemd_NR_name_to_handle_at 341
# elif defined(__ia64__)
# define systemd_NR_name_to_handle_at 1326
-# elif defined(__loongarch64)
+# elif defined(__loongarch_lp64)
# define systemd_NR_name_to_handle_at 264
# elif defined(__m68k__)
# define systemd_NR_name_to_handle_at 340
@@ -667,7 +735,7 @@ assert_cc(__NR_name_to_handle_at == systemd_NR_name_to_handle_at);
# define systemd_NR_open_tree 428
# elif defined(__ia64__)
# define systemd_NR_open_tree 1452
-# elif defined(__loongarch64)
+# elif defined(__loongarch_lp64)
# define systemd_NR_open_tree 428
# elif defined(__m68k__)
# define systemd_NR_open_tree 428
@@ -735,7 +803,7 @@ assert_cc(__NR_open_tree == systemd_NR_open_tree);
# define systemd_NR_openat2 437
# elif defined(__ia64__)
# define systemd_NR_openat2 1461
-# elif defined(__loongarch64)
+# elif defined(__loongarch_lp64)
# define systemd_NR_openat2 437
# elif defined(__m68k__)
# define systemd_NR_openat2 437
@@ -803,7 +871,7 @@ assert_cc(__NR_openat2 == systemd_NR_openat2);
# define systemd_NR_pidfd_open 434
# elif defined(__ia64__)
# define systemd_NR_pidfd_open 1458
-# elif defined(__loongarch64)
+# elif defined(__loongarch_lp64)
# define systemd_NR_pidfd_open 434
# elif defined(__m68k__)
# define systemd_NR_pidfd_open 434
@@ -871,7 +939,7 @@ assert_cc(__NR_pidfd_open == systemd_NR_pidfd_open);
# define systemd_NR_pidfd_send_signal 424
# elif defined(__ia64__)
# define systemd_NR_pidfd_send_signal 1448
-# elif defined(__loongarch64)
+# elif defined(__loongarch_lp64)
# define systemd_NR_pidfd_send_signal 424
# elif defined(__m68k__)
# define systemd_NR_pidfd_send_signal 424
@@ -939,7 +1007,7 @@ assert_cc(__NR_pidfd_send_signal == systemd_NR_pidfd_send_signal);
# define systemd_NR_pkey_mprotect 380
# elif defined(__ia64__)
# define systemd_NR_pkey_mprotect 1354
-# elif defined(__loongarch64)
+# elif defined(__loongarch_lp64)
# define systemd_NR_pkey_mprotect 288
# elif defined(__m68k__)
# define systemd_NR_pkey_mprotect 381
@@ -1007,7 +1075,7 @@ assert_cc(__NR_pkey_mprotect == systemd_NR_pkey_mprotect);
# define systemd_NR_renameat2 353
# elif defined(__ia64__)
# define systemd_NR_renameat2 1338
-# elif defined(__loongarch64)
+# elif defined(__loongarch_lp64)
# define systemd_NR_renameat2 276
# elif defined(__m68k__)
# define systemd_NR_renameat2 351
@@ -1075,7 +1143,7 @@ assert_cc(__NR_renameat2 == systemd_NR_renameat2);
# define systemd_NR_setns 346
# elif defined(__ia64__)
# define systemd_NR_setns 1330
-# elif defined(__loongarch64)
+# elif defined(__loongarch_lp64)
# define systemd_NR_setns 268
# elif defined(__m68k__)
# define systemd_NR_setns 344
@@ -1143,7 +1211,7 @@ assert_cc(__NR_setns == systemd_NR_setns);
# define systemd_NR_statx 383
# elif defined(__ia64__)
# define systemd_NR_statx 1350
-# elif defined(__loongarch64)
+# elif defined(__loongarch_lp64)
# define systemd_NR_statx 291
# elif defined(__m68k__)
# define systemd_NR_statx 379
diff --git a/src/basic/missing_syscalls.py b/src/basic/missing_syscalls.py
index 642d4d9..4b61c1c 100644
--- a/src/basic/missing_syscalls.py
+++ b/src/basic/missing_syscalls.py
@@ -10,6 +10,7 @@ SYSCALLS = [
'close_range',
'copy_file_range',
'epoll_pwait2',
+ 'fchmodat2',
'getrandom',
'memfd_create',
'mount_setattr',
@@ -60,7 +61,7 @@ DEF_TEMPLATE_B = '''\
# define systemd_NR_{syscall} {nr_i386}
# elif defined(__ia64__)
# define systemd_NR_{syscall} {nr_ia64}
-# elif defined(__loongarch64)
+# elif defined(__loongarch_lp64)
# define systemd_NR_{syscall} {nr_loongarch64}
# elif defined(__m68k__)
# define systemd_NR_{syscall} {nr_m68k}
diff --git a/src/basic/string-util.c b/src/basic/string-util.c
index 17d35fe..8a806e9 100644
--- a/src/basic/string-util.c
+++ b/src/basic/string-util.c
@@ -1202,3 +1202,15 @@ size_t strspn_from_end(const char *str, const char *accept) {
return n;
}
+
+char *startswith_strv(const char *string, char **strv) {
+ char *found = NULL;
+
+ STRV_FOREACH(i, strv) {
+ found = startswith(string, *i);
+ if (found)
+ break;
+ }
+
+ return found;
+}
diff --git a/src/basic/string-util.h b/src/basic/string-util.h
index 913a96f..6edfaef 100644
--- a/src/basic/string-util.h
+++ b/src/basic/string-util.h
@@ -243,3 +243,8 @@ bool streq_skip_trailing_chars(const char *s1, const char *s2, const char *ok);
char *string_replace_char(char *str, char old_char, char new_char);
size_t strspn_from_end(const char *str, const char *accept);
+
+char *startswith_strv(const char *string, char **strv);
+
+#define STARTSWITH_SET(p, ...) \
+ startswith_strv(p, STRV_MAKE(__VA_ARGS__))
diff --git a/src/basic/strv.h b/src/basic/strv.h
index bda8cbf..8857c47 100644
--- a/src/basic/strv.h
+++ b/src/basic/strv.h
@@ -206,18 +206,6 @@ void strv_print(char * const *l);
_x && strv_contains_case(STRV_MAKE(__VA_ARGS__), _x); \
})
-#define STARTSWITH_SET(p, ...) \
- ({ \
- const char *_p = (p); \
- char *_found = NULL; \
- STRV_FOREACH(_i, STRV_MAKE(__VA_ARGS__)) { \
- _found = startswith(_p, *_i); \
- if (_found) \
- break; \
- } \
- _found; \
- })
-
#define ENDSWITH_SET(p, ...) \
({ \
const char *_p = (p); \
diff --git a/src/basic/user-util.c b/src/basic/user-util.c
index 519e788..8823e73 100644
--- a/src/basic/user-util.c
+++ b/src/basic/user-util.c
@@ -313,7 +313,7 @@ int get_user_creds(
if (shell) {
if (FLAGS_SET(flags, USER_CREDS_CLEAN) &&
(isempty(p->pw_shell) ||
- !path_is_valid(p->pw_dir) ||
+ !path_is_valid(p->pw_shell) ||
!path_is_absolute(p->pw_shell) ||
is_nologin_shell(p->pw_shell)))
*shell = NULL;
diff --git a/src/basic/virt.c b/src/basic/virt.c
index c2ed8d0..6ea1854 100644
--- a/src/basic/virt.c
+++ b/src/basic/virt.c
@@ -97,7 +97,7 @@ static Virtualization detect_vm_cpuid(void) {
}
static Virtualization detect_vm_device_tree(void) {
-#if defined(__arm__) || defined(__aarch64__) || defined(__powerpc__) || defined(__powerpc64__)
+#if defined(__arm__) || defined(__aarch64__) || defined(__powerpc__) || defined(__powerpc64__) || defined(__riscv)
_cleanup_free_ char *hvtype = NULL;
int r;
@@ -154,7 +154,7 @@ static Virtualization detect_vm_device_tree(void) {
#endif
}
-#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || defined(__loongarch64)
+#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || defined(__loongarch_lp64) || defined(__riscv)
static Virtualization detect_vm_dmi_vendor(void) {
static const char* const dmi_vendors[] = {
"/sys/class/dmi/id/product_name", /* Test this before sys_vendor to detect KVM over QEMU */
@@ -245,10 +245,10 @@ static int detect_vm_smbios(void) {
log_debug("DMI BIOS Extension table does not indicate virtualization.");
return SMBIOS_VM_BIT_UNSET;
}
-#endif /* defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || defined(__loongarch64) */
+#endif /* defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || defined(__loongarch_lp64) */
static Virtualization detect_vm_dmi(void) {
-#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || defined(__loongarch64)
+#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || defined(__loongarch_lp64)
int r;
r = detect_vm_dmi_vendor();
@@ -454,7 +454,7 @@ Virtualization detect_vm(void) {
/* We have to use the correct order here:
*
- * → First, try to detect Oracle Virtualbox, Amazon EC2 Nitro, and Parallels, even if they use KVM,
+ * → First, try to detect Oracle Virtualbox, Amazon EC2 Nitro, Parallels, and Google Compute Engine, even if they use KVM,
* as well as Xen even if it cloaks as Microsoft Hyper-V. Attempt to detect uml at this stage also
* since it runs as a user-process nested inside other VMs. Also check for Xen now, because Xen PV
* mode does not override CPUID when nested inside another hypervisor.
@@ -469,7 +469,8 @@ Virtualization detect_vm(void) {
VIRTUALIZATION_ORACLE,
VIRTUALIZATION_XEN,
VIRTUALIZATION_AMAZON,
- VIRTUALIZATION_PARALLELS)) {
+ VIRTUALIZATION_PARALLELS,
+ VIRTUALIZATION_GOOGLE)) {
v = dmi;
goto finish;
}
diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c
index a57b7e8..ee4002f 100644
--- a/src/core/dbus-cgroup.c
+++ b/src/core/dbus-cgroup.c
@@ -519,7 +519,7 @@ static int bus_cgroup_set_transient_property(
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
c->delegate = b;
- c->delegate_controllers = b ? _CGROUP_MASK_ALL : 0;
+ c->delegate_controllers = b ? CGROUP_MASK_DELEGATE : 0;
unit_write_settingf(u, flags, name, "Delegate=%s", yes_no(b));
}
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index b4c4cd9..479e784 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -728,7 +728,7 @@ static int property_get_bind_paths(
c->bind_mounts[i].source,
c->bind_mounts[i].destination,
c->bind_mounts[i].ignore_enoent,
- c->bind_mounts[i].recursive ? (uint64_t) MS_REC : (uint64_t) 0);
+ c->bind_mounts[i].recursive ? (uint64_t) MS_REC : UINT64_C(0));
if (r < 0)
return r;
}
@@ -1100,7 +1100,7 @@ static int bus_property_get_exec_dir_symlink(
for (size_t i = 0; i < d->n_items; i++)
STRV_FOREACH(dst, d->items[i].symlinks) {
- r = sd_bus_message_append(reply, "(sst)", d->items[i].path, *dst, 0 /* flags, unused for now */);
+ r = sd_bus_message_append(reply, "(sst)", d->items[i].path, *dst, UINT64_C(0) /* flags, unused for now */);
if (r < 0)
return r;
}
diff --git a/src/core/execute.c b/src/core/execute.c
index 9715d02..2c1dda1 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -4512,6 +4512,16 @@ static int exec_child(
}
if (context->utmp_id) {
+ _cleanup_free_ char *username_alloc = NULL;
+
+ if (!username && context->utmp_mode == EXEC_UTMP_USER) {
+ username_alloc = uid_to_name(uid_is_valid(uid) ? uid : saved_uid);
+ if (!username_alloc) {
+ *exit_status = EXIT_USER;
+ return log_oom();
+ }
+ }
+
const char *line = context->tty_path ?
(path_startswith(context->tty_path, "/dev/") ?: context->tty_path) :
NULL;
@@ -4520,7 +4530,7 @@ static int exec_child(
context->utmp_mode == EXEC_UTMP_INIT ? INIT_PROCESS :
context->utmp_mode == EXEC_UTMP_LOGIN ? LOGIN_PROCESS :
USER_PROCESS,
- username);
+ username ?: username_alloc);
}
if (uid_is_valid(uid)) {
diff --git a/src/core/kmod-setup.c b/src/core/kmod-setup.c
index 15337d0..ea01fd7 100644
--- a/src/core/kmod-setup.c
+++ b/src/core/kmod-setup.c
@@ -30,7 +30,7 @@ static void systemd_kmod_log(
REENABLE_WARNING;
}
-static int has_virtio_rng_recurse_dir_cb(
+static int match_modalias_recurse_dir_cb(
RecurseDirEvent event,
const char *path,
int dir_fd,
@@ -40,6 +40,7 @@ static int has_virtio_rng_recurse_dir_cb(
void *userdata) {
_cleanup_free_ char *alias = NULL;
+ char **modaliases = ASSERT_PTR(userdata);
int r;
if (event != RECURSE_DIR_ENTRY)
@@ -57,13 +58,13 @@ static int has_virtio_rng_recurse_dir_cb(
return RECURSE_DIR_LEAVE_DIRECTORY;
}
- if (STARTSWITH_SET(alias, "pci:v00001AF4d00001005", "pci:v00001AF4d00001044"))
+ if (startswith_strv(alias, modaliases))
return 1;
return RECURSE_DIR_LEAVE_DIRECTORY;
}
-static bool has_virtio_rng(void) {
+static bool has_virtio_feature(const char *name, char **modaliases) {
int r;
/* Directory traversal might be slow, hence let's do a cheap check first if it's even worth it */
@@ -74,16 +75,28 @@ static bool has_virtio_rng(void) {
AT_FDCWD,
"/sys/devices/pci0000:00",
/* statx_mask= */ 0,
- /* n_depth_max= */ 2,
+ /* n_depth_max= */ 3,
RECURSE_DIR_ENSURE_TYPE,
- has_virtio_rng_recurse_dir_cb,
- NULL);
+ match_modalias_recurse_dir_cb,
+ modaliases);
if (r < 0)
- log_debug_errno(r, "Failed to determine whether host has virtio-rng device, ignoring: %m");
+ log_debug_errno(r, "Failed to determine whether host has %s device, ignoring: %m", name);
return r > 0;
}
+static bool has_virtio_rng(void) {
+ return has_virtio_feature("virtio-rng", STRV_MAKE("pci:v00001AF4d00001005", "pci:v00001AF4d00001044"));
+}
+
+static bool has_virtiofs(void) {
+ return has_virtio_feature("virtiofs", STRV_MAKE("virtio:d0000001Av"));
+}
+
+static bool has_virtio_pci(void) {
+ return has_virtio_feature("virtio-pci", STRV_MAKE("pci:v00001AF4d"));
+}
+
static bool in_qemu(void) {
return IN_SET(detect_vm(), VIRTUALIZATION_KVM, VIRTUALIZATION_QEMU);
}
@@ -117,6 +130,15 @@ int kmod_setup(void) {
/* virtio_rng would be loaded by udev later, but real entropy might be needed very early */
{ "virtio_rng", NULL, false, false, has_virtio_rng },
+ /* We can't wait for specific virtiofs tags to show up as device nodes so we have to load the
+ * virtiofs and virtio_pci modules early to make sure the virtiofs tags are found when
+ * sysroot.mount is started.
+ *
+ * TODO: Remove these again once https://gitlab.com/virtio-fs/virtiofsd/-/issues/128 is
+ * resolved and the kernel fix is widely available. */
+ { "virtiofs", "/sys/module/virtiofs", false, false, has_virtiofs },
+ { "virtio_pci", "/sys/module/virtio_pci", false, false, has_virtio_pci },
+
/* qemu_fw_cfg would be loaded by udev later, but we want to import credentials from it super early */
{ "qemu_fw_cfg", "/sys/firmware/qemu_fw_cfg", false, false, in_qemu },
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 1001faa..5f4d4b0 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -3990,7 +3990,7 @@ int config_parse_delegate(
} else if (r > 0) {
c->delegate = true;
- c->delegate_controllers = _CGROUP_MASK_ALL;
+ c->delegate_controllers = CGROUP_MASK_DELEGATE;
} else {
c->delegate = false;
c->delegate_controllers = 0;
diff --git a/src/core/service.c b/src/core/service.c
index 1d5b9ff..cdddd49 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -594,8 +594,7 @@ static int service_verify(Service *s) {
if (s->type != SERVICE_ONESHOT && s->exec_command[SERVICE_EXEC_START]->command_next)
return log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(ENOEXEC), "Service has more than one ExecStart= setting, which is only allowed for Type=oneshot services. Refusing.");
- if (s->type == SERVICE_ONESHOT &&
- !IN_SET(s->restart, SERVICE_RESTART_NO, SERVICE_RESTART_ON_FAILURE, SERVICE_RESTART_ON_ABNORMAL, SERVICE_RESTART_ON_WATCHDOG, SERVICE_RESTART_ON_ABORT))
+ if (s->type == SERVICE_ONESHOT && IN_SET(s->restart, SERVICE_RESTART_ALWAYS, SERVICE_RESTART_ON_SUCCESS))
return log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(ENOEXEC), "Service has Restart= set to either always or on-success, which isn't allowed for Type=oneshot services. Refusing.");
if (s->type == SERVICE_ONESHOT && !exit_status_set_is_empty(&s->restart_force_status))
diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c
index c94befe..e193e71 100644
--- a/src/libsystemd/sd-bus/bus-socket.c
+++ b/src/libsystemd/sd-bus/bus-socket.c
@@ -725,12 +725,12 @@ static int bus_socket_inotify_setup(sd_bus *b) {
assert(b->sockaddr.sa.sa_family == AF_UNIX);
assert(b->sockaddr.un.sun_path[0] != 0);
- /* Sets up an inotify fd in case watch_bind is enabled: wait until the configured AF_UNIX file system socket
- * appears before connecting to it. The implemented is pretty simplistic: we just subscribe to relevant changes
- * to all prefix components of the path, and every time we get an event for that we try to reconnect again,
- * without actually caring what precisely the event we got told us. If we still can't connect we re-subscribe
- * to all relevant changes of anything in the path, so that our watches include any possibly newly created path
- * components. */
+ /* Sets up an inotify fd in case watch_bind is enabled: wait until the configured AF_UNIX file system
+ * socket appears before connecting to it. The implemented is pretty simplistic: we just subscribe to
+ * relevant changes to all components of the path, and every time we get an event for that we try to
+ * reconnect again, without actually caring what precisely the event we got told us. If we still
+ * can't connect we re-subscribe to all relevant changes of anything in the path, so that our watches
+ * include any possibly newly created path components. */
if (b->inotify_fd < 0) {
b->inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
@@ -749,17 +749,17 @@ static int bus_socket_inotify_setup(sd_bus *b) {
if (r < 0)
goto fail;
- /* Watch all parent directories, and don't mind any prefix that doesn't exist yet. For the innermost directory
- * that exists we want to know when files are created or moved into it. For all parents of it we just care if
- * they are removed or renamed. */
+ /* Watch all components of the path, and don't mind any prefix that doesn't exist yet. For the
+ * innermost directory that exists we want to know when files are created or moved into it. For all
+ * parents of it we just care if they are removed or renamed. */
if (!GREEDY_REALLOC(new_watches, n + 1)) {
r = -ENOMEM;
goto fail;
}
- /* Start with the top-level directory, which is a bit simpler than the rest, since it can't be a symlink, and
- * always exists */
+ /* Start with the top-level directory, which is a bit simpler than the rest, since it can't be a
+ * symlink, and always exists */
wd = inotify_add_watch(b->inotify_fd, "/", IN_CREATE|IN_MOVED_TO);
if (wd < 0) {
r = log_debug_errno(errno, "Failed to add inotify watch on /: %m");
diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
index 3c91dd3..37fb888 100644
--- a/src/libsystemd/sd-bus/sd-bus.c
+++ b/src/libsystemd/sd-bus/sd-bus.c
@@ -3040,7 +3040,7 @@ null_message:
return r;
}
-static int bus_exit_now(sd_bus *bus) {
+static int bus_exit_now(sd_bus *bus, sd_event *event) {
assert(bus);
/* Exit due to close, if this is requested. If this is bus object is attached to an event source, invokes
@@ -3057,8 +3057,11 @@ static int bus_exit_now(sd_bus *bus) {
log_debug("Bus connection disconnected, exiting.");
- if (bus->event)
- return sd_event_exit(bus->event, EXIT_FAILURE);
+ if (!event)
+ event = bus->event;
+
+ if (event)
+ return sd_event_exit(event, EXIT_FAILURE);
else
exit(EXIT_FAILURE);
@@ -3120,6 +3123,7 @@ static int process_closing_reply_callback(sd_bus *bus, struct reply_callback *c)
static int process_closing(sd_bus *bus, sd_bus_message **ret) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+ _cleanup_(sd_event_unrefp) sd_event *event = NULL;
struct reply_callback *c;
int r;
@@ -3154,6 +3158,10 @@ static int process_closing(sd_bus *bus, sd_bus_message **ret) {
if (r < 0)
return r;
+ /* sd_bus_close() will deref the event and set bus->event to NULL. But in bus_exit_now() we use
+ * bus->event to decide whether to return from the event loop or exit(), but given it's always NULL
+ * at that point, it always exit(). Ref it here and pass it through further down to avoid that. */
+ event = sd_event_ref(bus->event);
sd_bus_close(bus);
bus->current_message = m;
@@ -3169,7 +3177,7 @@ static int process_closing(sd_bus *bus, sd_bus_message **ret) {
/* Nothing else to do, exit now, if the condition holds */
bus->exit_triggered = true;
- (void) bus_exit_now(bus);
+ (void) bus_exit_now(bus, event);
if (ret)
*ret = TAKE_PTR(m);
@@ -4281,7 +4289,7 @@ _public_ int sd_bus_set_exit_on_disconnect(sd_bus *bus, int b) {
bus->exit_on_disconnect = b;
/* If the exit condition was triggered already, exit immediately. */
- return bus_exit_now(bus);
+ return bus_exit_now(bus, /* event= */ NULL);
}
_public_ int sd_bus_get_exit_on_disconnect(sd_bus *bus) {
diff --git a/src/libsystemd/sd-bus/test-bus-watch-bind.c b/src/libsystemd/sd-bus/test-bus-watch-bind.c
index c577330..fae2a45 100644
--- a/src/libsystemd/sd-bus/test-bus-watch-bind.c
+++ b/src/libsystemd/sd-bus/test-bus-watch-bind.c
@@ -7,6 +7,7 @@
#include "sd-id128.h"
#include "alloc-util.h"
+#include "bus-internal.h"
#include "fd-util.h"
#include "fs-util.h"
#include "mkdir.h"
@@ -27,8 +28,11 @@ static int method_foobar(sd_bus_message *m, void *userdata, sd_bus_error *ret_er
static int method_exit(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
log_info("Got Exit() call");
- assert_se(sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(m)), 1) >= 0);
- return sd_bus_reply_method_return(m, NULL);
+
+ assert_se(sd_bus_reply_method_return(m, NULL) >= 0);
+ /* Simulate D-Bus going away to test the bus_exit_now() path with exit_on_disconnect set */
+ bus_enter_closing(sd_bus_message_get_bus(m));
+ return 0;
}
static const sd_bus_vtable vtable[] = {
@@ -100,6 +104,7 @@ static void* thread_server(void *p) {
log_debug("Accepted server connection");
assert_se(sd_bus_new(&bus) >= 0);
+ assert_se(sd_bus_set_exit_on_disconnect(bus, true) >= 0);
assert_se(sd_bus_set_description(bus, "server") >= 0);
assert_se(sd_bus_set_fd(bus, bus_fd, bus_fd) >= 0);
assert_se(sd_bus_set_server(bus, true, id) >= 0);
diff --git a/src/libsystemd/sd-id128/id128-util.c b/src/libsystemd/sd-id128/id128-util.c
index 8ae80cb..724c5fe 100644
--- a/src/libsystemd/sd-id128/id128-util.c
+++ b/src/libsystemd/sd-id128/id128-util.c
@@ -192,6 +192,8 @@ int id128_get_product(sd_id128_t *ret) {
r = id128_read("/sys/class/dmi/id/product_uuid", ID128_FORMAT_UUID, &uuid);
if (r == -ENOENT)
r = id128_read("/proc/device-tree/vm,uuid", ID128_FORMAT_UUID, &uuid);
+ if (r == -ENOENT)
+ r = id128_read("/sys/hypervisor/uuid", ID128_FORMAT_UUID, &uuid);
if (r < 0)
return r;
diff --git a/src/login/user-runtime-dir.c b/src/login/user-runtime-dir.c
index f96a2d8..c74d8b8 100644
--- a/src/login/user-runtime-dir.c
+++ b/src/login/user-runtime-dir.c
@@ -66,7 +66,7 @@ static int user_mkdir_runtime_path(
if (r < 0)
return log_error_errno(r, "Failed to create /run/user: %m");
- if (path_is_mount_point(runtime_path, NULL, 0) >= 0)
+ if (path_is_mount_point(runtime_path, NULL, 0) > 0)
log_debug("%s is already a mount point", runtime_path);
else {
char options[sizeof("mode=0700,uid=,gid=,size=,nr_inodes=,smackfsroot=*")
diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c
index a397ebd..1782315 100644
--- a/src/machine/machinectl.c
+++ b/src/machine/machinectl.c
@@ -1127,7 +1127,7 @@ static int copy_files(int argc, char *argv[], void *userdata) {
return bus_log_create_error(r);
if (arg_force) {
- r = sd_bus_message_append(m, "t", MACHINE_COPY_REPLACE);
+ r = sd_bus_message_append(m, "t", (uint64_t) MACHINE_COPY_REPLACE);
if (r < 0)
return bus_log_create_error(r);
}
diff --git a/src/network/wait-online/manager.c b/src/network/wait-online/manager.c
index cd4009e..ffc972b 100644
--- a/src/network/wait-online/manager.c
+++ b/src/network/wait-online/manager.c
@@ -158,7 +158,9 @@ bool manager_configured(Manager *m) {
r = manager_link_is_online(m, l,
(LinkOperationalStateRange) { _LINK_OPERSTATE_INVALID,
_LINK_OPERSTATE_INVALID });
- if (r < 0 && !m->any) /* Unlike the above loop, unmanaged interfaces are ignored here. */
+ /* Unlike the above loop, unmanaged interfaces are ignored here. Also, Configured but offline
+ * interfaces are ignored. See issue #29506. */
+ if (r < 0 && r != -EADDRNOTAVAIL && !m->any)
return false;
if (r > 0) {
if (m->any)
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 6c9f084..68c5b18 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -1805,8 +1805,10 @@ static int verify_arguments(void) {
if (arg_ephemeral && arg_template)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--ephemeral and --template= may not be combined.");
- if (arg_ephemeral && !IN_SET(arg_link_journal, LINK_NO, LINK_AUTO))
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--ephemeral and --link-journal= may not be combined.");
+ /* Permit --ephemeral with --link-journal=try-* to satisfy principle of the least astonishment
+ * (by common sense, "try" means "do not fail if not possible") */
+ if (arg_ephemeral && !IN_SET(arg_link_journal, LINK_NO, LINK_AUTO) && !arg_link_journal_try)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--ephemeral and --link-journal={host,guest} may not be combined.");
if (arg_userns_mode != USER_NAMESPACE_NO && !userns_supported())
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "--private-users= is not supported, kernel compiled without user namespace support.");
diff --git a/src/portable/portablectl.c b/src/portable/portablectl.c
index 3c9727c..378c7ec 100644
--- a/src/portable/portablectl.c
+++ b/src/portable/portablectl.c
@@ -1157,7 +1157,7 @@ static int is_image_attached(int argc, char *argv[], void *userdata) {
return r;
if (!strv_isempty(arg_extension_images)) {
- r = sd_bus_message_append(m, "t", 0);
+ r = sd_bus_message_append(m, "t", UINT64_C(0));
if (r < 0)
return bus_log_create_error(r);
}
diff --git a/src/resolve/resolved-dns-dnssec.c b/src/resolve/resolved-dns-dnssec.c
index f63cd9b..71a915f 100644
--- a/src/resolve/resolved-dns-dnssec.c
+++ b/src/resolve/resolved-dns-dnssec.c
@@ -27,8 +27,9 @@ DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EC_KEY*, EC_KEY_free, NULL);
/* Permit a maximum clock skew of 1h 10min. This should be enough to deal with DST confusion */
#define SKEW_MAX (1*USEC_PER_HOUR + 10*USEC_PER_MINUTE)
-/* Maximum number of NSEC3 iterations we'll do. RFC5155 says 2500 shall be the maximum useful value */
-#define NSEC3_ITERATIONS_MAX 2500
+/* Maximum number of NSEC3 iterations we'll do. RFC5155 says 2500 shall be the maximum useful value, but
+ * RFC9276 § 3.2 says that we should reduce the acceptable iteration count */
+#define NSEC3_ITERATIONS_MAX 100
/*
* The DNSSEC Chain of trust:
@@ -1176,6 +1177,7 @@ int dnssec_verify_rrset_search(
DnsResourceRecord **ret_rrsig) {
bool found_rrsig = false, found_invalid = false, found_expired_rrsig = false, found_unsupported_algorithm = false;
+ unsigned nvalidations = 0;
DnsResourceRecord *rrsig;
int r;
@@ -1221,6 +1223,14 @@ int dnssec_verify_rrset_search(
if (realtime == USEC_INFINITY)
realtime = now(CLOCK_REALTIME);
+ /* Have we seen an unreasonable number of invalid signaures? */
+ if (nvalidations > DNSSEC_INVALID_MAX) {
+ if (ret_rrsig)
+ *ret_rrsig = NULL;
+ *result = DNSSEC_TOO_MANY_VALIDATIONS;
+ return (int) nvalidations;
+ }
+
/* Yay, we found a matching RRSIG with a matching
* DNSKEY, awesome. Now let's verify all entries of
* the RRSet against the RRSIG and DNSKEY
@@ -1230,6 +1240,8 @@ int dnssec_verify_rrset_search(
if (r < 0)
return r;
+ nvalidations++;
+
switch (one_result) {
case DNSSEC_VALIDATED:
@@ -1240,7 +1252,7 @@ int dnssec_verify_rrset_search(
*ret_rrsig = rrsig;
*result = one_result;
- return 0;
+ return (int) nvalidations;
case DNSSEC_INVALID:
/* If the signature is invalid, let's try another
@@ -1287,7 +1299,7 @@ int dnssec_verify_rrset_search(
if (ret_rrsig)
*ret_rrsig = NULL;
- return 0;
+ return (int) nvalidations;
}
int dnssec_has_rrsig(DnsAnswer *a, const DnsResourceKey *key) {
@@ -2571,6 +2583,7 @@ static const char* const dnssec_result_table[_DNSSEC_RESULT_MAX] = {
[DNSSEC_FAILED_AUXILIARY] = "failed-auxiliary",
[DNSSEC_NSEC_MISMATCH] = "nsec-mismatch",
[DNSSEC_INCOMPATIBLE_SERVER] = "incompatible-server",
+ [DNSSEC_TOO_MANY_VALIDATIONS] = "too-many-validations",
};
DEFINE_STRING_TABLE_LOOKUP(dnssec_result, DnssecResult);
diff --git a/src/resolve/resolved-dns-dnssec.h b/src/resolve/resolved-dns-dnssec.h
index 954bb3e..29b9013 100644
--- a/src/resolve/resolved-dns-dnssec.h
+++ b/src/resolve/resolved-dns-dnssec.h
@@ -9,12 +9,13 @@ typedef enum DnssecVerdict DnssecVerdict;
#include "resolved-dns-rr.h"
enum DnssecResult {
- /* These five are returned by dnssec_verify_rrset() */
+ /* These six are returned by dnssec_verify_rrset() */
DNSSEC_VALIDATED,
DNSSEC_VALIDATED_WILDCARD, /* Validated via a wildcard RRSIG, further NSEC/NSEC3 checks necessary */
DNSSEC_INVALID,
DNSSEC_SIGNATURE_EXPIRED,
DNSSEC_UNSUPPORTED_ALGORITHM,
+ DNSSEC_TOO_MANY_VALIDATIONS,
/* These two are added by dnssec_verify_rrset_search() */
DNSSEC_NO_SIGNATURE,
@@ -45,6 +46,12 @@ enum DnssecVerdict {
/* The longest digest we'll ever generate, of all digest algorithms we support */
#define DNSSEC_HASH_SIZE_MAX (MAX(20, 32))
+/* The most invalid signatures we will tolerate for a single rrset */
+#define DNSSEC_INVALID_MAX 5
+
+/* The total number of signature validations we will tolerate for a single transaction */
+#define DNSSEC_VALIDATION_MAX 64
+
int dnssec_rrsig_match_dnskey(DnsResourceRecord *rrsig, DnsResourceRecord *dnskey, bool revoked_ok);
int dnssec_key_match_rrsig(const DnsResourceKey *key, DnsResourceRecord *rrsig);
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
index 1850d45..21326fa 100644
--- a/src/resolve/resolved-dns-transaction.c
+++ b/src/resolve/resolved-dns-transaction.c
@@ -3172,11 +3172,14 @@ static int dnssec_validate_records(
DnsTransaction *t,
Phase phase,
bool *have_nsec,
+ unsigned *nvalidations,
DnsAnswer **validated) {
DnsResourceRecord *rr;
int r;
+ assert(nvalidations);
+
/* Returns negative on error, 0 if validation failed, 1 to restart validation, 2 when finished. */
DNS_ANSWER_FOREACH(rr, t->answer) {
@@ -3218,6 +3221,7 @@ static int dnssec_validate_records(
&rrsig);
if (r < 0)
return r;
+ *nvalidations += r;
log_debug("Looking at %s: %s", strna(dns_resource_record_to_string(rr)), dnssec_result_to_string(result));
@@ -3415,7 +3419,8 @@ static int dnssec_validate_records(
DNSSEC_SIGNATURE_EXPIRED,
DNSSEC_NO_SIGNATURE))
manager_dnssec_verdict(t->scope->manager, DNSSEC_BOGUS, rr->key);
- else /* DNSSEC_MISSING_KEY or DNSSEC_UNSUPPORTED_ALGORITHM */
+ else /* DNSSEC_MISSING_KEY, DNSSEC_UNSUPPORTED_ALGORITHM,
+ or DNSSEC_TOO_MANY_VALIDATIONS */
manager_dnssec_verdict(t->scope->manager, DNSSEC_INDETERMINATE, rr->key);
/* This is a primary response to our question, and it failed validation.
@@ -3508,13 +3513,21 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) {
return r;
phase = DNSSEC_PHASE_DNSKEY;
- for (;;) {
+ for (unsigned nvalidations = 0;;) {
bool have_nsec = false;
- r = dnssec_validate_records(t, phase, &have_nsec, &validated);
+ r = dnssec_validate_records(t, phase, &have_nsec, &nvalidations, &validated);
if (r <= 0)
return r;
+ if (nvalidations > DNSSEC_VALIDATION_MAX) {
+ /* This reply requires an onerous number of signature validations to verify. Let's
+ * not waste our time trying, as this shouldn't happen for well-behaved domains
+ * anyway. */
+ t->answer_dnssec_result = DNSSEC_TOO_MANY_VALIDATIONS;
+ return 0;
+ }
+
/* Try again as long as we managed to achieve something */
if (r == 1)
continue;
diff --git a/src/shared/base-filesystem.c b/src/shared/base-filesystem.c
index 5b4f674..47a766e 100644
--- a/src/shared/base-filesystem.c
+++ b/src/shared/base-filesystem.c
@@ -63,7 +63,7 @@ static const BaseFilesystem table[] = {
"usr/lib64\0", "ld-linux-x86-64.so.2" },
# define KNOW_LIB64_DIRS 1
#elif defined(__ia64__)
-#elif defined(__loongarch64)
+#elif defined(__loongarch_lp64)
# define KNOW_LIB64_DIRS 1
# if defined(__loongarch_double_float)
{ "lib64", 0, "usr/lib/"LIB_ARCH_TUPLE"\0"
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index 7666012..ff0e175 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -1282,12 +1282,12 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
if (r < 0)
return log_error_errno(r, "Failed to parse resource limit: %s", eq);
- r = sd_bus_message_append(m, "(sv)", field, "t", l.rlim_max);
+ r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) l.rlim_max);
if (r < 0)
return bus_log_create_error(r);
sn = strjoina(field, "Soft");
- r = sd_bus_message_append(m, "(sv)", sn, "t", l.rlim_cur);
+ r = sd_bus_message_append(m, "(sv)", sn, "t", (uint64_t) l.rlim_cur);
if (r < 0)
return bus_log_create_error(r);
@@ -2030,7 +2030,7 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
return bus_log_create_error(r);
STRV_FOREACH_PAIR(source, destination, symlinks) {
- r = sd_bus_message_append(m, "(sst)", *source, *destination, 0);
+ r = sd_bus_message_append(m, "(sst)", *source, *destination, UINT64_C(0));
if (r < 0)
return bus_log_create_error(r);
}
diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c
index 5cb41a3..327dc38 100644
--- a/src/shared/conf-parser.c
+++ b/src/shared/conf-parser.c
@@ -463,7 +463,7 @@ int hashmap_put_stats_by_path(Hashmap **stats_by_path, const char *path, const s
return -ENOMEM;
path_copy = strdup(path);
- if (!path)
+ if (!path_copy)
return -ENOMEM;
r = hashmap_put(*stats_by_path, path_copy, st_copy);
diff --git a/src/shared/efi-loader.c b/src/shared/efi-loader.c
index 1340412..b9fe26b 100644
--- a/src/shared/efi-loader.c
+++ b/src/shared/efi-loader.c
@@ -99,7 +99,8 @@ int efi_loader_get_entries(char ***ret) {
if (r < 0)
return r;
- /* The variable contains a series of individually NUL terminated UTF-16 strings. */
+ /* The variable contains a series of individually NUL terminated UTF-16 strings. We gracefully
+ * consider the final NUL byte optional (i.e. the last string may or may not end in a NUL byte).*/
for (size_t i = 0, start = 0;; i++) {
_cleanup_free_ char *decoded = NULL;
@@ -113,6 +114,11 @@ int efi_loader_get_entries(char ***ret) {
if (!end && entries[i] != 0)
continue;
+ /* Empty string at the end of variable? That's the trailer, we are done (i.e. we have a final
+ * NUL terminator). */
+ if (end && start == i)
+ break;
+
/* We reached the end of a string, let's decode it into UTF-8 */
decoded = utf16_to_utf8(entries + start, (i - start) * sizeof(char16_t));
if (!decoded)
@@ -125,7 +131,8 @@ int efi_loader_get_entries(char ***ret) {
} else
log_debug("Ignoring invalid loader entry '%s'.", decoded);
- /* We reached the end of the variable */
+ /* Exit the loop if we reached the end of the variable (i.e. we do not have a final NUL
+ * terminator) */
if (end)
break;
diff --git a/src/shared/generate-syscall-list.py b/src/shared/generate-syscall-list.py
index 3ee19ff..c0975a0 100755
--- a/src/shared/generate-syscall-list.py
+++ b/src/shared/generate-syscall-list.py
@@ -2,15 +2,6 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
import sys
-import os
-
-s390 = 's390' in os.uname().machine
-arm = 'arm' in os.uname().machine
for line in open(sys.argv[1]):
- if line.startswith('s390_') and not s390:
- continue
- if line.startswith('arm_') and not arm:
- continue
-
print('"{}\\0"'.format(line.strip()))
diff --git a/src/shared/keyring-util.c b/src/shared/keyring-util.c
index 655cf52..fadd90e 100644
--- a/src/shared/keyring-util.c
+++ b/src/shared/keyring-util.c
@@ -5,34 +5,31 @@
#include "missing_syscall.h"
int keyring_read(key_serial_t serial, void **ret, size_t *ret_size) {
- size_t m = 100;
+ size_t bufsize = 100;
for (;;) {
- _cleanup_(erase_and_freep) uint8_t *p = NULL;
+ _cleanup_(erase_and_freep) uint8_t *buf = NULL;
long n;
- p = new(uint8_t, m+1);
- if (!p)
+ buf = new(uint8_t, bufsize + 1);
+ if (!buf)
return -ENOMEM;
- n = keyctl(KEYCTL_READ, (unsigned long) serial, (unsigned long) p, (unsigned long) m, 0);
+ n = keyctl(KEYCTL_READ, (unsigned long) serial, (unsigned long) buf, (unsigned long) bufsize, 0);
if (n < 0)
return -errno;
- if ((size_t) n <= m) {
- p[n] = 0; /* NUL terminate, just in case */
+ if ((size_t) n <= bufsize) {
+ buf[n] = 0; /* NUL terminate, just in case */
if (ret)
- *ret = TAKE_PTR(p);
+ *ret = TAKE_PTR(buf);
if (ret_size)
*ret_size = n;
return 0;
}
- if (m > (SIZE_MAX-1) / 2) /* overflow check */
- return -ENOMEM;
-
- m *= 2;
+ bufsize = (size_t) n;
}
}
diff --git a/src/shared/loop-util.c b/src/shared/loop-util.c
index 3396cf5..ef35e31 100644
--- a/src/shared/loop-util.c
+++ b/src/shared/loop-util.c
@@ -637,7 +637,7 @@ int loop_device_make_by_path(
else
direct = direct_flags != 0;
if (fd < 0) {
- r = -errno;
+ r = fd;
/* Retry read-only? */
if (open_flags >= 0 || !(ERRNO_IS_PRIVILEGE(r) || r == -EROFS))
diff --git a/src/shared/machine-id-setup.c b/src/shared/machine-id-setup.c
index 787c076..9ce5993 100644
--- a/src/shared/machine-id-setup.c
+++ b/src/shared/machine-id-setup.c
@@ -60,7 +60,7 @@ static int generate_machine_id(const char *root, sd_id128_t *ret) {
return 0;
}
- } else if (IN_SET(detect_vm(), VIRTUALIZATION_KVM, VIRTUALIZATION_AMAZON, VIRTUALIZATION_QEMU)) {
+ } else if (IN_SET(detect_vm(), VIRTUALIZATION_KVM, VIRTUALIZATION_AMAZON, VIRTUALIZATION_QEMU, VIRTUALIZATION_XEN)) {
/* If we are not running in a container, see if we are running in a VM that provides
* a system UUID via the SMBIOS/DMI interfaces. Such environments include QEMU/KVM
diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c
index 77cacb3..1c6bdc5 100644
--- a/src/shared/seccomp-util.c
+++ b/src/shared/seccomp-util.c
@@ -468,6 +468,7 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = {
"fchdir\0"
"fchmod\0"
"fchmodat\0"
+ "fchmodat2\0"
"fcntl\0"
"fcntl64\0"
"fgetxattr\0"
@@ -2031,7 +2032,7 @@ int seccomp_protect_hostname(void) {
static int seccomp_restrict_sxid(scmp_filter_ctx seccomp, mode_t m) {
/* Checks the mode_t parameter of the following system calls:
*
- * → chmod() + fchmod() + fchmodat()
+ * → chmod() + fchmod() + fchmodat() + fchmodat2()
* → open() + creat() + openat()
* → mkdir() + mkdirat()
* → mknod() + mknodat()
@@ -2074,6 +2075,28 @@ static int seccomp_restrict_sxid(scmp_filter_ctx seccomp, mode_t m) {
else
any = true;
+#if defined(__SNR_fchmodat2)
+ r = seccomp_rule_add_exact(
+ seccomp,
+ SCMP_ACT_ERRNO(EPERM),
+ SCMP_SYS(fchmodat2),
+ 1,
+ SCMP_A2(SCMP_CMP_MASKED_EQ, m, m));
+#else
+ /* It looks like this libseccomp does not know about fchmodat2().
+ * Pretend the fchmodat2() system call is not supported at all,
+ * regardless of the kernel version. */
+ r = seccomp_rule_add_exact(
+ seccomp,
+ SCMP_ACT_ERRNO(ENOSYS),
+ __NR_fchmodat2,
+ 0);
+#endif
+ if (r < 0)
+ log_debug_errno(r, "Failed to add filter for fchmodat2: %m");
+ else
+ any = true;
+
r = seccomp_rule_add_exact(
seccomp,
SCMP_ACT_ERRNO(EPERM),
diff --git a/src/shared/utmp-wtmp.c b/src/shared/utmp-wtmp.c
index cfeabbd..3193075 100644
--- a/src/shared/utmp-wtmp.c
+++ b/src/shared/utmp-wtmp.c
@@ -183,6 +183,7 @@ int utmp_put_init_process(const char *id, pid_t pid, pid_t sid, const char *line
int r;
assert(id);
+ assert(ut_type != USER_PROCESS || user);
init_timestamp(&store, 0);
diff --git a/src/systemd/sd-gpt.h b/src/systemd/sd-gpt.h
index 172ac35..7ffa57a 100644
--- a/src/systemd/sd-gpt.h
+++ b/src/systemd/sd-gpt.h
@@ -220,7 +220,7 @@ _SD_BEGIN_DECLARATIONS;
# define SD_GPT_USR_NATIVE_VERITY SD_GPT_USR_IA64_VERITY
# define SD_GPT_USR_NATIVE_VERITY_SIG SD_GPT_USR_IA64_VERITY_SIG
-#elif defined(__loongarch64)
+#elif defined(__loongarch_lp64)
# define SD_GPT_ROOT_NATIVE SD_GPT_ROOT_LOONGARCH64
# define SD_GPT_ROOT_NATIVE_VERITY SD_GPT_ROOT_LOONGARCH64_VERITY
# define SD_GPT_ROOT_NATIVE_VERITY_SIG SD_GPT_ROOT_LOONGARCH64_VERITY_SIG
diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c
index 7f45b70..ee2758a 100644
--- a/src/sysusers/sysusers.c
+++ b/src/sysusers/sysusers.c
@@ -1973,10 +1973,12 @@ static int parse_argv(int argc, char *argv[]) {
#endif
case ARG_REPLACE:
- if (!path_is_absolute(optarg) ||
- !endswith(optarg, ".conf"))
+ if (!path_is_absolute(optarg))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "The argument to --replace= must an absolute path to a config file");
+ "The argument to --replace= must be an absolute path.");
+ if (!endswith(optarg, ".conf"))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "The argument to --replace= must have the extension '.conf'.");
arg_replace = optarg;
break;
diff --git a/src/test/test-calendarspec.c b/src/test/test-calendarspec.c
index 564983b..4699991 100644
--- a/src/test/test-calendarspec.c
+++ b/src/test/test-calendarspec.c
@@ -260,4 +260,11 @@ TEST(calendar_spec_from_string) {
assert_se(calendar_spec_from_string("*:4,30:*\n", &c) == -EINVAL);
}
-DEFINE_TEST_MAIN(LOG_INFO);
+static int intro(void) {
+ /* Tests have hard-coded results that do not expect a specific timezone to be set by the caller */
+ assert_se(unsetenv("TZ") >= 0);
+
+ return EXIT_SUCCESS;
+}
+
+DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro);
diff --git a/src/test/test-date.c b/src/test/test-date.c
index 930f1bd..5f9d387 100644
--- a/src/test/test-date.c
+++ b/src/test/test-date.c
@@ -62,6 +62,9 @@ static void test_one_noutc(const char *p) {
}
int main(int argc, char *argv[]) {
+ /* Tests have hard-coded results that do not expect a specific timezone to be set by the caller */
+ assert_se(unsetenv("TZ") >= 0);
+
test_setup_logging(LOG_DEBUG);
test_one("17:41");
diff --git a/src/test/test-execute.c b/src/test/test-execute.c
index 9538fd3..88bbca5 100644
--- a/src/test/test-execute.c
+++ b/src/test/test-execute.c
@@ -391,7 +391,7 @@ static void test_exec_personality(Manager *m) {
#elif defined(__i386__)
test(m, "exec-personality-x86.service", 0, CLD_EXITED);
-#elif defined(__loongarch64)
+#elif defined(__loongarch_lp64)
test(m, "exec-personality-loongarch64.service", 0, CLD_EXITED);
#else
log_notice("Unknown personality, skipping %s", __func__);
diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c
index 67feb68..35b93b6 100644
--- a/src/test/test-fs-util.c
+++ b/src/test/test-fs-util.c
@@ -1068,4 +1068,42 @@ static int intro(void) {
return EXIT_SUCCESS;
}
+TEST(readlinkat_malloc) {
+ _cleanup_(rm_rf_physical_and_freep) char *t = NULL;
+ _cleanup_close_ int tfd = -EBADF, fd = -EBADF;
+ _cleanup_free_ char *p = NULL, *q = NULL;
+ const char *expect = "hgoehogefoobar", *a;
+
+ a = strjoina(arg_test_dir ?: "/tmp", "/readlinkat-malloc.XXXXXX");
+ assert_se(mkdtemp_malloc(a, &t) >= 0);
+
+ tfd = open(t, O_PATH|O_DIRECTORY|O_CLOEXEC);
+ assert_se(tfd >= 0);
+
+ assert_se(symlinkat(expect, tfd, "linkname") >= 0);
+
+ assert_se(readlinkat_malloc(tfd, "linkname", &p) >= 0);
+ assert_se(streq(p, expect));
+ p = mfree(p);
+
+ fd = openat(tfd, "linkname", O_PATH | O_NOFOLLOW | O_CLOEXEC);
+ assert_se(fd >= 0);
+ assert_se(readlinkat_malloc(fd, NULL, &p) >= 0);
+ assert_se(streq(p, expect));
+ p = mfree(p);
+ assert_se(readlinkat_malloc(fd, "", &p) >= 0);
+ assert_se(streq(p, expect));
+ p = mfree(p);
+ fd = safe_close(fd);
+
+ assert_se(q = path_join(t, "linkname"));
+ assert_se(readlinkat_malloc(AT_FDCWD, q, &p) >= 0);
+ assert_se(streq(p, expect));
+ p = mfree(p);
+ assert_se(readlinkat_malloc(INT_MAX, q, &p) >= 0);
+ assert_se(streq(p, expect));
+ p = mfree(p);
+ q = mfree(q);
+}
+
DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro);
diff --git a/src/test/test-namespace.c b/src/test/test-namespace.c
index 37acc78..7084e70 100644
--- a/src/test/test-namespace.c
+++ b/src/test/test-namespace.c
@@ -94,7 +94,7 @@ static void test_shareable_ns(unsigned long nsflag) {
return;
}
- assert_se(socketpair(AF_UNIX, SOCK_DGRAM, 0, s) >= 0);
+ assert_se(socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, s) >= 0);
pid1 = fork();
assert_se(pid1 >= 0);
diff --git a/src/test/test-nss-hosts.c b/src/test/test-nss-hosts.c
index 7758f0a..72a9c64 100644
--- a/src/test/test-nss-hosts.c
+++ b/src/test/test-nss-hosts.c
@@ -451,7 +451,11 @@ static int parse_argv(int argc, char **argv,
} else {
_cleanup_free_ char *hostname = NULL;
assert_se(hostname = gethostname_malloc());
- assert_se(names = strv_new("localhost", "_gateway", "_outbound", "foo_no_such_host", hostname));
+ assert_se(names = strv_new("localhost",
+ "_gateway",
+ "_outbound",
+ hostname,
+ slow_tests_enabled() ? "foo_no_such_host" : NULL));
n = make_addresses(&addrs);
assert_se(n >= 0);
diff --git a/src/test/test-seccomp.c b/src/test/test-seccomp.c
index 4c704ba..874f08b 100644
--- a/src/test/test-seccomp.c
+++ b/src/test/test-seccomp.c
@@ -21,6 +21,7 @@
#include "macro.h"
#include "memory-util.h"
#include "missing_sched.h"
+#include "missing_syscall_def.h"
#include "nsflags.h"
#include "nulstr-util.h"
#include "process-util.h"
@@ -1003,6 +1004,23 @@ static int real_open(const char *path, int flags, mode_t mode) {
#endif
}
+static int try_fchmodat2(int dirfd, const char *path, int flags, mode_t mode) {
+ /* glibc does not provide a direct wrapper for fchmodat2(). Let's hence define our own wrapper for
+ * testing purposes that calls the real syscall, on architectures and in environments where
+ * SYS_fchmodat2 is defined. Otherwise, let's just fall back to the glibc fchmodat() call. */
+
+#if defined __NR_fchmodat2 && __NR_fchmodat2 >= 0
+ int r;
+ r = (int) syscall(__NR_fchmodat2, dirfd, path, flags, mode);
+ /* The syscall might still be unsupported by kernel or libseccomp. */
+ if (r < 0 && errno == ENOSYS)
+ return fchmodat(dirfd, path, flags, mode);
+ return r;
+#else
+ return fchmodat(dirfd, path, flags, mode);
+#endif
+}
+
TEST(restrict_suid_sgid) {
pid_t pid;
@@ -1044,6 +1062,11 @@ TEST(restrict_suid_sgid) {
assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISGID | S_ISUID, 0) >= 0);
assert_se(fchmodat(AT_FDCWD, path, 0755, 0) >= 0);
+ assert_se(try_fchmodat2(AT_FDCWD, path, 0755 | S_ISUID, 0) >= 0);
+ assert_se(try_fchmodat2(AT_FDCWD, path, 0755 | S_ISGID, 0) >= 0);
+ assert_se(try_fchmodat2(AT_FDCWD, path, 0755 | S_ISGID | S_ISUID, 0) >= 0);
+ assert_se(try_fchmodat2(AT_FDCWD, path, 0755, 0) >= 0);
+
k = real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID);
k = safe_close(k);
assert_se(unlink(z) >= 0);
@@ -1145,6 +1168,11 @@ TEST(restrict_suid_sgid) {
assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISGID | S_ISUID, 0) < 0 && errno == EPERM);
assert_se(fchmodat(AT_FDCWD, path, 0755, 0) >= 0);
+ assert_se(try_fchmodat2(AT_FDCWD, path, 0755 | S_ISUID, 0) < 0 && errno == EPERM);
+ assert_se(try_fchmodat2(AT_FDCWD, path, 0755 | S_ISGID, 0) < 0 && errno == EPERM);
+ assert_se(try_fchmodat2(AT_FDCWD, path, 0755 | S_ISGID | S_ISUID, 0) < 0 && errno == EPERM);
+ assert_se(try_fchmodat2(AT_FDCWD, path, 0755, 0) >= 0);
+
assert_se(real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID) < 0 && errno == EPERM);
assert_se(real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISGID) < 0 && errno == EPERM);
assert_se(real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID | S_ISGID) < 0 && errno == EPERM);
diff --git a/src/test/test-time-util.c b/src/test/test-time-util.c
index 5b4bf3a..2738e8a 100644
--- a/src/test/test-time-util.c
+++ b/src/test/test-time-util.c
@@ -616,6 +616,9 @@ TEST(map_clock_usec) {
}
static int intro(void) {
+ /* Tests have hard-coded results that do not expect a specific timezone to be set by the caller */
+ assert_se(unsetenv("TZ") >= 0);
+
log_info("realtime=" USEC_FMT "\n"
"monotonic=" USEC_FMT "\n"
"boottime=" USEC_FMT "\n",
diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c
index 4352858..23480d4 100644
--- a/src/timesync/timesyncd-manager.c
+++ b/src/timesync/timesyncd-manager.c
@@ -25,6 +25,7 @@
#include "network-util.h"
#include "ratelimit.h"
#include "resolve-private.h"
+#include "random-util.h"
#include "socket-util.h"
#include "string-util.h"
#include "strv.h"
@@ -77,13 +78,6 @@ static double ts_to_d(const struct timespec *ts) {
return ts->tv_sec + (1.0e-9 * ts->tv_nsec);
}
-static uint32_t graceful_add_offset_1900_1970(time_t t) {
- /* Adds OFFSET_1900_1970 to t and returns it as 32bit value. This is handles overflows
- * gracefully in a deterministic and well-defined way by cutting off the top bits. */
- uint64_t a = (uint64_t) t + OFFSET_1900_1970;
- return (uint32_t) (a & UINT64_C(0xFFFFFFFF));
-}
-
static int manager_timeout(sd_event_source *source, usec_t usec, void *userdata) {
_cleanup_free_ char *pretty = NULL;
Manager *m = ASSERT_PTR(userdata);
@@ -125,20 +119,22 @@ static int manager_send_request(Manager *m) {
}
/*
- * Set transmit timestamp, remember it; the server will send that back
- * as the origin timestamp and we have an indication that this is the
- * matching answer to our request.
- *
- * The actual value does not matter, We do not care about the correct
- * NTP UINT_MAX fraction; we just pass the plain nanosecond value.
+ * Generate a random number as transmit timestamp, to ensure we get
+ * a full 64 bits of entropy to make it hard for off-path attackers
+ * to inject random time to us.
*/
- assert_se(clock_gettime(CLOCK_BOOTTIME, &m->trans_time_mon) >= 0);
- assert_se(clock_gettime(CLOCK_REALTIME, &m->trans_time) >= 0);
- ntpmsg.trans_time.sec = htobe32(graceful_add_offset_1900_1970(m->trans_time.tv_sec));
- ntpmsg.trans_time.frac = htobe32(m->trans_time.tv_nsec);
+ random_bytes(&m->request_nonce, sizeof(m->request_nonce));
+ ntpmsg.trans_time = m->request_nonce;
server_address_pretty(m->current_server_address, &pretty);
+ /*
+ * Record the transmit timestamp. This should be as close as possible to
+ * the send-to to ensure the timestamp is reasonably accurate
+ */
+ assert_se(clock_gettime(CLOCK_BOOTTIME, &m->trans_time_mon) >= 0);
+ assert_se(clock_gettime(CLOCK_REALTIME, &m->trans_time) >= 0);
+
len = sendto(m->server_socket, &ntpmsg, sizeof(ntpmsg), MSG_DONTWAIT, &m->current_server_address->sockaddr.sa, m->current_server_address->socklen);
if (len == sizeof(ntpmsg)) {
m->pending = true;
@@ -456,9 +452,8 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re
m->missed_replies = 0;
- /* check our "time cookie" (we just stored nanoseconds in the fraction field) */
- if (be32toh(ntpmsg.origin_time.sec) != graceful_add_offset_1900_1970(m->trans_time.tv_sec) ||
- be32toh(ntpmsg.origin_time.frac) != (unsigned long) m->trans_time.tv_nsec) {
+ /* check the transmit request nonce was properly returned in the origin_time field */
+ if (ntpmsg.origin_time.sec != m->request_nonce.sec || ntpmsg.origin_time.frac != m->request_nonce.frac) {
log_debug("Invalid reply; not our transmit time. Ignoring.");
return 0;
}
diff --git a/src/timesync/timesyncd-manager.h b/src/timesync/timesyncd-manager.h
index e595c7d..e9b5af5 100644
--- a/src/timesync/timesyncd-manager.h
+++ b/src/timesync/timesyncd-manager.h
@@ -71,6 +71,7 @@ struct Manager {
/* last sent packet */
struct timespec trans_time_mon;
struct timespec trans_time;
+ struct ntp_ts request_nonce;
usec_t retry_interval;
usec_t connection_retry_usec;
bool pending;
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index 9c3d994..281284c 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -3809,10 +3809,12 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_REPLACE:
- if (!path_is_absolute(optarg) ||
- !endswith(optarg, ".conf"))
+ if (!path_is_absolute(optarg))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "The argument to --replace= must an absolute path to a config file");
+ "The argument to --replace= must be an absolute path.");
+ if (!endswith(optarg, ".conf"))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "The argument to --replace= must have the extension '.conf'.");
arg_replace = optarg;
break;